Skip to content

Commit

Permalink
Merge branch 'master' into refactor-parking-cost-handler
Browse files Browse the repository at this point in the history
  • Loading branch information
paulheinr authored Apr 10, 2024
2 parents ae5bb37 + 208f71f commit 291eb75
Show file tree
Hide file tree
Showing 10 changed files with 231 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import static org.matsim.contrib.drt.schedule.DrtTaskBaseType.getBaseTypeOrElseThrow;

import java.util.List;

import org.matsim.contrib.drt.passenger.AcceptedDrtRequest;
import org.matsim.contrib.drt.prebooking.abandon.AbandonVoter;
import org.matsim.contrib.drt.schedule.DrtStopTask;
import org.matsim.contrib.drt.schedule.DrtTaskBaseType;
Expand Down Expand Up @@ -47,11 +50,42 @@ public DynAction createAction(DynAgent dynAgent, DvrpVehicle vehicle, double now

if (getBaseTypeOrElseThrow(task).equals(DrtTaskBaseType.STOP)) {
DrtStopTask stopTask = (DrtStopTask) task;
int incomingCapacity = getIncomingOccupancy(vehicle, stopTask);

return new PrebookingStopActivity(passengerHandler, dynAgent, stopTask, stopTask.getDropoffRequests(),
stopTask.getPickupRequests(), DrtActionCreator.DRT_STOP_NAME, () -> stopTask.getEndTime(),
stopDurationProvider, vehicle, prebookingManager, abandonVoter);
stopDurationProvider, vehicle, prebookingManager, abandonVoter, incomingCapacity);
}

return delegate.createAction(dynAgent, vehicle, now);
}

private int getIncomingOccupancy(DvrpVehicle vehicle, DrtStopTask referenceTask) {
int incomingOccupancy = 0;

List<? extends Task> tasks = vehicle.getSchedule().getTasks();

int index = tasks.size() - 1;
while (index >= 0) {
Task task = tasks.get(index);

if (task instanceof DrtStopTask) {
DrtStopTask stopTask = (DrtStopTask) task;

incomingOccupancy += stopTask.getDropoffRequests().values().stream()
.mapToInt(AcceptedDrtRequest::getPassengerCount).sum();

incomingOccupancy -= stopTask.getPickupRequests().values().stream()
.mapToInt(AcceptedDrtRequest::getPassengerCount).sum();

if (task == referenceTask) {
return incomingOccupancy;
}
}

index--;
}

throw new IllegalStateException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,13 @@ public class PrebookingStopActivity extends FirstLastSimStepDynActivity implemen
private final AbandonVoter abandonVoter;

private final Supplier<Double> endTime;
private int onboard;

public PrebookingStopActivity(PassengerHandler passengerHandler, DynAgent driver, StayTask task,
Map<Id<Request>, ? extends AcceptedDrtRequest> dropoffRequests,
Map<Id<Request>, ? extends AcceptedDrtRequest> pickupRequests, String activityType,
Supplier<Double> endTime, PassengerStopDurationProvider stopDurationProvider, DvrpVehicle vehicle,
PrebookingManager prebookingManager, AbandonVoter abandonVoter) {
PrebookingManager prebookingManager, AbandonVoter abandonVoter, int initialOccupancy) {
super(activityType);
this.passengerHandler = passengerHandler;
this.driver = driver;
Expand All @@ -64,12 +65,13 @@ public PrebookingStopActivity(PassengerHandler passengerHandler, DynAgent driver
this.prebookingManager = prebookingManager;
this.abandonVoter = abandonVoter;
this.endTime = endTime;
this.onboard = initialOccupancy;
}

@Override
protected boolean isLastStep(double now) {
boolean pickupsReady = updatePickupRequests(now);
boolean dropoffsReady = updateDropoffRequests(now);
boolean pickupsReady = updatePickupRequests(now);
return pickupsReady && dropoffsReady && now >= endTime.get();
}

Expand Down Expand Up @@ -97,6 +99,7 @@ private boolean updateDropoffRequests(double now) {
if (entry.getValue() <= now) { // Request should leave now
passengerHandler.dropOffPassengers(driver, entry.getKey(), now);
prebookingManager.notifyDropoff(entry.getKey());
onboard -= dropoffRequests.get(entry.getKey()).getPassengerCount();
iterator.remove();
}
}
Expand Down Expand Up @@ -128,12 +131,18 @@ private boolean updatePickupRequests(double now) {
var enterIterator = enterTimes.entrySet().iterator();

while (enterIterator.hasNext()) {
if (onboard >= vehicle.getCapacity()) {
// only let people enter if there is currently free capacity
break;
}

var entry = enterIterator.next();

if (entry.getValue() <= now) {
// let agent enter now
Verify.verify(passengerHandler.tryPickUpPassengers(this, driver, entry.getKey(), now));
enteredRequests.add(entry.getKey());
onboard += pickupRequests.get(entry.getKey()).getPassengerCount();
enterIterator.remove();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.matsim.contrib.drt.passenger.DrtRequest;
import org.matsim.contrib.drt.prebooking.PrebookingTestEnvironment.RequestInfo;
import org.matsim.contrib.drt.prebooking.logic.AttributeBasedPrebookingLogic;
import org.matsim.contrib.drt.run.DrtConfigGroup;
import org.matsim.contrib.drt.stops.PassengerStopDurationProvider;
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;

Expand Down Expand Up @@ -566,7 +569,7 @@ void destinationEqualsPrebookedOrigin_twoRequests() {
assertEquals(8000.0 + 60.0 + 1.0, requestInfo.pickupTime, 1e-3);
assertEquals(8230.0, requestInfo.dropoffTime, 1e-3);
}

{
RequestInfo requestInfo = environment.getRequestInfo().get("requestC");
assertEquals(2.0, requestInfo.submissionTime, 1e-3);
Expand All @@ -576,7 +579,7 @@ void destinationEqualsPrebookedOrigin_twoRequests() {

assertEquals(4, environment.getTaskInfo().get("vehicleA").stream().filter(t -> t.type.equals("STOP")).count());
}

@Test
void destinationEqualsPrebookedOrigin_oneRequest() {
/*-
Expand Down Expand Up @@ -614,4 +617,147 @@ void destinationEqualsPrebookedOrigin_oneRequest() {

assertEquals(4, environment.getTaskInfo().get("vehicleA").stream().filter(t -> t.type.equals("STOP")).count());
}

@Test
void intraStopTiming_pickupTooEarly() {
/*-
* In this test, we cover the intra stop timing when we use customizable stop
* durations. Before the fix, there was a bug described by the following
* situation:
*
* - We look for an insertion for a pickup
* - We find an existing stop that already contains some dropoffs
* - Inserting the pickup overall will fit (assuming that the persons are dropped off, then picked up)
* - But because of variable stop durations, the pickup happens *before* the dropoffs
* - Leading to a few seconds in which the occupancy is higher than the vehicle capacity
*
* This test led to a VerifyException in VehicleOccupancyProfileCalculator.processOccupancyChange
*/

PrebookingTestEnvironment environment = new PrebookingTestEnvironment(utils) //
.addVehicle("vehicleA", 1, 1) //
.setVehicleCapacity(2) //
.addRequest("requestA1", 1, 1, 8, 8, 2000.0, 1.0) // forward
.addRequest("requestA2", 1, 1, 8, 8, 2000.0, 2.0) // forward
.addRequest("requestB1", 8, 8, 1, 1, 2356.0, 3.0) // backward
.configure(300.0, 2.0, 1800.0, 60.0) //
.endTime(12.0 * 3600.0);

Controler controller = environment.build();
installPrebooking(controller);

controller.addOverridingModule(new AbstractDvrpModeModule("drt") {
@Override
public void install() {
bindModal(PassengerStopDurationProvider.class).toInstance(new PassengerStopDurationProvider() {
@Override
public double calcPickupDuration(DvrpVehicle vehicle, DrtRequest request) {
if (request.getPassengerIds().get(0).toString().startsWith("requestA")) {
return 60.0;
} else {
return 30.0; // shorter than the dropoff duration (see below)
}
}

@Override
public double calcDropoffDuration(DvrpVehicle vehicle, DrtRequest request) {
return 60.0;
}
});
}
});

controller.run();

{
RequestInfo requestInfo = environment.getRequestInfo().get("requestA1");
assertEquals(1.0, requestInfo.submissionTime, 1e-3);
assertEquals(2000.0 + 60.0 + 1.0, requestInfo.pickupTime, 1e-3);
assertEquals(2356.0 + 60.0, requestInfo.dropoffTime, 1e-3);
}

{
RequestInfo requestInfo = environment.getRequestInfo().get("requestA2");
assertEquals(2.0, requestInfo.submissionTime, 1e-3);
assertEquals(2000.0 + 60.0 + 1.0, requestInfo.pickupTime, 1e-3);
assertEquals(2356.0 + 60.0, requestInfo.dropoffTime, 1e-3);
}

{
RequestInfo requestInfo = environment.getRequestInfo().get("requestB1");
assertEquals(3.0, requestInfo.submissionTime, 1e-3);
assertEquals(2356.0 + 60.0, requestInfo.pickupTime, 1e-3); // NOT 30s because we need to wait for the dropoffs
assertEquals(2753.0 + 60.0, requestInfo.dropoffTime, 1e-3);
}

assertEquals(3, environment.getTaskInfo().get("vehicleA").stream().filter(t -> t.type.equals("STOP")).count());
}

@Test
void intraStopTiming_dropoffTooLate() {
/*-
* Inverse situation of the previous test: A new request is inserted, but the dropoff
* happens too late compared to the pickups in the following stop task.
*
* This test led to a VerifyException in VehicleOccupancyProfileCalculator.processOccupancyChange
*/

PrebookingTestEnvironment environment = new PrebookingTestEnvironment(utils) //
.addVehicle("vehicleA", 1, 1) //
.setVehicleCapacity(2) //
.addRequest("requestA", 1, 1, 8, 8, 2000.0, 1.0) // forward
.addRequest("requestB1", 8, 8, 1, 1, 2356.0, 2.0) // backward
.addRequest("requestB2", 8, 8, 1, 1, 2356.0, 3.0) // backward
.configure(300.0, 2.0, 1800.0, 60.0) //
.endTime(12.0 * 3600.0);

Controler controller = environment.build();
installPrebooking(controller);

controller.addOverridingModule(new AbstractDvrpModeModule("drt") {
@Override
public void install() {
bindModal(PassengerStopDurationProvider.class).toInstance(new PassengerStopDurationProvider() {
@Override
public double calcPickupDuration(DvrpVehicle vehicle, DrtRequest request) {
return 60.0;
}

@Override
public double calcDropoffDuration(DvrpVehicle vehicle, DrtRequest request) {
if (request.getPassengerIds().get(0).toString().equals("requestA")) {
return 90.0; // longer than the pickups
} else {
return 60.0;
}
}
});
}
});

controller.run();

{
RequestInfo requestInfo = environment.getRequestInfo().get("requestA");
assertEquals(1.0, requestInfo.submissionTime, 1e-3);
assertEquals(2000.0 + 60.0 + 1.0, requestInfo.pickupTime, 1e-3);
assertEquals(2356.0 + 90.0, requestInfo.dropoffTime, 1e-3);
}

{
RequestInfo requestInfo = environment.getRequestInfo().get("requestB1");
assertEquals(2.0, requestInfo.submissionTime, 1e-3);
assertEquals(2356.0 + 60.0, requestInfo.pickupTime, 1e-3);
assertEquals(2753.0 + 60.0 + 30.0, requestInfo.dropoffTime, 1e-3); // +30 because we wait for dropoff of A for B2 to enter
}

{
RequestInfo requestInfo = environment.getRequestInfo().get("requestB2");
assertEquals(3.0, requestInfo.submissionTime, 1e-3);
assertEquals(2356.0 + 60.0 + 30.0, requestInfo.pickupTime, 1e-3); // +30 because we wait for dropoff of A
assertEquals(2753.0 + 60.0 + 30.0, requestInfo.dropoffTime, 1e-3); // +30 because we wait for dropoff of A
}

assertEquals(3, environment.getTaskInfo().get("vehicleA").stream().filter(t -> t.type.equals("STOP")).count());
}
}
2 changes: 1 addition & 1 deletion contribs/hybridsim/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<properties>
<protobuf.version>4.26.1</protobuf.version>
<grpc.version>1.62.2</grpc.version>
<grpc.version>1.63.0</grpc.version>
</properties>

<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ public Integer call() throws Exception {
.createInputDataDistribution(output, landuseCategoriesAndDataConnection,
usedLanduseConfiguration.toString(), indexLanduse, indexZones,
indexBuildings, indexInvestigationAreaRegions, shapeFileZoneNameColumn, buildingsPerZone, pathToInvestigationAreaData,
pathToExistingDataDistributionToZones);
pathToExistingDataDistributionToZones, shapeFileBuildingTypeColumn);
Map<String, Map<Id<Link>, Link>> linksPerZone = filterLinksForZones(scenario, indexZones, buildingsPerZone, shapeFileZoneNameColumn);

switch (usedSmallScaleCommercialTrafficType) {
Expand Down Expand Up @@ -882,7 +882,7 @@ private Id<Link> findPossibleLink(String zone, String selectedCategory, List<Str
if (buildingsPerZone.isEmpty()) {
List<SimpleFeature> buildingsFeatures = indexBuildings.getAllFeatures();
LanduseBuildingAnalysis.analyzeBuildingType(buildingsFeatures, buildingsPerZone,
landuseCategoriesAndDataConnection, indexLanduse, indexZones);
landuseCategoriesAndDataConnection, indexLanduse, indexZones, shapeFileBuildingTypeColumn);
}
Id<Link> newLink = null;
for (int a = 0; newLink == null && a < buildingsPerZone.get(zone).get(selectedCategory).size() * 2; a++) {
Expand Down
Loading

0 comments on commit 291eb75

Please sign in to comment.