From 3155f24f8b5b76c1480a6e19cc1606dc24a9dad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=B6rl?= Date: Fri, 10 Nov 2023 15:01:04 +0100 Subject: [PATCH] backport & simplifications --- .../edrt/run/EDrtModeOptimizerQSimModule.java | 4 +- .../analysis/PrebookingAnalysisHandler.java | 14 +- .../dvrp/PrebookingActionCreator.java | 7 +- .../prebooking/dvrp/PrebookingManager.java | 147 ++++++++++++------ .../dvrp/PrebookingModeQSimModule.java | 3 +- .../dvrp/PrebookingPassengerEngine.java | 5 + .../dvrp/PrebookingStopActivity.java | 14 +- .../ElectricPrebookingActionCreator.java | 6 +- .../PassengerEnteringVehicleEventHandler.java | 10 -- .../logic/AttributePrebookingLogic.java | 4 +- .../logic/FixedSharePrebookingLogic.java | 2 +- .../prebooking/logic/PopulationIterator.java | 4 +- .../logic/TimedPrebookingLogic.java | 10 +- .../DrtAnalysisControlerListener.java | 5 +- .../analysis/DrtEventSequenceCollector.java | 146 +++++++---------- .../optimizer/DrtModeOptimizerQSimModule.java | 14 +- .../DefaultUnplannedRequestInserter.java | 21 ++- .../matsim/contrib/drt/run/DrtModeModule.java | 6 + .../DefaultUnplannedRequestInserterTest.java | 3 +- .../passenger/DefaultPassengerEngine.java | 5 + .../PassengerEngineWithPrebooking.java | 5 + .../passenger/PassengerWaitingEvent.java} | 17 +- .../PassengerWaitingEventHandler.java | 29 ++++ .../passenger/TeleportingPassengerEngine.java | 2 + .../contrib/dvrp/util/DvrpEventsReaders.java | 2 + 25 files changed, 273 insertions(+), 212 deletions(-) delete mode 100644 contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/events/PassengerEnteringVehicleEventHandler.java rename contribs/{drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/events/PassengerEnteringVehicleEvent.java => dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/PassengerWaitingEvent.java} (73%) create mode 100644 contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/PassengerWaitingEventHandler.java diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/EDrtModeOptimizerQSimModule.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/EDrtModeOptimizerQSimModule.java index 7104a16f376..ba65f62d550 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/EDrtModeOptimizerQSimModule.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/EDrtModeOptimizerQSimModule.java @@ -51,6 +51,7 @@ import org.matsim.contrib.drt.scheduler.DrtScheduleInquiry; import org.matsim.contrib.drt.scheduler.EmptyVehicleRelocator; import org.matsim.contrib.drt.scheduler.RequestInsertionScheduler; +import org.matsim.contrib.drt.stops.PassengerStopDurationProvider; import org.matsim.contrib.drt.stops.StopTimeCalculator; import org.matsim.contrib.dvrp.fleet.Fleet; import org.matsim.contrib.dvrp.optimizer.VrpOptimizer; @@ -136,7 +137,8 @@ public EmptyVehicleChargingScheduler get() { getter.getModal(RequestInsertionScheduler.class), getter.getModal(VehicleEntry.EntryFactory.class), getter.getModal(DrtInsertionSearch.class), getter.getModal(DrtRequestInsertionRetryQueue.class), getter.getModal(DrtOfferAcceptor.class), - getter.getModal(QSimScopeForkJoinPoolHolder.class).getPool()))).asEagerSingleton(); + getter.getModal(QSimScopeForkJoinPoolHolder.class).getPool(), + getter.getModal(PassengerStopDurationProvider.class)))).asEagerSingleton(); bindModal(InsertionCostCalculator.class).toProvider(modalProvider( getter -> new DefaultInsertionCostCalculator(getter.getModal(CostCalculationStrategy.class)))); diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/analysis/PrebookingAnalysisHandler.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/analysis/PrebookingAnalysisHandler.java index 0ee10246f48..e2afba10082 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/analysis/PrebookingAnalysisHandler.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/analysis/PrebookingAnalysisHandler.java @@ -6,8 +6,6 @@ import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.IdMap; import org.matsim.api.core.v01.population.Person; -import org.matsim.contrib.drt.extension.prebooking.events.PassengerEnteringVehicleEvent; -import org.matsim.contrib.drt.extension.prebooking.events.PassengerEnteringVehicleEventHandler; import org.matsim.contrib.drt.extension.prebooking.events.PassengerRequestBookedEvent; import org.matsim.contrib.drt.extension.prebooking.events.PassengerRequestBookedEventHandler; import org.matsim.contrib.dvrp.optimizer.Request; @@ -17,10 +15,12 @@ import org.matsim.contrib.dvrp.passenger.PassengerRequestScheduledEventHandler; import org.matsim.contrib.dvrp.passenger.PassengerRequestSubmittedEvent; import org.matsim.contrib.dvrp.passenger.PassengerRequestSubmittedEventHandler; +import org.matsim.contrib.dvrp.passenger.PassengerWaitingEvent; +import org.matsim.contrib.dvrp.passenger.PassengerWaitingEventHandler; public class PrebookingAnalysisHandler implements PassengerRequestBookedEventHandler, PassengerRequestSubmittedEventHandler, PassengerRequestScheduledEventHandler, - PassengerRequestRejectedEventHandler, PassengerEnteringVehicleEventHandler { + PassengerRequestRejectedEventHandler, PassengerWaitingEventHandler { private final String mode; private final IdMap sequences = new IdMap<>(Request.class); @@ -73,7 +73,7 @@ public void handleEvent(PassengerRequestScheduledEvent event) { } @Override - public void handleEvent(PassengerEnteringVehicleEvent event) { + public void handleEvent(PassengerWaitingEvent event) { if (!event.getMode().equals(mode)) { return; } @@ -81,7 +81,7 @@ public void handleEvent(PassengerEnteringVehicleEvent event) { Sequence sequence = sequences.get(event.getRequestId()); if (sequence != null) { - sequence.entering = event; + sequence.waiting = event; } } @@ -93,7 +93,7 @@ public List getRecords() { sequence.submitted != null ? sequence.submitted.getTime() : null, sequence.scheduled != null ? sequence.scheduled.getTime() : null, sequence.rejected != null ? sequence.rejected.getTime() : null, - sequence.entering != null ? sequence.entering.getTime() : null)); + sequence.waiting != null ? sequence.waiting.getTime() : null)); } return records; @@ -106,7 +106,7 @@ public record RequestRecord(Id requestId, Id personId, Double s private class Sequence { final PassengerRequestBookedEvent booked; PassengerRequestSubmittedEvent submitted; - PassengerEnteringVehicleEvent entering; + PassengerWaitingEvent waiting; PassengerRequestScheduledEvent scheduled; PassengerRequestRejectedEvent rejected; diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingActionCreator.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingActionCreator.java index e56679f716a..e0638f562c1 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingActionCreator.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingActionCreator.java @@ -26,14 +26,12 @@ public class PrebookingActionCreator implements VrpAgentLogic.DynActionCreator { private final VrpAgentLogic.DynActionCreator delegate; private final PrebookingPassengerEngine passengerEngine; private final PassengerStopDurationProvider stopDurationProvider; - private final PrebookingManager prebookingManager; public PrebookingActionCreator(PrebookingPassengerEngine passengerEngine, VrpAgentLogic.DynActionCreator delegate, - PassengerStopDurationProvider stopDurationProvider, PrebookingManager prebookingManager) { + PassengerStopDurationProvider stopDurationProvider) { this.delegate = delegate; this.passengerEngine = passengerEngine; this.stopDurationProvider = stopDurationProvider; - this.prebookingManager = prebookingManager; } @Override @@ -43,8 +41,7 @@ public DynAction createAction(DynAgent dynAgent, DvrpVehicle vehicle, double now if (getBaseTypeOrElseThrow(task).equals(DrtTaskBaseType.STOP)) { DrtStopTask stopTask = (DrtStopTask) task; return new PrebookingStopActivity(passengerEngine, dynAgent, stopTask, stopTask.getDropoffRequests(), - stopTask.getPickupRequests(), DrtActionCreator.DRT_STOP_NAME, stopDurationProvider, vehicle, - prebookingManager); + stopTask.getPickupRequests(), DrtActionCreator.DRT_STOP_NAME, () -> stopTask.getEndTime(), stopDurationProvider, vehicle); } return delegate.createAction(dynAgent, vehicle, now); diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingManager.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingManager.java index 49e93234a72..8c3176dfd1d 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingManager.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingManager.java @@ -1,5 +1,6 @@ package org.matsim.contrib.drt.extension.prebooking.dvrp; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; @@ -10,10 +11,8 @@ 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.drt.extension.prebooking.events.PassengerEnteringVehicleEvent; +import org.matsim.api.core.v01.population.Plan; import org.matsim.contrib.drt.extension.prebooking.events.PassengerRequestBookedEvent; -import org.matsim.contrib.drt.passenger.AcceptedDrtRequest; import org.matsim.contrib.dvrp.optimizer.Request; import org.matsim.contrib.dvrp.optimizer.VrpOptimizer; import org.matsim.contrib.dvrp.passenger.PassengerRequest; @@ -22,7 +21,9 @@ import org.matsim.contrib.dvrp.passenger.PassengerRequestValidator; import org.matsim.core.api.experimental.events.EventsManager; import org.matsim.core.mobsim.framework.MobsimAgent; +import org.matsim.core.mobsim.framework.MobsimAgent.State; import org.matsim.core.mobsim.qsim.InternalInterface; +import org.matsim.core.mobsim.qsim.agents.WithinDayAgentUtils; import org.matsim.core.mobsim.qsim.interfaces.MobsimEngine; import com.google.common.base.Preconditions; @@ -46,24 +47,13 @@ * @author Sebastian Hörl (sebhoerl), IRT SystemX */ public class PrebookingManager implements MobsimEngine { - private static final String PREBOOKED_REQUEST_PREFIX = "prebookedRequestId"; - private final String mode; private final Network network; private final EventsManager eventsManager; - private final PassengerRequestCreator requestCreator; - private final PassengerRequestValidator requestValidator; private final VrpOptimizer optimizer; - private final AtomicInteger currentRequestIndex = new AtomicInteger(-1); - - private final String requestAttribute; - - private final List prebookingQueue = new LinkedList<>(); - private final IdMap prebookedRequests = new IdMap<>(Request.class); - public PrebookingManager(String mode, Network network, PassengerRequestCreator requestCreator, VrpOptimizer optimizer, PassengerRequestValidator requestValidator, EventsManager eventsManager) { this.network = network; @@ -75,17 +65,11 @@ public PrebookingManager(String mode, Network network, PassengerRequestCreator r this.eventsManager = eventsManager; } - PassengerRequest consumePrebookedRequest(MobsimAgent agent, Leg leg) { - Verify.verify(leg.getMode().equals(mode), "Invalid mode for this prebooking manager"); + // Functionality for ID management - String rawRequestId = (String) leg.getAttributes().getAttribute(requestAttribute); - - if (rawRequestId == null) { - return null; - } - - return prebookedRequests.remove(Id.create(rawRequestId, Request.class)); - } + private static final String PREBOOKED_REQUEST_PREFIX = "prebookedRequestId"; + private final AtomicInteger currentRequestIndex = new AtomicInteger(-1); + private final String requestAttribute; private Id createRequestId() { return Id.create(mode + "_prebooked_" + currentRequestIndex.incrementAndGet(), Request.class); @@ -95,32 +79,34 @@ public boolean isPrebookedRequest(Id requestId) { return requestId.toString().startsWith(mode + "_prebooked_"); } - public void prebook(Person person, Leg leg, double earliestDepartureTime) { - Verify.verify(leg.getMode().equals(mode), "Invalid mode for this prebooking manager"); + public Id getRequestId(Leg leg) { + String rawRequestId = (String) leg.getAttributes().getAttribute(requestAttribute); - synchronized (prebookingQueue) { - this.prebookingQueue.add(new PrebookingQueueItem(person, leg, earliestDepartureTime)); + if (rawRequestId == null) { + return null; } - } - private Link getLink(Id linkId) { - return Preconditions.checkNotNull(network.getLinks().get(linkId), - "Link id=%s does not exist in network for mode %s. Agent departs from a link that does not belong to that network?", - linkId, mode); + return Id.create(rawRequestId, Request.class); } - private record PrebookingQueueItem(Person person, Leg leg, double earliestDepartureTime) { - } + // Booking functionality - @Override - public void onPrepareSim() { + private final PassengerRequestCreator requestCreator; + private final PassengerRequestValidator requestValidator; + private final List queue = new LinkedList<>(); + + public void prebook(MobsimAgent person, Leg leg, double earliestDepartureTime) { + Verify.verify(leg.getMode().equals(mode), "Invalid mode for this prebooking manager"); + + synchronized (queue) { + queue.add(new QueueItem(person, leg, earliestDepartureTime)); + } } - @Override - public void doSimStep(double now) { - synchronized (prebookingQueue) { - for (PrebookingQueueItem item : prebookingQueue) { - Verify.verify(item.leg.getMode().equals(mode), "Invalid mode for this prebooking manager"); + private void processQueue(double now) { + synchronized (queue) { + for (QueueItem item : queue) { + Verify.verify(!item.person.getState().equals(State.ABORT), "Cannot prebook aborted agent"); Id requestId = createRequestId(); @@ -131,6 +117,16 @@ public void doSimStep(double now) { getLink(item.leg.getRoute().getEndLinkId()), item.earliestDepartureTime, now); Set violations = requestValidator.validateRequest(request); + + Plan plan = WithinDayAgentUtils.getModifiablePlan(item.person); + int currentLegIndex = WithinDayAgentUtils.getCurrentPlanElementIndex(item.person); + int prebookingLegIndex = plan.getPlanElements().indexOf(item.leg); + + if (prebookingLegIndex <= currentLegIndex) { + violations = new HashSet<>(violations); + violations.add("past leg"); + } + if (!violations.isEmpty()) { String cause = String.join(", ", violations); eventsManager.processEvent(new PassengerRequestRejectedEvent(now, mode, request.getId(), @@ -141,17 +137,70 @@ public void doSimStep(double now) { } item.leg.getAttributes().putAttribute(requestAttribute, request.getId().toString()); - prebookedRequests.put(request.getId(), request); + requests.put(requestId, new RequestItem(request)); } } - prebookingQueue.clear(); + queue.clear(); + } + } + + private Link getLink(Id linkId) { + return Preconditions.checkNotNull(network.getLinks().get(linkId), + "Link id=%s does not exist in network for mode %s. Agent departs from a link that does not belong to that network?", + linkId, mode); + } + + private record QueueItem(MobsimAgent person, Leg leg, double earliestDepartureTime) { + } + + // Interface with PassengerEngine + + PassengerRequest consumePrebookedRequest(MobsimAgent agent, Leg leg) { + Verify.verify(leg.getMode().equals(mode), "Invalid mode for this prebooking manager"); + + Id requestId = getRequestId(leg); + + if (requestId == null) { + return null; + } + + RequestItem item = requests.get(requestId); + + if (item == null) { + return null; } + + return item.request; } - - void notifyEntering(double now, AcceptedDrtRequest request) { - eventsManager - .processEvent(new PassengerEnteringVehicleEvent(now, mode, request.getId(), request.getPassengerId())); + + // Housekeeping of requests + + private IdMap requests = new IdMap<>(Request.class); + + private class RequestItem { + // this class looks minimal for now, but will be extended with canceling + // functionality + final PassengerRequest request; + + RequestItem(PassengerRequest request) { + this.request = request; + } + } + + void notifyDropoff(Id requestId) { + requests.remove(requestId); + } + + // Engine code + + @Override + public void doSimStep(double now) { + processQueue(now); + } + + @Override + public void onPrepareSim() { } @Override @@ -160,5 +209,5 @@ public void afterSim() { @Override public void setInternalInterface(InternalInterface internalInterface) { - }; + } } diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingModeQSimModule.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingModeQSimModule.java index 9bfe632359e..594431ebc41 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingModeQSimModule.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingModeQSimModule.java @@ -43,9 +43,8 @@ protected void configureQSim() { DrtActionCreator delegate = getter.getModal(DrtActionCreator.class); PassengerStopDurationProvider stopDurationProvider = getter .getModal(PassengerStopDurationProvider.class); - PrebookingManager prebookingManager = getter.getModal(PrebookingManager.class); - return new PrebookingActionCreator(passengerEngine, delegate, stopDurationProvider, prebookingManager); + return new PrebookingActionCreator(passengerEngine, delegate, stopDurationProvider); })).in(Singleton.class); bindModal(VrpAgentLogic.DynActionCreator.class).to(modalKey(PrebookingActionCreator.class)); } else { diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingPassengerEngine.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingPassengerEngine.java index 5428e9bb659..99e2da77fdb 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingPassengerEngine.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingPassengerEngine.java @@ -20,6 +20,7 @@ import org.matsim.contrib.dvrp.passenger.PassengerRequestRejectedEvent; import org.matsim.contrib.dvrp.passenger.PassengerRequestRejectedEventHandler; import org.matsim.contrib.dvrp.passenger.PassengerRequestValidator; +import org.matsim.contrib.dvrp.passenger.PassengerWaitingEvent; import org.matsim.contrib.dvrp.run.DvrpModes; import org.matsim.core.api.experimental.events.EventsManager; import org.matsim.core.mobsim.framework.MobsimAgent; @@ -46,6 +47,7 @@ public final class PrebookingPassengerEngine implements PassengerEngine, Passeng private final String mode; private final MobsimTimer mobsimTimer; + private final EventsManager eventsManager; private final PassengerRequestCreator requestCreator; private final VrpOptimizer optimizer; @@ -77,6 +79,7 @@ public final class PrebookingPassengerEngine implements PassengerEngine, Passeng this.optimizer = optimizer; this.network = network; this.requestValidator = requestValidator; + this.eventsManager = eventsManager; this.prebookingManager = prebookingManager; internalPassengerHandling = new InternalPassengerHandling(mode, eventsManager); @@ -150,6 +153,8 @@ public boolean handleDeparture(double now, MobsimAgent agent, Id fromLinkI } } + eventsManager.processEvent(new PassengerWaitingEvent(now, mode, request.getId(), request.getPassengerId())); + return true; } diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingStopActivity.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingStopActivity.java index fcd4b0eac68..f2e992f5968 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingStopActivity.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/dvrp/PrebookingStopActivity.java @@ -3,6 +3,7 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.function.Supplier; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.IdMap; @@ -36,15 +37,16 @@ public class PrebookingStopActivity extends FirstLastSimStepDynActivity implemen private final IdMap leaveTimes = new IdMap<>(Request.class); private final Set> enteredRequests = new HashSet<>(); - private final PrebookingManager prebookingManager; private final PrebookingPassengerEngine passengerEngine; + private final PassengerStopDurationProvider stopDurationProvider; + private final Supplier endTime; public PrebookingStopActivity(PrebookingPassengerEngine passengerEngine, DynAgent driver, StayTask task, Map, ? extends AcceptedDrtRequest> dropoffRequests, Map, ? extends AcceptedDrtRequest> pickupRequests, String activityType, - PassengerStopDurationProvider stopDurationProvider, DvrpVehicle vehicle, - PrebookingManager prebookingManager) { + Supplier endTime, PassengerStopDurationProvider stopDurationProvider, + DvrpVehicle vehicle) { super(activityType); this.passengerEngine = passengerEngine; this.driver = driver; @@ -52,12 +54,12 @@ public PrebookingStopActivity(PrebookingPassengerEngine passengerEngine, DynAgen this.pickupRequests = pickupRequests; this.stopDurationProvider = stopDurationProvider; this.vehicle = vehicle; - this.prebookingManager = prebookingManager; + this.endTime = endTime; } @Override protected boolean isLastStep(double now) { - return updatePickupRequests(now) && leaveTimes.size() == 0; + return updatePickupRequests(now) && leaveTimes.size() == 0 && now >= endTime.get(); } @Override @@ -118,8 +120,6 @@ private boolean updatePickupRequests(double now) { } private void queuePickup(AcceptedDrtRequest request, double now) { - prebookingManager.notifyEntering(now, request); - double enterTime = now + stopDurationProvider.calcPickupDuration(vehicle, request.getRequest()); enterTimes.put(request.getId(), enterTime); } diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/electric/ElectricPrebookingActionCreator.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/electric/ElectricPrebookingActionCreator.java index ab7d089c458..aa71047ae36 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/electric/ElectricPrebookingActionCreator.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/electric/ElectricPrebookingActionCreator.java @@ -27,7 +27,6 @@ public class ElectricPrebookingActionCreator implements VrpAgentLogic.DynActionC private final PrebookingPassengerEngine passengerEngine; private final PassengerStopDurationProvider stopDurationProvider; private final MobsimTimer timer; - private final PrebookingManager prebookingManager; public ElectricPrebookingActionCreator(PrebookingPassengerEngine passengerEngine, VrpAgentLogic.DynActionCreator delegate, PassengerStopDurationProvider stopDurationProvider, @@ -36,7 +35,6 @@ public ElectricPrebookingActionCreator(PrebookingPassengerEngine passengerEngine this.passengerEngine = passengerEngine; this.stopDurationProvider = stopDurationProvider; this.timer = timer; - this.prebookingManager = prebookingManager; } @Override @@ -50,8 +48,8 @@ public DynAction createAction(DynAgent dynAgent, DvrpVehicle vehicle, double now stopTask.initTaskTracker(new OfflineETaskTracker((EvDvrpVehicle) vehicle, timer)); return new PrebookingStopActivity(passengerEngine, dynAgent, stopTask, stopTask.getDropoffRequests(), - stopTask.getPickupRequests(), DrtActionCreator.DRT_STOP_NAME, stopDurationProvider, vehicle, - prebookingManager); + stopTask.getPickupRequests(), DrtActionCreator.DRT_STOP_NAME, () -> stopTask.getEndTime(), + stopDurationProvider, vehicle); } return delegate.createAction(dynAgent, vehicle, now); diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/events/PassengerEnteringVehicleEventHandler.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/events/PassengerEnteringVehicleEventHandler.java deleted file mode 100644 index dcc64b5146f..00000000000 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/events/PassengerEnteringVehicleEventHandler.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.matsim.contrib.drt.extension.prebooking.events; - -import org.matsim.core.events.handler.EventHandler; - -/** - * @author Sebastian Hörl (sebhoerl), IRT SystemX - */ -public interface PassengerEnteringVehicleEventHandler extends EventHandler { - void handleEvent(final PassengerEnteringVehicleEvent event); -} diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/logic/AttributePrebookingLogic.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/logic/AttributePrebookingLogic.java index e7b85ac0720..e76cafbb8c4 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/logic/AttributePrebookingLogic.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/logic/AttributePrebookingLogic.java @@ -83,7 +83,7 @@ protected void scheduleRequests() { Leg leg = (Leg) element; if (leg.getMode().equals(mode)) { - Verify.verify(!foundLeg, "Person " + item.person().getId().toString() + Verify.verify(!foundLeg, "Person " + item.agent().getId().toString() + " has at least two drt legs in one trip."); foundLeg = true; @@ -92,7 +92,7 @@ protected void scheduleRequests() { } if (submissionTime != null) { - queue.schedule(submissionTime, item.person(), leg, plannedDepartureTime); + queue.schedule(submissionTime, item.agent(), leg, plannedDepartureTime); } } } diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/logic/FixedSharePrebookingLogic.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/logic/FixedSharePrebookingLogic.java index 02bb26cd16a..583e9a35d00 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/logic/FixedSharePrebookingLogic.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/logic/FixedSharePrebookingLogic.java @@ -72,7 +72,7 @@ protected void scheduleRequests() { double submissionTime = Double.isFinite(submissionSlack) ? leg.getDepartureTime().seconds() - submissionSlack : timeInterpretation.getSimulationStartTime(); - queue.schedule(submissionTime, item.person(), leg, earliestDepartureTime); + queue.schedule(submissionTime, item.agent(), leg, earliestDepartureTime); } } diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/logic/PopulationIterator.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/logic/PopulationIterator.java index 8735934790e..7d682054aa2 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/logic/PopulationIterator.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/logic/PopulationIterator.java @@ -35,10 +35,10 @@ public PersonItem next() { Person person = internalIterator.next(); MobsimAgent agent = qsim.getAgents().get(person.getId()); Plan plan = ((HasModifiablePlan) agent).getModifiablePlan(); - return new PersonItem(person, plan); + return new PersonItem(agent, plan); } - public record PersonItem(Person person, Plan plan) { + public record PersonItem(MobsimAgent agent, Plan plan) { } static public PopulationIterator create(Population population, QSim qsim) { diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/logic/TimedPrebookingLogic.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/logic/TimedPrebookingLogic.java index 30da7592701..284bf941e31 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/logic/TimedPrebookingLogic.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/logic/TimedPrebookingLogic.java @@ -6,8 +6,8 @@ import java.util.PriorityQueue; import org.matsim.api.core.v01.population.Leg; -import org.matsim.api.core.v01.population.Person; import org.matsim.contrib.drt.extension.prebooking.dvrp.PrebookingManager; +import org.matsim.core.mobsim.framework.MobsimAgent; import org.matsim.core.mobsim.framework.events.MobsimBeforeSimStepEvent; import org.matsim.core.mobsim.framework.events.MobsimInitializedEvent; import org.matsim.core.mobsim.framework.listeners.MobsimBeforeSimStepListener; @@ -41,7 +41,7 @@ public void notifyMobsimInitialized(@SuppressWarnings("rawtypes") MobsimInitiali @Override public void notifyMobsimBeforeSimStep(@SuppressWarnings("rawtypes") MobsimBeforeSimStepEvent event) { queue.getScheduledItems(event.getSimulationTime()).forEach(item -> { - prebookingManager.prebook(item.person(), item.leg(), item.departuretime()); + prebookingManager.prebook(item.agent(), item.leg(), item.departuretime()); }); } @@ -49,8 +49,8 @@ protected class PrebookingQueue { private PriorityQueue queue = new PriorityQueue<>(); private int sequence = 0; - public void schedule(double submissionTime, Person person, Leg leg, double departureTime) { - queue.add(new ScheduledItem(submissionTime, person, leg, departureTime, sequence++)); + public void schedule(double submissionTime, MobsimAgent agent, Leg leg, double departureTime) { + queue.add(new ScheduledItem(submissionTime, agent, leg, departureTime, sequence++)); } public Collection getScheduledItems(double time) { @@ -70,7 +70,7 @@ public void clear() { } - private record ScheduledItem(double submissionTime, Person person, Leg leg, double departuretime, int sequence) + private record ScheduledItem(double submissionTime, MobsimAgent agent, Leg leg, double departuretime, int sequence) implements Comparable { @Override public int compareTo(ScheduledItem o) { diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtAnalysisControlerListener.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtAnalysisControlerListener.java index 93029cd986d..fe767004ce0 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtAnalysisControlerListener.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtAnalysisControlerListener.java @@ -176,12 +176,13 @@ public void notifyIterationEnds(IterationEndsEvent event) { .collect(toList()); collection2Text(drtEventSequenceCollector.getRejectedRequestSequences().values(), filename(event, "drt_rejections", ".csv"), - String.join(delimiter, "time", "personId", "fromLinkId", "toLinkId", "fromX", "fromY", "toX", "toY"), seq -> { + String.join(delimiter, "time", "personId", "requestId", "fromLinkId", "toLinkId", "fromX", "fromY", "toX", "toY"), seq -> { DrtRequestSubmittedEvent submission = seq.getSubmitted(); Coord fromCoord = network.getLinks().get(submission.getFromLinkId()).getToNode().getCoord(); Coord toCoord = network.getLinks().get(submission.getToLinkId()).getToNode().getCoord(); return String.join(delimiter, submission.getTime() + "",// submission.getPersonId() + "",// + submission.getRequestId() + "",// submission.getFromLinkId() + "",// submission.getToLinkId() + "",// fromCoord.getX() + "",// @@ -215,6 +216,7 @@ public void notifyIterationEnds(IterationEndsEvent event) { "submissionTime", // "departureTime",// "personId",// + "requestId",// "vehicleId",// "fromLinkId",// "fromX",// @@ -236,6 +238,7 @@ public void notifyIterationEnds(IterationEndsEvent event) { (Double)leg.submissionTime + "",// (Double)leg.departureTime + "",// leg.person + "",// + leg.request + "",// leg.vehicle + "",// leg.fromLinkId + "",// format.format(leg.fromCoord.getX()),// diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtEventSequenceCollector.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtEventSequenceCollector.java index f70931a4e06..47ad8a86847 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtEventSequenceCollector.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtEventSequenceCollector.java @@ -24,7 +24,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -52,19 +51,37 @@ import org.matsim.contrib.dvrp.passenger.PassengerRequestRejectedEventHandler; import org.matsim.contrib.dvrp.passenger.PassengerRequestScheduledEvent; import org.matsim.contrib.dvrp.passenger.PassengerRequestScheduledEventHandler; +import org.matsim.contrib.dvrp.passenger.PassengerWaitingEvent; +import org.matsim.contrib.dvrp.passenger.PassengerWaitingEventHandler; import com.google.common.base.Preconditions; +import com.google.common.base.Verify; /** - * Creates PerformedRequestEventSequence (for scheduled requests) and RejectedRequestEventSequence (for rejected requests). - * Almost all data for request/leg analysis is there (except info on actual paths), so should be quite reusable. + * Creates PerformedRequestEventSequence (for scheduled requests) and + * RejectedRequestEventSequence (for rejected requests). Almost all data for + * request/leg analysis is there (except info on actual paths), so should be + * quite reusable. + * + * Without prebooking, the order of sequences is always the same: First the + * agent *departs* then the request is *submitted*, then it is *rejected* or + * picked up. With prebooking, the order of departure and submission can be + * reversed: An agent first submits the request, and only later departs on the + * leg. Since *departure* is core MATSim, the respective event has no + * information about the request identifier. It could now happen that two + * submission with same characteristics have been submitted (person id, origin + * id). Then it is not clear which request belongs to the current departure. For + * that purpose the PassengerWaiting event has been introduced which is fired + * right after a departure has been processed by a DRT-related PassengerEngine. + * This events allows to link the latest departure of an agent to a request id. * * @author jbischoff * @author Michal Maciejewski + * @author Sebastian Hörl (sebhoerl), IRT SystemX */ public class DrtEventSequenceCollector implements PassengerRequestRejectedEventHandler, PassengerRequestScheduledEventHandler, - DrtRequestSubmittedEventHandler, PassengerPickedUpEventHandler, PassengerDroppedOffEventHandler, + DrtRequestSubmittedEventHandler, PassengerWaitingEventHandler, PassengerPickedUpEventHandler, PassengerDroppedOffEventHandler, PersonMoneyEventHandler, PersonDepartureEventHandler { public static class EventSequence { @@ -137,8 +154,8 @@ public boolean isCompleted() { private final Map, EventSequence> sequences = new HashMap<>(); private final List drtFarePersonMoneyEvents = new ArrayList<>(); - private final Map, List> sequencesWithoutDeparture = new HashMap<>(); - private final Map, List> departuresWithoutSequence = new HashMap<>(); + private final Map, PersonDepartureEvent> latestDepartures = new HashMap<>(); + private final Map, PersonDepartureEvent> waitingForSubmission = new HashMap<>(); public DrtEventSequenceCollector(String mode) { this.mode = mode; @@ -158,6 +175,8 @@ public Map, EventSequence> getRejectedRequestSequences() { public Map, EventSequence> getPerformedRequestSequences() { return sequences.entrySet().stream() // .filter(e -> e.getValue().getRejected().isEmpty()) // + .filter(e -> e.getValue().getDeparture().isPresent()) // + .filter(e -> e.getValue().getPickedUp().isPresent()) // .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue())); } @@ -169,8 +188,8 @@ public List getDrtFarePersonMoneyEvents() { public void reset(int iteration) { sequences.clear(); drtFarePersonMoneyEvents.clear(); - sequencesWithoutDeparture.clear(); - departuresWithoutSequence.clear(); + latestDepartures.clear(); + waitingForSubmission.clear(); } @Override @@ -178,35 +197,42 @@ public void handleEvent(DrtRequestSubmittedEvent event) { if (event.getMode().equals(mode)) { EventSequence sequence = new EventSequence(event); sequences.put(event.getRequestId(), sequence); - - PersonDepartureEvent departureEvent = popDepartureForSubmission(event); - - if (departureEvent == null) { - // We have a submitted request, but no departure event yet (i.e. a prebooking). We start the - // sequence and note down the person id to fill in the departure event later on. - sequencesWithoutDeparture.computeIfAbsent(event.getPersonId(), id -> new LinkedList<>()).add(sequence); - } else { - sequence.departure = departureEvent; - } + + // if we already have a departure + sequence.departure = waitingForSubmission.remove(event.getRequestId()); } } @Override public void handleEvent(PersonDepartureEvent event) { if (event.getLegMode().equals(mode)) { - EventSequence sequence = popSequenceForDeparture(event); + // note down the departure event here, for now we don't know which request it + // belongs to, see below + Verify.verify(!latestDepartures.containsKey(event.getPersonId()), + "Attempt to register a departure event for " + mode + " and person " + event.getPersonId() + + ", but there is still a departure that has not been consumed"); + latestDepartures.put(event.getPersonId(), event); + } + } + + @Override + public void handleEvent(PassengerWaitingEvent event) { + if (event.getMode().equals(mode)) { + // must exist, otherwise something is wrong + PersonDepartureEvent departureEvent = Objects.requireNonNull(latestDepartures.remove(event.getPersonId())); - if (sequence == null) { - // We have a departure event, but no submission yet (i.e. and instant booking). - // We note down the departure event here to recover it later when the submission - // is down (usually right after). - departuresWithoutSequence.computeIfAbsent(event.getPersonId(), id -> new LinkedList<>()).add(event); + EventSequence sequence = sequences.get(event.getRequestId()); + if (sequence != null) { + // prebooked request, we already have the submission + Verify.verifyNotNull(sequence.submitted); + sequence.departure = departureEvent; } else { - sequence.departure = event; + // immediate request, submission event should come soon + waitingForSubmission.put(event.getRequestId(), departureEvent); } } } - + @Override public void handleEvent(PassengerRequestScheduledEvent event) { if (event.getMode().equals(mode)) { @@ -254,72 +280,4 @@ public void handleEvent(PersonMoneyEvent event) { } } } - - /* - * This function is helper that finds a PersonDepartureEvent for a given - * DrtRequestSubmittedEvent. This means that the departure has happened before - * submission, which is the usually case for instant requests. - */ - private PersonDepartureEvent popDepartureForSubmission(DrtRequestSubmittedEvent event) { - List potentialDepartures = departuresWithoutSequence.get(event.getPersonId()); - PersonDepartureEvent result = null; - - if (potentialDepartures != null) { - Iterator iterator = potentialDepartures.iterator(); - - while (iterator.hasNext()) { - PersonDepartureEvent departureEvent = iterator.next(); - - if (event.getFromLinkId().equals(departureEvent.getLinkId())) { - if (result != null) { - throw new IllegalStateException( - "Ambiguous matching between submission and departure - not sure how to solve this"); - } - - iterator.remove(); - result = departureEvent; - } - } - - if (potentialDepartures.size() == 0) { - departuresWithoutSequence.remove(event.getPersonId()); - } - } - - return result; - } - - /* - * This function is helper that finds a sequence given a PersonDepartureEvent. - * This means that a sequence has started (the request has been submitted) - * before the agent has departed, i.e. this is a pre-booking of some sort. - */ - private EventSequence popSequenceForDeparture(PersonDepartureEvent event) { - EventSequence result = null; - List potentialSequences = sequencesWithoutDeparture.get(event.getPersonId()); - - if (potentialSequences != null) { - Iterator iterator = potentialSequences.iterator(); - - while (iterator.hasNext()) { - EventSequence sequence = iterator.next(); - - if (sequence.submitted.getFromLinkId().equals(event.getLinkId())) { - if (result != null) { - throw new IllegalStateException( - "Ambiguous matching between submission and departure - not sure how to solve this"); - } - - iterator.remove(); - result = sequence; - } - } - - if (potentialSequences.size() == 0) { - sequencesWithoutDeparture.remove(event.getPersonId()); - } - } - - return result; - } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtModeOptimizerQSimModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtModeOptimizerQSimModule.java index 82886c17508..92ba3a2376b 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtModeOptimizerQSimModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtModeOptimizerQSimModule.java @@ -46,6 +46,7 @@ import org.matsim.contrib.drt.scheduler.DrtScheduleInquiry; import org.matsim.contrib.drt.scheduler.EmptyVehicleRelocator; import org.matsim.contrib.drt.scheduler.RequestInsertionScheduler; +import org.matsim.contrib.drt.stops.PassengerStopDurationProvider; import org.matsim.contrib.drt.stops.StopTimeCalculator; import org.matsim.contrib.drt.vrpagent.DrtActionCreator; import org.matsim.contrib.dvrp.fleet.Fleet; @@ -66,6 +67,7 @@ import org.matsim.core.router.util.TravelTime; import com.google.inject.Inject; +import com.google.inject.TypeLiteral; /** * @author Michal Maciejewski (michalm) @@ -82,14 +84,17 @@ public DrtModeOptimizerQSimModule(DrtConfigGroup drtCfg) { protected void configureQSim() { addModalComponent(DrtOptimizer.class, modalProvider( getter -> { - RequestQueue requestQueue = DefaultRequestQueue.withLimitedAdvanceRequestPlanningHorizon(drtCfg.advanceRequestPlanningHorizon); - return new DefaultDrtOptimizer(drtCfg, getter.getModal(Fleet.class), getter.get(MobsimTimer.class), getter.getModal(DepotFinder.class), getter.getModal(RebalancingStrategy.class), getter.getModal(DrtScheduleInquiry.class), getter.getModal(ScheduleTimingUpdater.class), getter.getModal(EmptyVehicleRelocator.class), getter.getModal(UnplannedRequestInserter.class), - getter.getModal(DrtRequestInsertionRetryQueue.class), requestQueue); + getter.getModal(DrtRequestInsertionRetryQueue.class), + getter.getModal(new TypeLiteral>() {})); })); + + bindModal(new TypeLiteral>() {}).toProvider(modalProvider(getter -> { + return DefaultRequestQueue.withLimitedAdvanceRequestPlanningHorizon(drtCfg.advanceRequestPlanningHorizon); + })); bindModal(DepotFinder.class).toProvider( modalProvider(getter -> new NearestStartLinkAsDepot(getter.getModal(Fleet.class)))).asEagerSingleton(); @@ -106,7 +111,8 @@ protected void configureQSim() { getter.getModal(RequestInsertionScheduler.class), getter.getModal(VehicleEntry.EntryFactory.class), getter.getModal(DrtInsertionSearch.class), getter.getModal(DrtRequestInsertionRetryQueue.class), getter.getModal(DrtOfferAcceptor.class), - getter.getModal(QSimScopeForkJoinPoolHolder.class).getPool()))).asEagerSingleton(); + getter.getModal(QSimScopeForkJoinPoolHolder.class).getPool(), + getter.getModal(PassengerStopDurationProvider.class)))).asEagerSingleton(); bindModal(InsertionCostCalculator.class).toProvider(modalProvider( getter -> new DefaultInsertionCostCalculator(getter.getModal(CostCalculationStrategy.class)))); diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultUnplannedRequestInserter.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultUnplannedRequestInserter.java index 056d5ae0d4e..34503207f82 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultUnplannedRequestInserter.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultUnplannedRequestInserter.java @@ -38,6 +38,7 @@ import org.matsim.contrib.drt.passenger.DrtRequest; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.drt.scheduler.RequestInsertionScheduler; +import org.matsim.contrib.drt.stops.PassengerStopDurationProvider; import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.contrib.dvrp.fleet.Fleet; import org.matsim.contrib.dvrp.passenger.PassengerRequestRejectedEvent; @@ -63,22 +64,23 @@ public class DefaultUnplannedRequestInserter implements UnplannedRequestInserter private final DrtInsertionSearch insertionSearch; private final DrtRequestInsertionRetryQueue insertionRetryQueue; private final DrtOfferAcceptor drtOfferAcceptor; - private final ForkJoinPool forkJoinPool; + private final ForkJoinPool forkJoinPool; + private final PassengerStopDurationProvider stopDurationProvider; public DefaultUnplannedRequestInserter(DrtConfigGroup drtCfg, Fleet fleet, MobsimTimer mobsimTimer, EventsManager eventsManager, RequestInsertionScheduler insertionScheduler, VehicleEntry.EntryFactory vehicleEntryFactory, DrtInsertionSearch insertionSearch, DrtRequestInsertionRetryQueue insertionRetryQueue, DrtOfferAcceptor drtOfferAcceptor, - ForkJoinPool forkJoinPool) { + ForkJoinPool forkJoinPool, PassengerStopDurationProvider stopDurationProvider) { this(drtCfg.getMode(), fleet, mobsimTimer::getTimeOfDay, eventsManager, insertionScheduler, vehicleEntryFactory, - insertionRetryQueue, insertionSearch, drtOfferAcceptor, forkJoinPool); + insertionRetryQueue, insertionSearch, drtOfferAcceptor, forkJoinPool, stopDurationProvider); } @VisibleForTesting DefaultUnplannedRequestInserter(String mode, Fleet fleet, DoubleSupplier timeOfDay, EventsManager eventsManager, RequestInsertionScheduler insertionScheduler, VehicleEntry.EntryFactory vehicleEntryFactory, DrtRequestInsertionRetryQueue insertionRetryQueue, DrtInsertionSearch insertionSearch, - DrtOfferAcceptor drtOfferAcceptor, ForkJoinPool forkJoinPool) { + DrtOfferAcceptor drtOfferAcceptor, ForkJoinPool forkJoinPool, PassengerStopDurationProvider stopDurationProvider) { this.mode = mode; this.fleet = fleet; this.timeOfDay = timeOfDay; @@ -89,6 +91,7 @@ public DefaultUnplannedRequestInserter(DrtConfigGroup drtCfg, Fleet fleet, Mobsi this.insertionSearch = insertionSearch; this.drtOfferAcceptor = drtOfferAcceptor; this.forkJoinPool = forkJoinPool; + this.stopDurationProvider = stopDurationProvider; } @Override @@ -150,11 +153,17 @@ private void scheduleUnplannedRequest(DrtRequest req, Map, Vehic } else { vehicleEntries.remove(vehicle.getId()); } + + double expectedPickupTime = pickupDropoffTaskPair.pickupTask.getBeginTime(); + expectedPickupTime = Math.max(expectedPickupTime, acceptedRequest.get().getEarliestStartTime()); + expectedPickupTime += stopDurationProvider.calcPickupDuration(vehicle, req); + + double expectedDropoffTime = pickupDropoffTaskPair.dropoffTask.getBeginTime(); + expectedDropoffTime += stopDurationProvider.calcDropoffDuration(vehicle, req); eventsManager.processEvent( new PassengerRequestScheduledEvent(now, mode, req.getId(), req.getPassengerId(), vehicle.getId(), - pickupDropoffTaskPair.pickupTask.getEndTime(), - pickupDropoffTaskPair.dropoffTask.getBeginTime())); + expectedPickupTime, expectedDropoffTime)); } } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeModule.java index 6176da047c8..e4df7dd4981 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtModeModule.java @@ -26,6 +26,8 @@ import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingModule; import org.matsim.contrib.drt.speedup.DrtSpeedUp; import org.matsim.contrib.drt.stops.DefaultStopTimeCalculator; +import org.matsim.contrib.drt.stops.PassengerStopDurationProvider; +import org.matsim.contrib.drt.stops.StaticPassengerStopDurationProvider; import org.matsim.contrib.drt.stops.StopTimeCalculator; import org.matsim.contrib.dvrp.fleet.FleetModule; import org.matsim.contrib.dvrp.fleet.FleetSpecification; @@ -83,6 +85,10 @@ public void install() { addControlerListenerBinding().to(modalKey(DrtSpeedUp.class)); }); + bindModal(PassengerStopDurationProvider.class).toProvider(modalProvider(getter -> { + return StaticPassengerStopDurationProvider.of(drtCfg.stopDuration, 0.0); + })); + bindModal(DefaultStopTimeCalculator.class).toProvider(modalProvider(getter -> { return new DefaultStopTimeCalculator(drtCfg.stopDuration); })).in(Singleton.class); diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/DefaultUnplannedRequestInserterTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/DefaultUnplannedRequestInserterTest.java index ffc7e76818b..ee1e2efc29a 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/DefaultUnplannedRequestInserterTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/DefaultUnplannedRequestInserterTest.java @@ -49,6 +49,7 @@ import org.matsim.contrib.drt.schedule.DefaultDrtStopTask; import org.matsim.contrib.drt.scheduler.RequestInsertionScheduler; import org.matsim.contrib.drt.scheduler.RequestInsertionScheduler.PickupDropoffTaskPair; +import org.matsim.contrib.drt.stops.StaticPassengerStopDurationProvider; import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.contrib.dvrp.fleet.Fleet; import org.matsim.contrib.dvrp.optimizer.Request; @@ -287,7 +288,7 @@ private DefaultUnplannedRequestInserter newInserter(Fleet fleet, double now, DrtInsertionSearch insertionSearch, RequestInsertionScheduler insertionScheduler) { return new DefaultUnplannedRequestInserter(mode, fleet, () -> now, eventsManager, insertionScheduler, vehicleEntryFactory, insertionRetryQueue, insertionSearch, DrtOfferAcceptor.DEFAULT_ACCEPTOR, - rule.forkJoinPool); + rule.forkJoinPool, StaticPassengerStopDurationProvider.of(10.0, 0.0)); } private Link link(String id) { diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/DefaultPassengerEngine.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/DefaultPassengerEngine.java index 12600006799..8876208d137 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/DefaultPassengerEngine.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/DefaultPassengerEngine.java @@ -54,6 +54,7 @@ public final class DefaultPassengerEngine implements PassengerEngine, PassengerR private final String mode; private final MobsimTimer mobsimTimer; + private final EventsManager eventsManager; private final PassengerRequestCreator requestCreator; private final VrpOptimizer optimizer; @@ -79,6 +80,7 @@ public final class DefaultPassengerEngine implements PassengerEngine, PassengerR this.optimizer = optimizer; this.network = network; this.requestValidator = requestValidator; + this.eventsManager = eventsManager; internalPassengerHandling = new InternalPassengerHandling(mode, eventsManager); } @@ -123,6 +125,9 @@ public boolean handleDeparture(double now, MobsimAgent agent, Id fromLinkI PassengerRequest request = requestCreator.createRequest(internalPassengerHandling.createRequestId(), passenger.getId(), route, getLink(fromLinkId), getLink(toLinkId), now, now); validateAndSubmitRequest(passenger, request, now); + + eventsManager.processEvent(new PassengerWaitingEvent(now, mode, request.getId(), request.getPassengerId())); + return true; } diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/PassengerEngineWithPrebooking.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/PassengerEngineWithPrebooking.java index 3e6fb064d00..fc6bf25fc2d 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/PassengerEngineWithPrebooking.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/PassengerEngineWithPrebooking.java @@ -62,6 +62,7 @@ public final class PassengerEngineWithPrebooking private final String mode; private final MobsimTimer mobsimTimer; + private final EventsManager eventsManager; private final PreplanningEngine preplanningEngine; private final PassengerRequestCreator requestCreator; @@ -87,6 +88,7 @@ public final class PassengerEngineWithPrebooking this.optimizer = optimizer; this.network = network; this.requestValidator = requestValidator; + this.eventsManager = eventsManager; internalPassengerHandling = new InternalPassengerHandling(mode, eventsManager); } @@ -168,6 +170,9 @@ private Link getLink(Id linkId) { if (awaitingPickup != null) { awaitingPickup.notifyPassengerIsReadyForDeparture(passenger, now); } + + eventsManager.processEvent(new PassengerWaitingEvent(now, mode, prebookedRequest.getId(), prebookedRequest.getPassengerId())); + return true; } diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/events/PassengerEnteringVehicleEvent.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/PassengerWaitingEvent.java similarity index 73% rename from contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/events/PassengerEnteringVehicleEvent.java rename to contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/PassengerWaitingEvent.java index 6cc8a03e771..6c37f84a9be 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/prebooking/events/PassengerEnteringVehicleEvent.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/PassengerWaitingEvent.java @@ -17,7 +17,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.drt.extension.prebooking.events; +package org.matsim.contrib.dvrp.passenger; import java.util.Map; import java.util.Objects; @@ -26,19 +26,14 @@ import org.matsim.api.core.v01.events.GenericEvent; import org.matsim.api.core.v01.population.Person; import org.matsim.contrib.dvrp.optimizer.Request; -import org.matsim.contrib.dvrp.passenger.AbstractPassengerRequestEvent; /** - * When using prebooking in DRT, it is sometimes difficult to correctly - * attribute which request is being consumed when a customer enters a vehicle. - * The PassengerEnteringEvent provides exactly this information. - * * @author Sebastian Hörl (sebhoerl), IRT SystemX */ -public class PassengerEnteringVehicleEvent extends AbstractPassengerRequestEvent { - public static final String EVENT_TYPE = "passenger entering vehicle"; +public class PassengerWaitingEvent extends AbstractPassengerRequestEvent { + public static final String EVENT_TYPE = "passenger waiting"; - public PassengerEnteringVehicleEvent(double time, String mode, Id requestId, Id personId) { + public PassengerWaitingEvent(double time, String mode, Id requestId, Id personId) { super(time, mode, requestId, personId); } @@ -47,12 +42,12 @@ public String getEventType() { return EVENT_TYPE; } - public static PassengerEnteringVehicleEvent convert(GenericEvent event) { + public static PassengerWaitingEvent convert(GenericEvent event) { Map attributes = event.getAttributes(); double time = Double.parseDouble(attributes.get(ATTRIBUTE_TIME)); String mode = Objects.requireNonNull(attributes.get(ATTRIBUTE_MODE)); Id requestId = Id.create(attributes.get(ATTRIBUTE_REQUEST), Request.class); Id personId = Id.createPersonId(attributes.get(ATTRIBUTE_PERSON)); - return new PassengerEnteringVehicleEvent(time, mode, requestId, personId); + return new PassengerWaitingEvent(time, mode, requestId, personId); } } diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/PassengerWaitingEventHandler.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/PassengerWaitingEventHandler.java new file mode 100644 index 00000000000..1ca52e48d2f --- /dev/null +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/PassengerWaitingEventHandler.java @@ -0,0 +1,29 @@ +/* *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2017 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** */ + +package org.matsim.contrib.dvrp.passenger; + +import org.matsim.core.events.handler.EventHandler; + +/** + * @author Sebastian Hörl (sebhoerl), IRT SystemX + */ +public interface PassengerWaitingEventHandler extends EventHandler { + void handleEvent(final PassengerWaitingEvent event); +} 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 0906bed9e71..7dddeb6a4e0 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 @@ -156,6 +156,8 @@ public boolean handleDeparture(double now, MobsimAgent agent, Id fromLinkI passenger.setStateToAbort(mobsimTimer.getTimeOfDay()); internalInterface.arrangeNextAgentState(passenger); } + + eventsManager.processEvent(new PassengerWaitingEvent(now, mode, request.getId(), request.getPassengerId())); return true; } diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/util/DvrpEventsReaders.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/util/DvrpEventsReaders.java index 2df41bed134..093071c7f08 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/util/DvrpEventsReaders.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/util/DvrpEventsReaders.java @@ -28,6 +28,7 @@ import org.matsim.contrib.dvrp.passenger.PassengerRequestRejectedEvent; import org.matsim.contrib.dvrp.passenger.PassengerRequestScheduledEvent; import org.matsim.contrib.dvrp.passenger.PassengerRequestSubmittedEvent; +import org.matsim.contrib.dvrp.passenger.PassengerWaitingEvent; import org.matsim.contrib.dvrp.schedule.Task; import org.matsim.contrib.dvrp.vrpagent.TaskEndedEvent; import org.matsim.contrib.dvrp.vrpagent.TaskStartedEvent; @@ -41,6 +42,7 @@ public static Map createCustomEven return Map.of(PassengerRequestSubmittedEvent.EVENT_TYPE, PassengerRequestSubmittedEvent::convert,// PassengerRequestScheduledEvent.EVENT_TYPE, PassengerRequestScheduledEvent::convert,// PassengerRequestRejectedEvent.EVENT_TYPE, PassengerRequestRejectedEvent::convert,// + PassengerWaitingEvent.EVENT_TYPE, PassengerWaitingEvent::convert,// PassengerPickedUpEvent.EVENT_TYPE, PassengerPickedUpEvent::convert, // PassengerDroppedOffEvent.EVENT_TYPE, PassengerDroppedOffEvent::convert,// TaskStartedEvent.EVENT_TYPE, e -> TaskStartedEvent.convert(e, stringToTaskTypeConverter),