diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/unscheduler/ComplexRequestUnscheduler.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/unscheduler/ComplexRequestUnscheduler.java index 4fb0cae5339..ca25cb41cbf 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/unscheduler/ComplexRequestUnscheduler.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/unscheduler/ComplexRequestUnscheduler.java @@ -65,7 +65,7 @@ public void unscheduleRequest(double now, Id vehicleId, Id DvrpVehicle vehicle = vehicleLookup.lookupVehicle(vehicleId); VehicleEntry vEntry = vehicleEntryFactory.create(vehicle, now); - Waypoint.Stop pickupStop = null; + Waypoint pickupStop = null; Waypoint.Stop dropoffStop = null; DrtStopTask pickupStopTask = null; @@ -89,6 +89,15 @@ public void unscheduleRequest(double now, Id vehicleId, Id } } + if(pickupStopTask == null) { + if(vEntry.start.task.orElseThrow() instanceof DrtStopTask stopTask) { + if(stopTask.getPickupRequests().containsKey(requestId)) { + pickupStopTask = stopTask; + pickupStop = vEntry.start; + } + } + } + Verify.verifyNotNull(pickupStopTask, "Could not find request that I'm supposed to unschedule"); Verify.verifyNotNull(dropoffStopTask, "Could not find request that I'm supposed to unschedule"); Verify.verifyNotNull(pickupStop); @@ -103,12 +112,13 @@ public void unscheduleRequest(double now, Id vehicleId, Id // removed the pickup and the StopAction will handle the situation // - or we found a stop, then it is not started yet and we can remove it - boolean removePickup = pickupStopTask.getPickupRequests().size() == 0 - && pickupStopTask.getDropoffRequests().size() == 0; - boolean removeDropoff = dropoffStopTask.getPickupRequests().size() == 0 - && dropoffStopTask.getDropoffRequests().size() == 0; + boolean removePickup = pickupStopTask.getPickupRequests().isEmpty() + && pickupStopTask.getDropoffRequests().isEmpty() + && pickupStop instanceof Waypoint.Stop; + boolean removeDropoff = dropoffStopTask.getPickupRequests().isEmpty() + && dropoffStopTask.getDropoffRequests().isEmpty(); - Replacement pickupReplacement = removePickup ? findReplacement(vEntry, pickupStop) : null; + Replacement pickupReplacement = removePickup ? findReplacement(vEntry, (Waypoint.Stop) pickupStop) : null; Replacement dropoffReplacement = removeDropoff ? findReplacement(vEntry, dropoffStop) : null; if (pickupReplacement != null && dropoffReplacement != null) { diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/prebooking/AbandonAndCancelTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/prebooking/AbandonAndCancelTest.java index 61241d7c293..ca3f22dd46f 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/prebooking/AbandonAndCancelTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/prebooking/AbandonAndCancelTest.java @@ -265,4 +265,69 @@ public void notifyMobsimBeforeSimStep(MobsimBeforeSimStepEvent e) { assertTrue(requestInfo.rejected); } } + + @Test + void cancelLateWithComplexUnschedulerTest() { + /* + * One person requests to depart at 2000 and also is there at 2000. Another + * person asks also to depart at 2000, but only arrives at 4000, i.e. the person + * has 1000s delay. + * + * In this test we manually cancel the second request at 3000.0 (so after + * departure of the first agent). + */ + + PrebookingTestEnvironment environment = new PrebookingTestEnvironment(utils) // + .addVehicle("vehicle", 1, 1) // + .addRequest("personOk", 0, 0, 5, 5, 2000.0, 0.0, 2000.0) // + .addRequest("personLate", 0, 0, 5, 5, 4000.0, 0.0, 2000.0) // + .configure(600.0, 1.3, 600.0, 60.0) // + .endTime(10.0 * 3600.0); + + Controler controller = environment.build(); + PrebookingParams prebookingParams = new PrebookingParams(); + prebookingParams.unschedulingMode = PrebookingParams.UnschedulingMode.Routing; + PrebookingTest.installPrebooking(controller, prebookingParams); + + controller.addOverridingQSimModule(new AbstractDvrpModeQSimModule("drt") { + @Override + protected void configureQSim() { + addModalQSimComponentBinding().toProvider(modalProvider(getter -> { + PrebookingManager prebookingManager = getter.getModal(PrebookingManager.class); + QSim qsim = getter.get(QSim.class); + + return new MobsimBeforeSimStepListener() { + @Override + public void notifyMobsimBeforeSimStep(MobsimBeforeSimStepEvent e) { + if (e.getSimulationTime() == 3000.0) { + PlanAgent planAgent = (PlanAgent) qsim.getAgents() + .get(Id.createPersonId("personLate")); + + Leg leg = TripStructureUtils.getLegs(planAgent.getCurrentPlan()).get(1); + + prebookingManager.cancel(leg); + } + } + }; + })); + } + }); + + controller.run(); + + { + RequestInfo requestInfo = environment.getRequestInfo().get("personOk"); + assertEquals(0.0, requestInfo.submissionTime, 1e-3); + assertEquals(2061.0, requestInfo.pickupTime, 1e-3); + assertEquals(3212.0, requestInfo.dropoffTime, 1e-3); // still waited quite a bit + } + + { + RequestInfo requestInfo = environment.getRequestInfo().get("personLate"); + assertEquals(0.0, requestInfo.submissionTimes.get(0), 1e-3); + // agent tries a non-prebooked request upon arrival + assertEquals(4000.0, requestInfo.submissionTimes.get(1), 1e-3); + assertTrue(requestInfo.rejected); + } + } } diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/prebooking/PrebookingTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/prebooking/PrebookingTest.java index 8a2f236a7b0..4809a205c8a 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/prebooking/PrebookingTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/prebooking/PrebookingTest.java @@ -12,7 +12,6 @@ import org.matsim.contrib.drt.stops.StaticPassengerStopDurationProvider; import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; -import org.matsim.contrib.dvrp.run.AbstractDvrpModeQSimModule; import org.matsim.core.controler.Controler; import org.matsim.testcases.MatsimTestUtils; @@ -57,12 +56,20 @@ void withoutPrebookedRequests() { } static PrebookingParams installPrebooking(Controler controller) { - return installPrebooking(controller, true); + return installPrebooking(controller, true, new PrebookingParams()); + } + + static PrebookingParams installPrebooking(Controler controller, PrebookingParams prebookingParams) { + return installPrebooking(controller, true, prebookingParams); } static PrebookingParams installPrebooking(Controler controller, boolean installLogic) { + return installPrebooking(controller, installLogic, new PrebookingParams()); + } + + static PrebookingParams installPrebooking(Controler controller, boolean installLogic, PrebookingParams prebookingParams) { DrtConfigGroup drtConfig = DrtConfigGroup.getSingleModeDrtConfig(controller.getConfig()); - drtConfig.addParameterSet(new PrebookingParams()); + drtConfig.addParameterSet(prebookingParams); if (installLogic) { AttributeBasedPrebookingLogic.install(controller, drtConfig);