diff --git a/contribs/common/src/main/java/org/matsim/contrib/common/timeprofile/ProfileWriter.java b/contribs/common/src/main/java/org/matsim/contrib/common/timeprofile/ProfileWriter.java index e98f9cbb2b4..aa942dea0eb 100644 --- a/contribs/common/src/main/java/org/matsim/contrib/common/timeprofile/ProfileWriter.java +++ b/contribs/common/src/main/java/org/matsim/contrib/common/timeprofile/ProfileWriter.java @@ -61,12 +61,18 @@ public interface ProfileView { private final String mode; private final ProfileView view; private final String outputFile; + private final boolean createdStacked; public ProfileWriter(MatsimServices matsimServices, String mode, ProfileView profileView, String fileName) { + this(matsimServices, mode, profileView, fileName, true); + } + + public ProfileWriter(MatsimServices matsimServices, String mode, ProfileView profileView, String fileName, boolean createdStacked) { this.matsimServices = matsimServices; this.mode = mode; this.view = profileView; this.outputFile = fileName; + this.createdStacked = createdStacked; } @Override @@ -91,7 +97,10 @@ public void notifyIterationEnds(IterationEndsEvent event) { if (createGraphsInterval > 0 && event.getIteration() % createGraphsInterval == 0) { DefaultTableXYDataset xyDataset = createXYDataset(times, profiles); generateImage(xyDataset, TimeProfileCharts.ChartType.Line); - generateImage(xyDataset, TimeProfileCharts.ChartType.StackedArea); + + if (createdStacked) { + generateImage(xyDataset, TimeProfileCharts.ChartType.StackedArea); + } } } diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/fleet/EvShiftDvrpFleetQSimModule.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/fleet/EvShiftDvrpFleetQSimModule.java index 429bb95b167..d3390979be4 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/fleet/EvShiftDvrpFleetQSimModule.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/fleet/EvShiftDvrpFleetQSimModule.java @@ -4,6 +4,7 @@ import org.matsim.api.core.v01.network.Network; import org.matsim.contrib.dvrp.fleet.DvrpVehicleImpl; import org.matsim.contrib.dvrp.fleet.Fleet; +import org.matsim.contrib.dvrp.fleet.FleetCreator; import org.matsim.contrib.dvrp.fleet.FleetSpecification; import org.matsim.contrib.dvrp.fleet.Fleets; import org.matsim.contrib.dvrp.run.AbstractDvrpModeQSimModule; @@ -23,12 +24,12 @@ public EvShiftDvrpFleetQSimModule(String mode) { @Override public void configureQSim() { - bindModal(Fleet.class).toProvider(new ModalProviders.AbstractProvider<>(getMode(), DvrpModes::mode) { + bindModal(FleetCreator.class).toProvider(new ModalProviders.AbstractProvider<>(getMode(), DvrpModes::mode) { @Inject private ElectricFleet evFleet; @Override - public Fleet get() { + public FleetCreator get() { FleetSpecification fleetSpecification = getModalInstance(FleetSpecification.class); Network network = getModalInstance(Network.class); return Fleets.createCustomFleet(fleetSpecification, diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java index e7f4f58b391..24cf33d1d61 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java @@ -43,6 +43,7 @@ import org.matsim.contrib.drt.vrpagent.DrtActionCreator; import org.matsim.contrib.dvrp.fleet.DvrpVehicleImpl; import org.matsim.contrib.dvrp.fleet.Fleet; +import org.matsim.contrib.dvrp.fleet.FleetCreator; import org.matsim.contrib.dvrp.fleet.FleetSpecification; import org.matsim.contrib.dvrp.fleet.Fleets; import org.matsim.contrib.dvrp.passenger.PassengerHandler; @@ -164,9 +165,9 @@ shiftsParams, new DefaultShiftStartLogic(), new DefaultAssignShiftToVehicleLogic bindModal(VrpAgentLogic.DynActionCreator.class).to(modalKey(ShiftDrtActionCreator.class)); - bindModal(Fleet.class).toProvider(new ModalProviders.AbstractProvider<>(getMode(), DvrpModes::mode) { + bindModal(FleetCreator.class).toProvider(new ModalProviders.AbstractProvider<>(getMode(), DvrpModes::mode) { @Override - public Fleet get() { + public FleetCreator get() { FleetSpecification fleetSpecification = getModalInstance(FleetSpecification.class); Network network = getModalInstance(Network.class); return Fleets.createCustomFleet(fleetSpecification, diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDvrpFleetQsimModule.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDvrpFleetQsimModule.java index 998b84a6156..f97279fe0a6 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDvrpFleetQsimModule.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDvrpFleetQsimModule.java @@ -3,7 +3,7 @@ import org.matsim.api.core.v01.network.Network; import org.matsim.contrib.drt.extension.operations.shifts.fleet.DefaultShiftDvrpVehicle; import org.matsim.contrib.dvrp.fleet.DvrpVehicleImpl; -import org.matsim.contrib.dvrp.fleet.Fleet; +import org.matsim.contrib.dvrp.fleet.FleetCreator; import org.matsim.contrib.dvrp.fleet.FleetSpecification; import org.matsim.contrib.dvrp.fleet.Fleets; import org.matsim.contrib.dvrp.run.AbstractDvrpModeQSimModule; @@ -21,10 +21,10 @@ public ShiftDvrpFleetQsimModule(String mode) { @Override public void configureQSim() { - bindModal(Fleet.class).toProvider(new ModalProviders.AbstractProvider<>(getMode(), DvrpModes::mode) { + bindModal(FleetCreator.class).toProvider(new ModalProviders.AbstractProvider<>(getMode(), DvrpModes::mode) { @Override - public Fleet get() { + public FleetCreator get() { FleetSpecification fleetSpecification = getModalInstance(FleetSpecification.class); Network network = getModalInstance(Network.class); return Fleets.createCustomFleet(fleetSpecification, 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 399804f9aee..d1b68bad70a 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 @@ -94,7 +94,6 @@ public class DrtAnalysisControlerListener implements IterationEndsListener, Shut private boolean vheaderWritten = false; private final String runId; private final DecimalFormat format = new DecimalFormat(); - private final int maxcap; private static final String notAvailableString = "NA"; private final String delimiter; @@ -110,7 +109,6 @@ public class DrtAnalysisControlerListener implements IterationEndsListener, Shut this.drtCfg = drtCfg; this.qSimCfg = config.qsim(); runId = Optional.ofNullable(config.controller().getRunId()).orElse(notAvailableString); - maxcap = findMaxVehicleCapacity(fleet); format.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US)); format.setMinimumIntegerDigits(1); @@ -210,6 +208,8 @@ public void notifyIterationEnds(IterationEndsEvent event) { event.getIteration()); double l_d = getTotalDistance(drtVehicleStats.getVehicleStates()) / (legs.size() * directDistanceMean); + int maxcap = drtVehicleStats.getVehicleStates().values().stream().mapToInt(v -> v.maxCapacity).max().orElse(0); + MinCountAndShareIdleVehiclesOverDay minCountAndShareIdleVehiclesOverDay = getMinCountAndShareIdleVehiclesOverDay(); String vehStats = summarizeVehicles(drtVehicleStats.getVehicleStates(), delimiter) + delimiter @@ -219,7 +219,7 @@ public void notifyIterationEnds(IterationEndsEvent event) { + delimiter + format.format(minCountAndShareIdleVehiclesOverDay.minCountIdleVehiclesOverDay); String occStats = summarizeDetailedOccupancyStats(drtVehicleStats.getVehicleStates(), delimiter, maxcap); - writeIterationVehicleStats(vehStats, occStats, event.getIteration()); + writeIterationVehicleStats(vehStats, occStats, event.getIteration(), maxcap); if (drtCfg.plotDetailedCustomerStats) { String header = String.join(delimiter, // "submissionTime", // @@ -347,7 +347,7 @@ private void writeIterationPassengerStats(String summarizeLegs, int it) { * @param summarizeVehicles * @param it iteration */ - private void writeIterationVehicleStats(String summarizeVehicles, String vehOcc, int it) { + private void writeIterationVehicleStats(String summarizeVehicles, String vehOcc, int it, int maxcap) { try (var bw = getAppendingBufferedWriter("drt_vehicle_stats", ".csv")) { if (!vheaderWritten) { bw.write(line("runId", "iteration", "vehicles", "totalServiceDuration", "totalDistance", "totalEmptyDistance", "emptyRatio", "totalPassengerDistanceTraveled", @@ -923,14 +923,6 @@ private static String summarizeVehicles(Map, DrtVehicleDistanceStats format.format(d_p_d_t) + ""); } - /** - * @param fleet - * @return - */ - static int findMaxVehicleCapacity(FleetSpecification fleet) { - return fleet.getVehicleSpecifications().values().stream().mapToInt(DvrpVehicleSpecification::getCapacity).max().getAsInt(); - } - private static String summarizeDetailedOccupancyStats(Map, DrtVehicleDistanceStats.VehicleState> vehicleDistances, String del, int maxcap) { DecimalFormat format = new DecimalFormat(); @@ -942,7 +934,7 @@ private static String summarizeDetailedOccupancyStats(Map, DrtVehicl double[] sum = new double[maxcap + 1]; for (DrtVehicleDistanceStats.VehicleState state : vehicleDistances.values()) { - for (int i = 0; i <= maxcap; i++) { + for (int i = 0; i < state.totalDistanceByOccupancy.length; i++) { sum[i] += state.totalDistanceByOccupancy[i]; } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtModeAnalysisModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtModeAnalysisModule.java index 67d38dad708..9b291e245df 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtModeAnalysisModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtModeAnalysisModule.java @@ -36,6 +36,8 @@ import org.matsim.contrib.drt.scheduler.EmptyVehicleRelocator; import org.matsim.contrib.drt.sharingmetrics.SharingMetricsModule; import org.matsim.contrib.dvrp.analysis.ExecutedScheduleCollector; +import org.matsim.contrib.dvrp.analysis.FleetSizeProfileCalculator; +import org.matsim.contrib.dvrp.analysis.FleetSizeProfileView; import org.matsim.contrib.dvrp.fleet.FleetSpecification; import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; import org.matsim.contrib.dvrp.schedule.Task; @@ -99,7 +101,7 @@ public void install() { addEventHandlerBinding().to(modalKey(ExecutedScheduleCollector.class)); bindModal(DrtVehicleDistanceStats.class).toProvider( - modalProvider(getter -> new DrtVehicleDistanceStats(getter.get(Network.class), drtCfg, getter.getModal(FleetSpecification.class)))) + modalProvider(getter -> new DrtVehicleDistanceStats(getter.get(Network.class), drtCfg))) .asEagerSingleton(); addEventHandlerBinding().to(modalKey(DrtVehicleDistanceStats.class)); @@ -124,6 +126,18 @@ public void install() { getter -> new VehicleTaskProfileCalculator(getMode(), getter.getModal(FleetSpecification.class), 300, getter.get(QSimConfigGroup.class)))).asEagerSingleton(); addEventHandlerBinding().to(modalKey(VehicleTaskProfileCalculator.class)); + + addControlerListenerBinding().toProvider(modalProvider(getter -> { + MatsimServices matsimServices = getter.get(MatsimServices.class); + String mode = drtCfg.getMode(); + var profileView = new FleetSizeProfileView(getter.getModal(FleetSizeProfileCalculator.class)); + return new ProfileWriter(matsimServices, mode, profileView, "fleet_size_profile", false); + })); + + bindModal(FleetSizeProfileCalculator.class).toProvider(modalProvider( + getter -> new FleetSizeProfileCalculator(getMode(), getter.getModal(FleetSpecification.class), 300, + getter.get(QSimConfigGroup.class)))).asEagerSingleton(); + addEventHandlerBinding().to(modalKey(FleetSizeProfileCalculator.class)); addControlerListenerBinding().toProvider(modalProvider(getter -> { MatsimServices matsimServices = getter.get(MatsimServices.class); diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtVehicleDistanceStats.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtVehicleDistanceStats.java index d167a3d7700..d6c613a4313 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtVehicleDistanceStats.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtVehicleDistanceStats.java @@ -34,7 +34,10 @@ import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.population.Person; import org.matsim.contrib.drt.run.DrtConfigGroup; -import org.matsim.contrib.dvrp.fleet.FleetSpecification; +import org.matsim.contrib.dvrp.fleet.VehicleAddedEvent; +import org.matsim.contrib.dvrp.fleet.VehicleAddedEventHandler; +import org.matsim.contrib.dvrp.fleet.VehicleRemovedEvent; +import org.matsim.contrib.dvrp.fleet.VehicleRemovedEventHandler; import org.matsim.contrib.dvrp.optimizer.Request; import org.matsim.contrib.dvrp.passenger.PassengerDroppedOffEvent; import org.matsim.contrib.dvrp.passenger.PassengerDroppedOffEventHandler; @@ -45,14 +48,16 @@ import org.matsim.vehicles.Vehicle; import com.google.common.base.Preconditions; +import com.google.common.base.Verify; /** * @author jbischoff * @author Michal Maciejewski + * @author Sebastian Hörl (sebhoerl), IRT SystemX */ public class DrtVehicleDistanceStats implements PassengerPickedUpEventHandler, LinkEnterEventHandler, PassengerDroppedOffEventHandler, - TeleportationArrivalEventHandler { + TeleportationArrivalEventHandler, VehicleAddedEventHandler, VehicleRemovedEventHandler { static class VehicleState { final Map, MutableDouble> distanceByPersonId = new HashMap<>(); @@ -61,8 +66,11 @@ static class VehicleState { double totalPassengerTraveledDistance = 0; //in (passenger x meters) final double[] totalDistanceByOccupancy; final double serviceDuration; + final int maxCapacity; + boolean active = true; private VehicleState(int maxCapacity, double serviceTime) { + this.maxCapacity = maxCapacity; this.totalDistanceByOccupancy = new double[maxCapacity + 1]; this.serviceDuration = serviceTime; } @@ -85,36 +93,44 @@ private void linkEntered(Link link) { private final String mode; private final Network network; - private final FleetSpecification fleetSpecification; - public DrtVehicleDistanceStats(Network network, DrtConfigGroup drtCfg, FleetSpecification fleetSpecification) { + public DrtVehicleDistanceStats(Network network, DrtConfigGroup drtCfg) { this.mode = drtCfg.getMode(); this.network = network; - this.fleetSpecification = fleetSpecification; - initializeVehicles(); } @Override public void reset(int iteration) { vehicleStates.clear(); - initializeVehicles(); } - private void initializeVehicles() { - int maxCapacity = DrtAnalysisControlerListener.findMaxVehicleCapacity(fleetSpecification); - fleetSpecification.getVehicleSpecifications() - .values() - .stream() - .forEach(spec -> vehicleStates.put(Id.createVehicleId(spec.getId()), - new VehicleState(maxCapacity, spec.getServiceEndTime() - spec.getServiceBeginTime()))); + @Override + public void handleEvent(VehicleAddedEvent event) { + var state = vehicleStates.get(Id.createVehicleId(event.getDvrpVehicleId())); + + if (state == null) { + vehicleStates.put(Id.createVehicleId(event.getDvrpVehicleId()), new VehicleState(event.getCapacity(), Double.NaN)); + } else { + state.active = true; + Verify.verify(state.maxCapacity == event.getCapacity()); + } + } + + @Override + public void handleEvent(VehicleRemovedEvent event) { + Objects.requireNonNull(vehicleStates.get(Id.createVehicleId(event.getDvrpVehicleId()))).active = false; } @Override public void handleEvent(PassengerPickedUpEvent event) { if (event.getMode().equals(mode)) { if (event.getVehicleId() != null) { - vehicleStates.get(Id.createVehicleId(event.getVehicleId())).distanceByPersonId.put(event.getPersonId(), - new MutableDouble()); + var state = vehicleStates.get(Id.createVehicleId(event.getVehicleId())); + + if (state.active) { + state.distanceByPersonId.put(event.getPersonId(), + new MutableDouble()); + } } } } @@ -122,7 +138,7 @@ public void handleEvent(PassengerPickedUpEvent event) { @Override public void handleEvent(LinkEnterEvent event) { VehicleState vehicleState = vehicleStates.get(event.getVehicleId()); - if (vehicleState != null) { + if (vehicleState != null && vehicleState.active) { vehicleState.linkEntered(network.getLinks().get(event.getLinkId())); } } @@ -133,9 +149,13 @@ public void handleEvent(LinkEnterEvent event) { public void handleEvent(PassengerDroppedOffEvent event) { if (event.getMode().equals(mode)) { if (event.getVehicleId() != null) { - double distance = vehicleStates.get(Id.createVehicleId(event.getVehicleId())).distanceByPersonId.remove( - event.getPersonId()).doubleValue(); - travelDistances.put(event.getRequestId(), distance); + var state = vehicleStates.get(Id.createVehicleId(event.getVehicleId())); + + if (state.active) { + double distance = state.distanceByPersonId.remove( + event.getPersonId()).doubleValue(); + travelDistances.put(event.getRequestId(), distance); + } } else { Preconditions.checkArgument( soonArrivingTeleportedRequests.put(event.getPersonId(), event.getRequestId()) == null, diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/util/DrtFleetExtensionHelper.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/util/DrtFleetExtensionHelper.java new file mode 100644 index 00000000000..5480001cf35 --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/util/DrtFleetExtensionHelper.java @@ -0,0 +1,71 @@ +package org.matsim.contrib.drt.util; + +import org.matsim.api.core.v01.network.Network; +import org.matsim.contrib.drt.schedule.DrtTaskFactory; +import org.matsim.contrib.dvrp.fleet.DvrpVehicle; +import org.matsim.contrib.dvrp.fleet.DvrpVehicleImpl; +import org.matsim.contrib.dvrp.fleet.DvrpVehicleSpecification; +import org.matsim.contrib.dvrp.fleet.FleetExtensionHelper; +import org.matsim.contrib.dvrp.fleet.FleetExtensionHelper.FleetExtensionHelperQSimModule; +import org.matsim.contrib.dvrp.run.AbstractDvrpModeQSimModule; + +/** + * This is a convenience class that simplifies the process of adding VRP agents + * to a DRT fleet during the QSim. On top of DVRP's FleetExtensionHelper it also + * makes sure to initialize the first schedule task. + * + * @author Sebastian Hörl (sebhoerl), IRT SystemX + */ +public class DrtFleetExtensionHelper { + private final FleetExtensionHelper delegate; + private final DrtTaskFactory taskFactory; + private final Network network; + + DrtFleetExtensionHelper(FleetExtensionHelper delegate, DrtTaskFactory taskFactory, Network network) { + this.delegate = delegate; + this.taskFactory = taskFactory; + this.network = network; + } + + public DvrpVehicle addVehicle(DvrpVehicleSpecification specification) { + DvrpVehicle vehicle = new DvrpVehicleImpl(specification, + network.getLinks().get(specification.getStartLinkId())); + + addVehicle(vehicle); + return vehicle; + } + + public void addVehicle(DvrpVehicle vehicle) { + vehicle.getSchedule().addTask(taskFactory.createInitialTask(vehicle, vehicle.getServiceBeginTime(), + vehicle.getServiceEndTime(), vehicle.getStartLink())); + + delegate.addVehicle(vehicle); + } + + static public class DrtFleetExtensionHelperQSimModule extends AbstractDvrpModeQSimModule { + private final boolean installFleetExtensionHelper; + + public DrtFleetExtensionHelperQSimModule(String mode) { + this(mode, true); + } + + public DrtFleetExtensionHelperQSimModule(String mode, boolean installFleetExtensionHelper) { + super(mode); + this.installFleetExtensionHelper = installFleetExtensionHelper; + } + + @Override + protected void configureQSim() { + if (installFleetExtensionHelper) { + install(new FleetExtensionHelperQSimModule(getMode())); + } + + bindModal(DrtFleetExtensionHelper.class).toProvider(modalProvider(getter -> { + return new DrtFleetExtensionHelper(getter.getModal(FleetExtensionHelper.class), + getter.getModal(DrtTaskFactory.class), getter.getModal(Network.class)); + })).asEagerSingleton(); + + addModalQSimComponentBinding().to(modalKey(FleetExtensionHelper.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 58637acaddc..b761e70ccb0 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 @@ -36,6 +36,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.IdMap; import org.matsim.api.core.v01.Identifiable; import org.matsim.api.core.v01.network.Link; import org.matsim.contrib.drt.optimizer.DrtRequestInsertionRetryParams; @@ -56,6 +57,7 @@ import org.matsim.core.api.experimental.events.EventsManager; import org.matsim.testcases.fakes.FakeLink; import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; import com.google.common.collect.ImmutableMap; @@ -260,8 +262,15 @@ private Collection requests(DrtRequest... requests) { } private Fleet fleet(DvrpVehicle... vehicles) { - var map = Arrays.stream(vehicles).collect(ImmutableMap.toImmutableMap(Identifiable::getId, v -> v)); - return () -> map; + Fleet fleet = Mockito.mock(Fleet.class); + + IdMap map = new IdMap<>(DvrpVehicle.class); + for (DvrpVehicle v : vehicles) { + map.put(v.getId(), v); + } + + Mockito.when(fleet.getVehicles()).thenReturn(map); + return fleet; } private DvrpVehicle vehicle(String vehicleId) { diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/run/examples/RunDrtExampleIT.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/run/examples/RunDrtExampleIT.java index 652d66ecf19..96f5a56ab57 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/run/examples/RunDrtExampleIT.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/run/examples/RunDrtExampleIT.java @@ -27,9 +27,11 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.Id; @@ -47,17 +49,28 @@ 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.drt.util.DrtFleetExtensionHelper; +import org.matsim.contrib.drt.util.DrtFleetExtensionHelper.DrtFleetExtensionHelperQSimModule; +import org.matsim.contrib.dvrp.fleet.DvrpVehicle; +import org.matsim.contrib.dvrp.fleet.DvrpVehicleSpecification; +import org.matsim.contrib.dvrp.fleet.Fleet; +import org.matsim.contrib.dvrp.fleet.FleetSpecification; +import org.matsim.contrib.dvrp.fleet.FleetSpecificationImpl; +import org.matsim.contrib.dvrp.fleet.ImmutableDvrpVehicleSpecification; import org.matsim.contrib.dvrp.passenger.PassengerRequestRejectedEvent; 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.run.AbstractDvrpModeModule; +import org.matsim.contrib.dvrp.run.AbstractDvrpModeQSimModule; import org.matsim.contrib.dvrp.run.DvrpConfigGroup; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; import org.matsim.core.controler.AbstractModule; import org.matsim.core.controler.Controler; import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.mobsim.framework.events.MobsimBeforeSimStepEvent; +import org.matsim.core.mobsim.framework.listeners.MobsimBeforeSimStepListener; import org.matsim.core.utils.io.IOUtils; import org.matsim.examples.ExamplesUtils; import org.matsim.testcases.MatsimTestUtils; @@ -353,6 +366,85 @@ void testRunDrtWithPrebooking() { verifyDrtCustomerStatsCloseToExpectedStats(utils.getOutputDirectory(), expectedStats); } + + + @Test + void testRunWithVariableFleetSize() { + Id.resetCaches(); + URL configUrl = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("mielec"), + "mielec_drt_config.xml"); + + Config config = ConfigUtils.loadConfig(configUrl, new MultiModeDrtConfigGroup(), new DvrpConfigGroup(), + new OTFVisConfigGroup()); + + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + + DrtConfigGroup drtConfig = DrtConfigGroup.getSingleModeDrtConfig(config); + drtConfig.addParameterSet(new PrebookingParams()); + + Controler controller = DrtControlerCreator.createControler(config, false); + + // here starts the extension of the fleet + // at 02h00 we add two new vehicles to the fleet that are in service between 8h00 and 12h00 + // they are removed again at 13h00 + + double insertionTime = 7200.0; + double removalTime = 46800.0; + + FleetSpecification addedFleetSpecification = new FleetSpecificationImpl(); + for (int i = 0; i < 3; i++) { + addedFleetSpecification.addVehicleSpecification(ImmutableDvrpVehicleSpecification.newBuilder() // + .id(Id.create("added:" + i, DvrpVehicle.class)) // + .capacity(4) // + .serviceBeginTime(28800.0) // + .serviceEndTime(43200.0) // + .startLinkId(Id.createLinkId("313")) // + .build()); + } + + controller.addOverridingQSimModule(new DrtFleetExtensionHelperQSimModule("drt")); + + controller.addOverridingQSimModule(new AbstractDvrpModeQSimModule("drt") { + @Override + protected void configureQSim() { + addModalComponent(MobsimBeforeSimStepListener.class, modalProvider(getter -> { + DrtFleetExtensionHelper helper = getter.getModal(DrtFleetExtensionHelper.class); + Fleet fleet = getter.getModal(Fleet.class); + List vehicles = new LinkedList<>(); + + return new MobsimBeforeSimStepListener() { + @Override + public void notifyMobsimBeforeSimStep(@SuppressWarnings("rawtypes") MobsimBeforeSimStepEvent e) { + if (e.getSimulationTime() == insertionTime) { + for (DvrpVehicleSpecification specification : addedFleetSpecification.getVehicleSpecifications().values()) { + vehicles.add(helper.addVehicle(specification)); + } + } + + if (e.getSimulationTime() == removalTime) { + vehicles.forEach(v -> fleet.removeVehicle(v.getId())); + } + } + }; + })); + } + }); + + // end of code extending the fleet + + controller.run(); + + var expectedStats = Stats.newBuilder() + .rejectionRate(0.03) + .rejections(12) + .waitAverage(255.58) + .inVehicleTravelTimeMean(387.27) + .totalTravelTimeMean(642.85) + .build(); + + verifyDrtCustomerStatsCloseToExpectedStats(utils.getOutputDirectory(), expectedStats); + } /** * Early warning system: if customer stats vary more than the defined percentage above or below the expected values diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/analysis/FleetSizeProfileCalculator.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/analysis/FleetSizeProfileCalculator.java new file mode 100644 index 00000000000..703a85f4908 --- /dev/null +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/analysis/FleetSizeProfileCalculator.java @@ -0,0 +1,104 @@ +/* + * *********************************************************************** * + * project: org.matsim.* + * *********************************************************************** * + * * + * copyright : (C) 2023 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.analysis; + +import org.matsim.contrib.common.timeprofile.TimeDiscretizer; +import org.matsim.contrib.dvrp.fleet.DvrpVehicleSpecification; +import org.matsim.contrib.dvrp.fleet.FleetSpecification; +import org.matsim.contrib.dvrp.fleet.VehicleAddedEvent; +import org.matsim.contrib.dvrp.fleet.VehicleAddedEventHandler; +import org.matsim.contrib.dvrp.fleet.VehicleRemovedEvent; +import org.matsim.contrib.dvrp.fleet.VehicleRemovedEventHandler; +import org.matsim.core.config.groups.QSimConfigGroup; + +/** + * @author Sebastian Hörl (sebhoerl), IRT SystemX + */ +public class FleetSizeProfileCalculator implements VehicleAddedEventHandler, VehicleRemovedEventHandler { + + private final String dvrpMode; + + private final double analysisEndTime; + private final TimeDiscretizer timeDiscretizer; + + private double[] activeCount; + + public FleetSizeProfileCalculator(String dvrpMode, FleetSpecification fleet, int timeInterval, + QSimConfigGroup qsimConfig) { + this.dvrpMode = dvrpMode; + + double qsimEndTime = qsimConfig.getEndTime().orElse(0); + double maxServiceEndTime = fleet.getVehicleSpecifications().values().stream() + .mapToDouble(DvrpVehicleSpecification::getServiceEndTime).max().orElse(0); + analysisEndTime = Math.max(qsimEndTime, maxServiceEndTime); + timeDiscretizer = new TimeDiscretizer((int) Math.ceil(analysisEndTime), timeInterval); + + activeCount = new double[timeDiscretizer.getIntervalCount()]; + } + + @Override + public void handleEvent(VehicleAddedEvent event) { + if (event.getDvrpMode().equals(dvrpMode)) { + increment(event.getTime()); + } + } + + @Override + public void handleEvent(VehicleRemovedEvent event) { + if (event.getDvrpMode().equals(dvrpMode)) { + decrement(event.getTime()); + } + } + + private void increment(double startTime) { + double timeInterval = timeDiscretizer.getTimeInterval(); + int fromIdx = timeDiscretizer.getIdx(startTime); + + for (int i = fromIdx; i < timeDiscretizer.getIntervalCount(); i++) { + activeCount[i] += 1.0; + } + + activeCount[fromIdx] -= (startTime % timeInterval) / timeInterval; + } + + private void decrement(double startTime) { + double timeInterval = timeDiscretizer.getTimeInterval(); + int fromIdx = timeDiscretizer.getIdx(startTime); + + for (int i = fromIdx; i < timeDiscretizer.getIntervalCount(); i++) { + activeCount[i] -= 1.0; + } + + activeCount[fromIdx] += (startTime % timeInterval) / timeInterval; + } + + public double[] getActiveVehiclesProfile() { + return activeCount; + } + + public TimeDiscretizer getTimeDiscretizer() { + return timeDiscretizer; + } + + @Override + public void reset(int iteration) { + activeCount = new double[timeDiscretizer.getIntervalCount()]; + } +} diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/analysis/FleetSizeProfileView.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/analysis/FleetSizeProfileView.java new file mode 100644 index 00000000000..a293159e2c9 --- /dev/null +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/analysis/FleetSizeProfileView.java @@ -0,0 +1,52 @@ +/* + * *********************************************************************** * + * project: org.matsim.* + * *********************************************************************** * + * * + * copyright : (C) 2023 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.analysis; + +import java.awt.Color; +import java.awt.Paint; +import java.util.Map; + +import org.matsim.contrib.common.timeprofile.ProfileWriter; + +import com.google.common.collect.ImmutableMap; + +public class FleetSizeProfileView implements ProfileWriter.ProfileView { + private final FleetSizeProfileCalculator calculator; + + public FleetSizeProfileView(FleetSizeProfileCalculator calculator) { + this.calculator = calculator; + } + + @Override + public ImmutableMap profiles() { + return ImmutableMap.of("Fleet size", calculator.getActiveVehiclesProfile()); + } + + @Override + public Map seriesPaints() { + return ImmutableMap.of("Fleet size", Color.RED); + } + + @Override + public double[] times() { + return calculator.getTimeDiscretizer().getTimes(); + } +} diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/analysis/VehicleOccupancyProfileCalculator.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/analysis/VehicleOccupancyProfileCalculator.java index 16a8136492c..6c4bc47eb8f 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/analysis/VehicleOccupancyProfileCalculator.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/analysis/VehicleOccupancyProfileCalculator.java @@ -19,11 +19,11 @@ */ package org.matsim.contrib.dvrp.analysis; -import static com.google.common.collect.ImmutableList.toImmutableList; - +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import java.util.stream.IntStream; import org.matsim.api.core.v01.Id; @@ -35,11 +35,15 @@ import org.matsim.api.core.v01.events.handler.PersonEntersVehicleEventHandler; import org.matsim.api.core.v01.events.handler.PersonLeavesVehicleEventHandler; import org.matsim.api.core.v01.population.Person; +import org.matsim.contrib.common.timeprofile.TimeDiscretizer; import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.contrib.dvrp.fleet.DvrpVehicleSpecification; import org.matsim.contrib.dvrp.fleet.FleetSpecification; +import org.matsim.contrib.dvrp.fleet.VehicleAddedEvent; +import org.matsim.contrib.dvrp.fleet.VehicleAddedEventHandler; +import org.matsim.contrib.dvrp.fleet.VehicleRemovedEvent; +import org.matsim.contrib.dvrp.fleet.VehicleRemovedEventHandler; import org.matsim.contrib.dvrp.schedule.Task; -import org.matsim.contrib.common.timeprofile.TimeDiscretizer; import org.matsim.contrib.dvrp.vrpagent.TaskEndedEvent; import org.matsim.contrib.dvrp.vrpagent.TaskEndedEventHandler; import org.matsim.contrib.dvrp.vrpagent.TaskStartedEvent; @@ -49,15 +53,15 @@ import com.google.common.base.Preconditions; import com.google.common.base.Verify; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; /** * @author michalm (Michal Maciejewski) + * @author Sebastian Hörl (sebhoerl), IRT SystemX */ public class VehicleOccupancyProfileCalculator implements PersonEntersVehicleEventHandler, PersonLeavesVehicleEventHandler, TaskStartedEventHandler, - TaskEndedEventHandler { + TaskEndedEventHandler, VehicleAddedEventHandler, VehicleRemovedEventHandler { private static class VehicleState { private Task.TaskType taskType; @@ -68,13 +72,13 @@ private static class VehicleState { private final TimeDiscretizer timeDiscretizer; private Map nonPassengerServingTaskProfiles; - private ImmutableList vehicleOccupancyProfiles; + private ArrayList vehicleOccupancyProfiles; private final ImmutableSet passengerServingTaskTypes; private final Map, VehicleState> vehicleStates = new IdMap<>(DvrpVehicle.class); private final double analysisEndTime; - private final int maxCapacity; + private int initialCapacity; private final String dvrpMode; @@ -95,7 +99,7 @@ public VehicleOccupancyProfileCalculator(String dvrpMode, FleetSpecification fle analysisEndTime = Math.max(qsimEndTime, maxServiceEndTime); timeDiscretizer = new TimeDiscretizer((int)Math.ceil(analysisEndTime), timeInterval); - maxCapacity = fleet.getVehicleSpecifications() + initialCapacity = fleet.getVehicleSpecifications() .values() .stream() .mapToInt(DvrpVehicleSpecification::getCapacity) @@ -162,14 +166,18 @@ public TimeDiscretizer getTimeDiscretizer() { } private void increment(VehicleState state, double endTime) { - Verify.verify(state.taskType != null); + if (state.taskType == null) { + // will be null if a vehicle has been added to the fleet, but the task that has + // ended came from a different dvrp mode + return; + } + Verify.verify(state.occupancy >= 0); - Verify.verify(state.occupancy <= maxCapacity); boolean servingPassengers = passengerServingTaskTypes.contains(state.taskType) || state.occupancy > 0; double[] profile = servingPassengers ? - vehicleOccupancyProfiles.get(state.occupancy) : + occupancyProfile(state.occupancy) : nonPassengerServingTaskProfiles.computeIfAbsent(state.taskType, v -> new double[timeDiscretizer.getIntervalCount()]); increment(profile, Math.min(state.beginTime, endTime), endTime); @@ -199,18 +207,30 @@ private void increment(double[] values, double beginTime, double endTime) { /* Event handling starts here */ @Override - public void handleEvent(TaskStartedEvent event) { + public void handleEvent(VehicleAddedEvent event) { if (!event.getDvrpMode().equals(dvrpMode)) { return; } + + vehicleStates.put(event.getDvrpVehicleId(), new VehicleState()); + } - final VehicleState state; - if (event.getTaskIndex() == 0) { - state = new VehicleState(); - vehicleStates.put(event.getDvrpVehicleId(), state); - } else { - state = vehicleStates.get(event.getDvrpVehicleId()); + @Override + public void handleEvent(VehicleRemovedEvent event) { + if (!event.getDvrpMode().equals(dvrpMode)) { + return; } + + increment(vehicleStates.remove(event.getDvrpVehicleId()), event.getTime()); + } + + @Override + public void handleEvent(TaskStartedEvent event) { + if (!event.getDvrpMode().equals(dvrpMode)) { + return; + } + + VehicleState state = vehicleStates.get(event.getDvrpVehicleId()); state.taskType = event.getTaskType(); state.beginTime = event.getTime(); } @@ -249,13 +269,21 @@ private boolean isDriver(Id personId, Id vehicleId) { return personId.equals(vehicleId); } + private double[] occupancyProfile(int occupancy) { + while (vehicleOccupancyProfiles.size() <= occupancy) { + vehicleOccupancyProfiles.add(new double[timeDiscretizer.getIntervalCount()]); + } + + return vehicleOccupancyProfiles.get(occupancy); + } + @Override public void reset(int iteration) { vehicleStates.clear(); - vehicleOccupancyProfiles = IntStream.rangeClosed(0, maxCapacity) + vehicleOccupancyProfiles = new ArrayList<>(IntStream.rangeClosed(0, initialCapacity) .mapToObj(i -> new double[timeDiscretizer.getIntervalCount()]) - .collect(toImmutableList()); + .collect(Collectors.toList())); nonPassengerServingTaskProfiles = new HashMap<>(); wasConsolidatedInThisIteration = false; diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/analysis/VehicleTaskProfileCalculator.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/analysis/VehicleTaskProfileCalculator.java index 673eae38188..4c51de9c1a0 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/analysis/VehicleTaskProfileCalculator.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/analysis/VehicleTaskProfileCalculator.java @@ -27,6 +27,10 @@ import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.contrib.dvrp.fleet.DvrpVehicleSpecification; import org.matsim.contrib.dvrp.fleet.FleetSpecification; +import org.matsim.contrib.dvrp.fleet.VehicleAddedEvent; +import org.matsim.contrib.dvrp.fleet.VehicleAddedEventHandler; +import org.matsim.contrib.dvrp.fleet.VehicleRemovedEvent; +import org.matsim.contrib.dvrp.fleet.VehicleRemovedEventHandler; import org.matsim.contrib.dvrp.schedule.Task; import org.matsim.contrib.common.timeprofile.TimeDiscretizer; import org.matsim.contrib.dvrp.vrpagent.TaskEndedEvent; @@ -36,15 +40,15 @@ import org.matsim.core.config.groups.QSimConfigGroup; import com.google.common.base.Preconditions; -import com.google.common.base.Verify; /** * Collects task profiles of DVRP vehicles. Based on {@link VehicleOccupancyProfileCalculator} but only collects tasks. * * @author nkuehnel / MOIA + * @author Sebastian Hörl (sebhoerl), IRT SystemX */ public class VehicleTaskProfileCalculator implements TaskStartedEventHandler, - TaskEndedEventHandler { + TaskEndedEventHandler, VehicleAddedEventHandler, VehicleRemovedEventHandler { private static class VehicleState { private Task.TaskType taskType; @@ -114,7 +118,11 @@ public TimeDiscretizer getTimeDiscretizer() { } private void increment(VehicleState state, double endTime) { - Verify.verify(state.taskType != null); + if (state.taskType == null) { + // will be null if a vehicle has been added to the fleet, but the task that has + // ended came from a different dvrp mode + return; + } double[] profile = taskProfiles.computeIfAbsent(state.taskType, v -> new double[timeDiscretizer.getIntervalCount()]); @@ -145,18 +153,30 @@ private void increment(double[] values, double beginTime, double endTime) { /* Event handling starts here */ @Override - public void handleEvent(TaskStartedEvent event) { + public void handleEvent(VehicleAddedEvent event) { if (!event.getDvrpMode().equals(dvrpMode)) { return; } + + vehicleStates.put(event.getDvrpVehicleId(), new VehicleState()); + } - final VehicleState state; - if (event.getTaskIndex() == 0) { - state = new VehicleState(); - vehicleStates.put(event.getDvrpVehicleId(), state); - } else { - state = vehicleStates.get(event.getDvrpVehicleId()); + @Override + public void handleEvent(VehicleRemovedEvent event) { + if (!event.getDvrpMode().equals(dvrpMode)) { + return; } + + increment(vehicleStates.remove(event.getDvrpVehicleId()), event.getTime()); + } + + @Override + public void handleEvent(TaskStartedEvent event) { + if (!event.getDvrpMode().equals(dvrpMode)) { + return; + } + + VehicleState state = vehicleStates.get(event.getDvrpVehicleId()); state.taskType = event.getTaskType(); state.beginTime = event.getTime(); } diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/AbstractFleetEvent.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/AbstractFleetEvent.java new file mode 100644 index 00000000000..d46685010b8 --- /dev/null +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/AbstractFleetEvent.java @@ -0,0 +1,41 @@ +package org.matsim.contrib.dvrp.fleet; + +import java.util.Map; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.events.Event; + +/** + * Base class for fleet-related events in DVRP + * + * @author Sebastian Hörl (sebhoerl), IRT SystemX + */ +public abstract class AbstractFleetEvent extends Event { + protected static final String MODE_ATTRIBUTE = "mode"; + protected static final String VEHICLE_ATTRIBUTE = "vehicle"; + + private final String mode; + private final Id vehicleId; + + protected AbstractFleetEvent(double time, String mode, Id vehicleId) { + super(time); + this.mode = mode; + this.vehicleId = vehicleId; + } + + public String getDvrpMode() { + return mode; + } + + public Id getDvrpVehicleId() { + return vehicleId; + } + + @Override + public Map getAttributes() { + Map attributes = super.getAttributes(); + attributes.put(MODE_ATTRIBUTE, mode); + attributes.put(VEHICLE_ATTRIBUTE, vehicleId.toString()); + return attributes; + } +} diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/DvrpVehicleLookup.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/DvrpVehicleLookup.java index 9948a08a606..190119db957 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/DvrpVehicleLookup.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/DvrpVehicleLookup.java @@ -20,21 +20,15 @@ package org.matsim.contrib.dvrp.fleet; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - import org.matsim.api.core.v01.Id; -import org.matsim.contrib.dvrp.run.DvrpMode; +import org.matsim.api.core.v01.IdMap; -import com.google.inject.Inject; -import com.google.inject.Injector; -import com.google.inject.Key; -import com.google.inject.Provider; +import com.google.common.base.Verify; import com.google.inject.Singleton; /** * @author Michal Maciejewski (michalm) + * @author Sebastian Hörl (sebhoerl), IRT SystemX */ @Singleton public class DvrpVehicleLookup { @@ -48,10 +42,14 @@ private VehicleAndMode(DvrpVehicle vehicle, String mode) { } } - private final Map, VehicleAndMode> vehicleLookupMap; + private final IdMap vehicleLookupMap = new IdMap<>(DvrpVehicle.class); + + void addVehicle(String mode, DvrpVehicle vehicle) { + Verify.verify(vehicleLookupMap.put(vehicle.getId(), new VehicleAndMode(vehicle, mode)) == null); + } - public DvrpVehicleLookup(Map, VehicleAndMode> vehicleLookupMap) { - this.vehicleLookupMap = vehicleLookupMap; + void removeVehicle(String mode, Id vehicleId) { + Verify.verify(vehicleLookupMap.remove(vehicleId).mode.equals(mode)); } public VehicleAndMode lookupVehicleAndMode(Id id) { @@ -62,25 +60,4 @@ public DvrpVehicle lookupVehicle(Id id) { VehicleAndMode vehicleAndMode = lookupVehicleAndMode(id); return vehicleAndMode == null ? null : vehicleAndMode.vehicle; } - - public static class DvrpVehicleLookupProvider implements Provider { - @Inject - private Injector injector; - - @Inject - private Set dvrpModes; - - @Override - public DvrpVehicleLookup get() { - Map, VehicleAndMode> vehicleLookupMap = new HashMap<>(); - for (DvrpMode m : dvrpModes) { - for (DvrpVehicle v : injector.getInstance(Key.get(Fleet.class, m)).getVehicles().values()) { - if (vehicleLookupMap.put(v.getId(), new VehicleAndMode(v, m.value())) != null) { - throw new RuntimeException("Two DvrpVehicles with the same id: " + v.getId()); - } - } - } - return new DvrpVehicleLookup(vehicleLookupMap); - } - } } diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/Fleet.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/Fleet.java index d6cfbdf6ea6..62ec869906e 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/Fleet.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/Fleet.java @@ -21,16 +21,75 @@ package org.matsim.contrib.dvrp.fleet; import org.matsim.api.core.v01.Id; - -import com.google.common.collect.ImmutableMap; +import org.matsim.api.core.v01.IdMap; +import org.matsim.core.api.experimental.events.EventsManager; +import org.matsim.core.mobsim.framework.MobsimTimer; /** - * Contains all DvrpVehicles generated for a given iteration. Its lifespan is limited to a single QSim simulation. - *

- * Fleet (ond the contained DvrpVehicles) are created from FleetSpecification (and the contained DvrpVehicleSpecifications) + * Contains all DvrpVehicles generated for a given iteration. Its lifespan is + * limited to a single QSim simulation. + * + * Fleet (and the contained DvrpVehicles) are created from FleetSpecification + * (and the contained DvrpVehicleSpecifications). + * + * Vehicles may be added and removed during the QSim simulation. * * @author michalm + * @author Sebastian Hörl (sebhoerl), IRT SystemX */ -public interface Fleet { - ImmutableMap, DvrpVehicle> getVehicles(); +public final class Fleet { + private final String mode; + + private final EventsManager eventsManager; + private final MobsimTimer timer; + + private final DvrpVehicleLookup lookup; + + private final IdMap vehicles = new IdMap<>(DvrpVehicle.class); + + public Fleet(String mode, EventsManager eventsManager, MobsimTimer timer, DvrpVehicleLookup lookup) { + this.mode = mode; + this.eventsManager = eventsManager; + this.timer = timer; + this.lookup = lookup; + } + + /** + * Adds a vehicle to the fleet. + * + * @return True if the vehicle was not already part of the fleet + */ + public boolean addVehicle(DvrpVehicle vehicle) { + boolean added = vehicles.put(vehicle.getId(), vehicle) == null; + + if (added) { + lookup.addVehicle(mode, vehicle); + eventsManager.processEvent(new VehicleAddedEvent(timer.getTimeOfDay(), mode, vehicle.getId(), vehicle.getCapacity())); + } + + return added; + } + + /** + * Removes a vehicle from the fleet. + * + * @return True if the vehicle existed in the fleet + */ + public boolean removeVehicle(Id vehicleId) { + boolean removed = vehicles.remove(vehicleId) != null; + + if (removed) { + lookup.removeVehicle(mode, vehicleId); + eventsManager.processEvent(new VehicleRemovedEvent(timer.getTimeOfDay(), mode, vehicleId)); + } + + return removed; + } + + /** + * Returns a map of vehicles for this fleet + */ + public IdMap getVehicles() { + return vehicles; + } } diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/FleetCreator.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/FleetCreator.java new file mode 100644 index 00000000000..9467d13d797 --- /dev/null +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/FleetCreator.java @@ -0,0 +1,11 @@ +package org.matsim.contrib.dvrp.fleet; + +/** + * This interface is used to fill the DVRP Fleet at the beginning of the + * simulation. + * + * @author Sebastian Hörl (sebhoerl), IRT SystemX + */ +public interface FleetCreator { + void createFleet(Fleet fleet); +} diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/FleetExtensionHelper.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/FleetExtensionHelper.java new file mode 100644 index 00000000000..830cdcad4af --- /dev/null +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/FleetExtensionHelper.java @@ -0,0 +1,76 @@ +package org.matsim.contrib.dvrp.fleet; + +import java.util.LinkedList; +import java.util.List; + +import org.matsim.contrib.dvrp.run.AbstractDvrpModeQSimModule; +import org.matsim.contrib.dvrp.vrpagent.VrpAgentSource; +import org.matsim.contrib.dynagent.DynAgent; +import org.matsim.core.mobsim.qsim.InternalInterface; +import org.matsim.core.mobsim.qsim.interfaces.MobsimEngine; + +/** + * This is a convenience class that simplifies the process of adding VRP agents + * during the QSim. + * + * @author Sebastian Hörl (sebhoerl), IRT SystemX + */ +public class FleetExtensionHelper implements MobsimEngine { + private final VrpAgentSource source; + private final Fleet fleet; + + private InternalInterface internalInterface; + + private final List vehicles = new LinkedList<>(); + + FleetExtensionHelper(VrpAgentSource source, Fleet fleet) { + this.source = source; + this.fleet = fleet; + } + + public void addVehicle(DvrpVehicle vehicle) { + synchronized (vehicles) { + vehicles.add(vehicle); + } + } + + @Override + public void doSimStep(double time) { + synchronized (vehicles) { + for (DvrpVehicle vehicle : vehicles) { + DynAgent agent = source.addVehicle(vehicle); + fleet.addVehicle(vehicle); + + internalInterface.arrangeNextAgentState(agent); + } + + vehicles.clear(); + } + } + + @Override + public void onPrepareSim() { + } + + @Override + public void afterSim() { + } + + @Override + public void setInternalInterface(InternalInterface internalInterface) { + this.internalInterface = internalInterface; + } + + static public class FleetExtensionHelperQSimModule extends AbstractDvrpModeQSimModule { + public FleetExtensionHelperQSimModule(String mode) { + super(mode); + } + + @Override + protected void configureQSim() { + bindModal(FleetExtensionHelper.class).toProvider(modalProvider(getter -> { + return new FleetExtensionHelper(getter.getModal(VrpAgentSource.class), getter.getModal(Fleet.class)); + })).asEagerSingleton(); + } + } +} diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/FleetModule.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/FleetModule.java index 2a49ab78f37..72b862f262f 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/FleetModule.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/FleetModule.java @@ -26,7 +26,9 @@ import org.matsim.contrib.dvrp.analysis.ExecutedScheduleCollector; import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; import org.matsim.contrib.dvrp.run.AbstractDvrpModeQSimModule; +import org.matsim.core.api.experimental.events.EventsManager; import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.mobsim.framework.MobsimTimer; import org.matsim.vehicles.VehicleType; import org.matsim.vehicles.VehicleUtils; import org.matsim.vehicles.Vehicles; @@ -92,9 +94,23 @@ public FleetSpecification get() { installQSimModule(new AbstractDvrpModeQSimModule(getMode()) { @Override protected void configureQSim() { - bindModal(Fleet.class).toProvider(modalProvider( + bindModal(FleetCreator.class).toProvider(modalProvider( getter -> Fleets.createDefaultFleet(getter.getModal(FleetSpecification.class), getter.getModal(Network.class).getLinks()::get))).asEagerSingleton(); + + bindModal(Fleet.class).toProvider(modalProvider(getter -> { + EventsManager eventsManager = getter.get(EventsManager.class); + MobsimTimer mobsimTimer = getter.get(MobsimTimer.class); + DvrpVehicleLookup lookup = getter.get(DvrpVehicleLookup.class); + + Fleet fleet = new Fleet(getMode(), eventsManager, mobsimTimer, lookup); + + // use the FleetCreator to initialize the vehicles in Fleet + FleetCreator fleetCreator = getter.getModal(FleetCreator.class); + fleetCreator.createFleet(fleet); + + return fleet; + })).asEagerSingleton(); } }); diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/Fleets.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/Fleets.java index 8e1f29a16d7..7700daf52ba 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/Fleets.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/Fleets.java @@ -25,25 +25,24 @@ import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; -import com.google.common.collect.ImmutableMap; - /** * @author michalm + * @author Sebastian Hörl (sebhoerl), IRT SystemX */ public class Fleets { - public static Fleet createDefaultFleet(FleetSpecification fleetSpecification, + public static FleetCreator createDefaultFleet(FleetSpecification fleetSpecification, Function, Link> linkProvider) { return createCustomFleet(fleetSpecification, s -> new DvrpVehicleImpl(s, linkProvider.apply(s.getStartLinkId()))); } - public static Fleet createCustomFleet(FleetSpecification fleetSpecification, + public static FleetCreator createCustomFleet(FleetSpecification fleetSpecification, Function vehicleCreator) { - ImmutableMap, DvrpVehicle> vehicles = fleetSpecification.getVehicleSpecifications() - .values() - .stream() - .map(vehicleCreator) - .collect(ImmutableMap.toImmutableMap(DvrpVehicle::getId, v -> v)); - return () -> vehicles; + return fleet -> { + fleetSpecification.getVehicleSpecifications() // + .values().stream() // + .map(vehicleCreator) // + .forEach(fleet::addVehicle); + }; } } diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/VehicleAddedEvent.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/VehicleAddedEvent.java new file mode 100644 index 00000000000..5569b98bd93 --- /dev/null +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/VehicleAddedEvent.java @@ -0,0 +1,38 @@ +package org.matsim.contrib.dvrp.fleet; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.events.GenericEvent; + +/** + * Event fired when a vehicle is added to a DVRP fleet + * + * @author Sebastian Hörl (sebhoerl), IRT SystemX + */ +public class VehicleAddedEvent extends AbstractFleetEvent { + static public final String EVENT_NAME = "dvrp vehicle added"; + + static public final String CAPACITY_ATTRIBUTE = "capacity"; + + private final int capacity; + + protected VehicleAddedEvent(double time, String mode, Id vehicleId, int capacity) { + super(time, mode, vehicleId); + this.capacity = capacity; + } + + public int getCapacity() { + return capacity; + } + + @Override + public String getEventType() { + return EVENT_NAME; + } + + static public VehicleAddedEvent convert(GenericEvent event) { + return new VehicleAddedEvent(event.getTime(), // + event.getAttributes().get(MODE_ATTRIBUTE), // + Id.create(event.getAttributes().get(VEHICLE_ATTRIBUTE), DvrpVehicle.class), // + Integer.parseInt(event.getAttributes().get(CAPACITY_ATTRIBUTE))); + } +} diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/VehicleAddedEventHandler.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/VehicleAddedEventHandler.java new file mode 100644 index 00000000000..2a5bf309c59 --- /dev/null +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/VehicleAddedEventHandler.java @@ -0,0 +1,10 @@ +package org.matsim.contrib.dvrp.fleet; + +import org.matsim.core.events.handler.EventHandler; + +/** + * @author Sebastian Hörl (sebhoerl), IRT Systemx + */ +public interface VehicleAddedEventHandler extends EventHandler { + void handleEvent(VehicleAddedEvent event); +} diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/VehicleRemovedEvent.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/VehicleRemovedEvent.java new file mode 100644 index 00000000000..9f52b48a74f --- /dev/null +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/VehicleRemovedEvent.java @@ -0,0 +1,28 @@ +package org.matsim.contrib.dvrp.fleet; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.events.GenericEvent; + +/** + * Event fired when a vehicle is removed from a DVRP fleet + * + * @author Sebastian Hörl (sebhoerl), IRT SystemX + */ +public class VehicleRemovedEvent extends AbstractFleetEvent { + static public final String EVENT_NAME = "dvrp vehicle removed"; + + protected VehicleRemovedEvent(double time, String mode, Id vehicleId) { + super(time, mode, vehicleId); + } + + @Override + public String getEventType() { + return EVENT_NAME; + } + + static public VehicleRemovedEvent convert(GenericEvent event) { + return new VehicleRemovedEvent(event.getTime(), // + event.getAttributes().get(MODE_ATTRIBUTE), // + Id.create(event.getAttributes().get(VEHICLE_ATTRIBUTE), DvrpVehicle.class)); + } +} diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/VehicleRemovedEventHandler.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/VehicleRemovedEventHandler.java new file mode 100644 index 00000000000..4b5afb3a274 --- /dev/null +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/VehicleRemovedEventHandler.java @@ -0,0 +1,10 @@ +package org.matsim.contrib.dvrp.fleet; + +import org.matsim.core.events.handler.EventHandler; + +/** + * @author Sebastian Hörl (sebhoerl), IRT Systemx + */ +public interface VehicleRemovedEventHandler extends EventHandler { + void handleEvent(VehicleRemovedEvent event); +} diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/VehicleStartLinkToLastLinkUpdater.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/VehicleStartLinkToLastLinkUpdater.java index df3d201b288..cce4a64813e 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/VehicleStartLinkToLastLinkUpdater.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/fleet/VehicleStartLinkToLastLinkUpdater.java @@ -43,11 +43,14 @@ public VehicleStartLinkToLastLinkUpdater(FleetSpecification fleetSpecification, public void notifyIterationEnds(IterationEndsEvent event) { executedScheduleCollector.getExecutedSchedules().forEach(schedule -> { var currentSpecification = fleetSpecification.getVehicleSpecifications().get(schedule.vehicleId); - var tasks = schedule.getExecutedTasks(); - var updatedSpecification = ImmutableDvrpVehicleSpecification.newBuilder(currentSpecification) - .startLinkId(tasks.get(tasks.size() - 1).endLinkId) // update start link to last link - .build(); - fleetSpecification.replaceVehicleSpecification(updatedSpecification); + + if (currentSpecification != null) { + var tasks = schedule.getExecutedTasks(); + var updatedSpecification = ImmutableDvrpVehicleSpecification.newBuilder(currentSpecification) + .startLinkId(tasks.get(tasks.size() - 1).endLinkId) // update start link to last link + .build(); + fleetSpecification.replaceVehicleSpecification(updatedSpecification); + } }); } } diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/run/DvrpModule.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/run/DvrpModule.java index 536f9315c82..66397b12269 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/run/DvrpModule.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/run/DvrpModule.java @@ -98,8 +98,7 @@ public TravelTimeMatrix get() { protected void configureQSim() { addQSimComponentBinding(DynActivityEngine.COMPONENT_NAME).to(DynActivityEngine.class); bind(MobsimTimer.class).toProvider(MobsimTimerProvider.class).asEagerSingleton(); - bind(DvrpVehicleLookup.class).toProvider(DvrpVehicleLookup.DvrpVehicleLookupProvider.class) - .asEagerSingleton(); + bind(DvrpVehicleLookup.class); } }); 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 093071c7f08..e4ad068ad0c 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 @@ -23,6 +23,8 @@ import java.util.Map; import java.util.function.Function; +import org.matsim.contrib.dvrp.fleet.VehicleAddedEvent; +import org.matsim.contrib.dvrp.fleet.VehicleRemovedEvent; import org.matsim.contrib.dvrp.passenger.PassengerDroppedOffEvent; import org.matsim.contrib.dvrp.passenger.PassengerPickedUpEvent; import org.matsim.contrib.dvrp.passenger.PassengerRequestRejectedEvent; @@ -45,8 +47,10 @@ public static Map createCustomEven PassengerWaitingEvent.EVENT_TYPE, PassengerWaitingEvent::convert,// PassengerPickedUpEvent.EVENT_TYPE, PassengerPickedUpEvent::convert, // PassengerDroppedOffEvent.EVENT_TYPE, PassengerDroppedOffEvent::convert,// - TaskStartedEvent.EVENT_TYPE, e -> TaskStartedEvent.convert(e, stringToTaskTypeConverter), - TaskEndedEvent.EVENT_TYPE, e -> TaskEndedEvent.convert(e, stringToTaskTypeConverter)); + TaskStartedEvent.EVENT_TYPE, e -> TaskStartedEvent.convert(e, stringToTaskTypeConverter),// + TaskEndedEvent.EVENT_TYPE, e -> TaskEndedEvent.convert(e, stringToTaskTypeConverter), // + VehicleAddedEvent.EVENT_NAME, VehicleAddedEvent::convert,// + VehicleRemovedEvent.EVENT_NAME, VehicleRemovedEvent::convert); } public static MatsimEventsReader createEventsReader(EventsManager eventsManager, diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/vrpagent/VrpAgentSource.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/vrpagent/VrpAgentSource.java index b5ab8b34fa3..eb53e9c3d38 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/vrpagent/VrpAgentSource.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/vrpagent/VrpAgentSource.java @@ -41,6 +41,7 @@ public class VrpAgentSource implements AgentSource { private final String dvrpMode; private final QSim qSim; private final VehicleType vehicleType; + private final VehiclesFactory vehicleFactory; public VrpAgentSource(DynActionCreator nextActionCreator, Fleet fleet, VrpOptimizer optimizer, String dvrpMode, QSim qSim, VehicleType vehicleType) { @@ -50,29 +51,34 @@ public VrpAgentSource(DynActionCreator nextActionCreator, Fleet fleet, VrpOptimi this.dvrpMode = dvrpMode; this.qSim = qSim; this.vehicleType = vehicleType; + this.vehicleFactory = this.qSim.getScenario().getVehicles().getFactory(); } @Override public void insertAgentsIntoMobsim() { - VehiclesFactory vehicleFactory = this.qSim.getScenario().getVehicles().getFactory(); - for (DvrpVehicle dvrpVehicle : fleet.getVehicles().values()) { - Id id = dvrpVehicle.getId(); - Id startLinkId = dvrpVehicle.getStartLink().getId(); + addVehicle(dvrpVehicle); + } + } + + public DynAgent addVehicle(DvrpVehicle dvrpVehicle) { + Id id = dvrpVehicle.getId(); + Id startLinkId = dvrpVehicle.getStartLink().getId(); - VrpAgentLogic vrpAgentLogic = new VrpAgentLogic(optimizer, nextActionCreator, dvrpVehicle, dvrpMode, - qSim.getEventsManager()); - DynAgent vrpAgent = new DynAgent(Id.createPersonId(id), startLinkId, qSim.getEventsManager(), - vrpAgentLogic); - Vehicle matsimVehicle = dvrpVehicle.getSpecification() - .getMatsimVehicle() - .orElse(vehicleFactory.createVehicle(Id.create(id, Vehicle.class), vehicleType)); - QVehicle mobsimVehicle = new QVehicleImpl(matsimVehicle); - vrpAgent.setVehicle(mobsimVehicle); - mobsimVehicle.setDriver(vrpAgent); + VrpAgentLogic vrpAgentLogic = new VrpAgentLogic(optimizer, nextActionCreator, dvrpVehicle, dvrpMode, + qSim.getEventsManager()); + DynAgent vrpAgent = new DynAgent(Id.createPersonId(id), startLinkId, qSim.getEventsManager(), + vrpAgentLogic); + Vehicle matsimVehicle = dvrpVehicle.getSpecification() + .getMatsimVehicle() + .orElse(vehicleFactory.createVehicle(Id.create(id, Vehicle.class), vehicleType)); + QVehicle mobsimVehicle = new QVehicleImpl(matsimVehicle); + vrpAgent.setVehicle(mobsimVehicle); + mobsimVehicle.setDriver(vrpAgent); - qSim.addParkedVehicle(mobsimVehicle, startLinkId); - qSim.insertAgentIntoMobsim(vrpAgent); - } + qSim.addParkedVehicle(mobsimVehicle, startLinkId); + qSim.insertAgentIntoMobsim(vrpAgent); + + return vrpAgent; } } diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/vrpagent/VrpAgentSourceQSimModule.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/vrpagent/VrpAgentSourceQSimModule.java index 4a8ef6a8026..f331ba61c23 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/vrpagent/VrpAgentSourceQSimModule.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/vrpagent/VrpAgentSourceQSimModule.java @@ -23,13 +23,9 @@ import org.matsim.contrib.dvrp.fleet.Fleet; import org.matsim.contrib.dvrp.optimizer.VrpOptimizer; import org.matsim.contrib.dvrp.run.AbstractDvrpModeQSimModule; -import org.matsim.contrib.dvrp.run.DvrpModes; import org.matsim.core.mobsim.qsim.QSim; -import org.matsim.core.modal.ModalProviders; import org.matsim.vehicles.VehicleType; -import com.google.inject.Inject; - public class VrpAgentSourceQSimModule extends AbstractDvrpModeQSimModule { public VrpAgentSourceQSimModule(String mode) { super(mode); @@ -37,16 +33,12 @@ public VrpAgentSourceQSimModule(String mode) { @Override protected void configureQSim() { - addModalComponent(VrpAgentSource.class, new ModalProviders.AbstractProvider<>(getMode(), DvrpModes::mode) { - @Inject - private QSim qSim; - - @Override - public VrpAgentSource get() { - return new VrpAgentSource(getModalInstance(VrpAgentLogic.DynActionCreator.class), - getModalInstance(Fleet.class), getModalInstance(VrpOptimizer.class), getMode(), qSim, - getModalInstance(VehicleType.class)); - } - }); + bindModal(VrpAgentSource.class).toProvider(modalProvider(getter -> { + return new VrpAgentSource(getter.getModal(VrpAgentLogic.DynActionCreator.class), + getter.getModal(Fleet.class), getter.getModal(VrpOptimizer.class), getMode(), getter.get(QSim.class), + getter.getModal(VehicleType.class)); + })); + + addModalQSimComponentBinding().to(modalKey(VrpAgentSource.class)); } } diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/evrp/EvDvrpFleetQSimModule.java b/contribs/dvrp/src/main/java/org/matsim/contrib/evrp/EvDvrpFleetQSimModule.java index c6096e6d38a..f58a321c61d 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/evrp/EvDvrpFleetQSimModule.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/evrp/EvDvrpFleetQSimModule.java @@ -22,13 +22,13 @@ import org.matsim.api.core.v01.network.Network; import org.matsim.contrib.dvrp.fleet.DvrpVehicleImpl; -import org.matsim.contrib.dvrp.fleet.Fleet; +import org.matsim.contrib.dvrp.fleet.FleetCreator; import org.matsim.contrib.dvrp.fleet.FleetSpecification; import org.matsim.contrib.dvrp.fleet.Fleets; import org.matsim.contrib.dvrp.run.AbstractDvrpModeQSimModule; import org.matsim.contrib.dvrp.run.DvrpModes; -import org.matsim.core.modal.ModalProviders; import org.matsim.contrib.ev.fleet.ElectricFleet; +import org.matsim.core.modal.ModalProviders; import com.google.inject.Inject; @@ -42,12 +42,12 @@ public EvDvrpFleetQSimModule(String mode) { @Override public void configureQSim() { - bindModal(Fleet.class).toProvider(new ModalProviders.AbstractProvider<>(getMode(), DvrpModes::mode) { + bindModal(FleetCreator.class).toProvider(new ModalProviders.AbstractProvider<>(getMode(), DvrpModes::mode) { @Inject private ElectricFleet evFleet; @Override - public Fleet get() { + public FleetCreator get() { FleetSpecification fleetSpecification = getModalInstance(FleetSpecification.class); Network network = getModalInstance(Network.class); return Fleets.createCustomFleet(fleetSpecification, diff --git a/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/passenger/DefaultPassengerEngineTest.java b/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/passenger/DefaultPassengerEngineTest.java index 97579d14517..a3e35c86af3 100644 --- a/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/passenger/DefaultPassengerEngineTest.java +++ b/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/passenger/DefaultPassengerEngineTest.java @@ -20,13 +20,17 @@ package org.matsim.contrib.dvrp.passenger; -import static org.matsim.contrib.dvrp.passenger.PassengerEngineTestFixture.*; +import static org.matsim.contrib.dvrp.passenger.PassengerEngineTestFixture.END_ACTIVITY; +import static org.matsim.contrib.dvrp.passenger.PassengerEngineTestFixture.MODE; +import static org.matsim.contrib.dvrp.passenger.PassengerEngineTestFixture.START_ACTIVITY; import java.util.Collections; import java.util.List; import java.util.Set; + import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.IdMap; import org.matsim.api.core.v01.events.ActivityEndEvent; import org.matsim.api.core.v01.events.ActivityStartEvent; import org.matsim.api.core.v01.events.PersonArrivalEvent; @@ -38,9 +42,9 @@ import org.matsim.contrib.dvrp.examples.onetaxi.OneTaxiActionCreator; import org.matsim.contrib.dvrp.examples.onetaxi.OneTaxiOptimizer; import org.matsim.contrib.dvrp.examples.onetaxi.OneTaxiRequest; +import org.matsim.contrib.dvrp.fleet.Fleet; import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.contrib.dvrp.fleet.DvrpVehicleImpl; -import org.matsim.contrib.dvrp.fleet.Fleet; import org.matsim.contrib.dvrp.fleet.ImmutableDvrpVehicleSpecification; import org.matsim.contrib.dvrp.optimizer.Request; import org.matsim.contrib.dvrp.optimizer.VrpOptimizer; @@ -58,8 +62,8 @@ import org.matsim.core.mobsim.qsim.QSimBuilder; import org.matsim.vehicles.VehicleType; import org.matsim.vehicles.VehicleUtils; +import org.mockito.Mockito; -import com.google.common.collect.ImmutableMap; import com.google.inject.Inject; /** @@ -76,7 +80,17 @@ public class DefaultPassengerEngineTest { .startLinkId(fixture.linkAB.getId()) .capacity(1) .build(), fixture.linkAB); - private final Fleet fleet = () -> ImmutableMap.of(oneTaxi.getId(), oneTaxi); + + private final Fleet fleet = createFleet(); + private Fleet createFleet() { + IdMap vehicles = new IdMap<>(DvrpVehicle.class); + vehicles.put(oneTaxi.getId(), oneTaxi); + + Fleet fleet = Mockito.mock(Fleet.class); + Mockito.when(fleet.getVehicles()).thenReturn(vehicles); + + return fleet; + } @Test void test_valid_served() { diff --git a/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/passenger/PassengerGroupTest.java b/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/passenger/PassengerGroupTest.java index 61a9804b4bf..386cb681963 100644 --- a/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/passenger/PassengerGroupTest.java +++ b/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/passenger/PassengerGroupTest.java @@ -1,18 +1,30 @@ package org.matsim.contrib.dvrp.passenger; -import com.google.common.collect.ImmutableMap; -import org.apache.commons.compress.utils.Sets; +import static org.matsim.contrib.dvrp.passenger.PassengerEngineTestFixture.END_ACTIVITY; +import static org.matsim.contrib.dvrp.passenger.PassengerEngineTestFixture.MODE; +import static org.matsim.contrib.dvrp.passenger.PassengerEngineTestFixture.START_ACTIVITY; + +import java.util.List; +import java.util.Optional; +import java.util.Set; + import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Id; -import org.matsim.api.core.v01.events.*; +import org.matsim.api.core.v01.IdMap; +import org.matsim.api.core.v01.events.ActivityEndEvent; +import org.matsim.api.core.v01.events.ActivityStartEvent; +import org.matsim.api.core.v01.events.PersonArrivalEvent; +import org.matsim.api.core.v01.events.PersonDepartureEvent; +import org.matsim.api.core.v01.events.PersonEntersVehicleEvent; +import org.matsim.api.core.v01.events.PersonLeavesVehicleEvent; import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.population.Person; import org.matsim.contrib.dvrp.examples.onetaxi.OneTaxiActionCreator; import org.matsim.contrib.dvrp.examples.onetaxi.OneTaxiOptimizer; import org.matsim.contrib.dvrp.examples.onetaxi.OneTaxiRequest; +import org.matsim.contrib.dvrp.fleet.Fleet; import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.contrib.dvrp.fleet.DvrpVehicleImpl; -import org.matsim.contrib.dvrp.fleet.Fleet; import org.matsim.contrib.dvrp.fleet.ImmutableDvrpVehicleSpecification; import org.matsim.contrib.dvrp.optimizer.Request; import org.matsim.contrib.dvrp.optimizer.VrpOptimizer; @@ -28,12 +40,7 @@ import org.matsim.core.mobsim.qsim.QSimBuilder; import org.matsim.vehicles.VehicleType; import org.matsim.vehicles.VehicleUtils; - -import java.util.List; -import java.util.Optional; -import java.util.Set; - -import static org.matsim.contrib.dvrp.passenger.PassengerEngineTestFixture.*; +import org.mockito.Mockito; /** * @author nkuehnel / MOIA @@ -50,7 +57,17 @@ public class PassengerGroupTest { .startLinkId(fixture.linkAB.getId()) .capacity(1) .build(), fixture.linkAB); - private final Fleet fleet = () -> ImmutableMap.of(oneTaxi.getId(), oneTaxi); + + private final Fleet fleet = createFleet(); + private Fleet createFleet() { + IdMap vehicles = new IdMap<>(DvrpVehicle.class); + vehicles.put(oneTaxi.getId(), oneTaxi); + + Fleet fleet = Mockito.mock(Fleet.class); + Mockito.when(fleet.getVehicles()).thenReturn(vehicles); + + return fleet; + } @Test void test_group() { diff --git a/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/router/DiversionTest.java b/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/router/DiversionTest.java index 2aa72304e53..8d4acb9ed11 100644 --- a/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/router/DiversionTest.java +++ b/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/router/DiversionTest.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; + import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Coord; @@ -16,8 +17,10 @@ import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.network.NetworkFactory; import org.matsim.api.core.v01.network.Node; -import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.contrib.dvrp.fleet.Fleet; +import org.matsim.contrib.dvrp.fleet.DvrpVehicle; +import org.matsim.contrib.dvrp.fleet.FleetCreator; +import org.matsim.contrib.dvrp.fleet.FleetModule; import org.matsim.contrib.dvrp.fleet.FleetSpecification; import org.matsim.contrib.dvrp.fleet.FleetSpecificationImpl; import org.matsim.contrib.dvrp.fleet.Fleets; @@ -187,6 +190,7 @@ void testRepeatedSameDestinationDiversions() { // Add bindings for test case controller.addOverridingModule(new TestModeModule(testTracker)); + controller.addOverridingModule(new FleetModule(MODE, null)); controller.addOverridingQSimModule(new TestModeQSimModule(fleetSpecification, testTracker)); controller.addOverridingQSimModule(new AbstractDvrpModeQSimModule(MODE) { @@ -283,12 +287,10 @@ protected void configureQSim() { /* * Bind the fleet and agent source */ - bindModal(Fleet.class).toProvider(modalProvider(getter -> { + bindModal(FleetCreator.class).toProvider(modalProvider(getter -> { return Fleets.createDefaultFleet(fleetSpecification, getter.getModal(Network.class).getLinks()::get); })).in(Singleton.class); - bindModal(VehicleType.class).toInstance(VehicleUtils.getDefaultVehicleType()); - install(new VrpAgentSourceQSimModule(getMode())); /* @@ -514,6 +516,7 @@ void testRepeatedDiversionToDifferentDestinationRightBeforeLastLink() { // Add bindings for test case controller.addOverridingModule(new TestModeModule(testTracker)); + controller.addOverridingModule(new FleetModule(MODE, null)); controller.addOverridingQSimModule(new TestModeQSimModule(fleetSpecification, testTracker)); controller.addOverridingQSimModule(new AbstractDvrpModeQSimModule(MODE) { diff --git a/contribs/taxi/test/input/org/matsim/contrib/etaxi/run/RunETaxiScenarioIT/testAssignment/output_events.xml.gz b/contribs/taxi/test/input/org/matsim/contrib/etaxi/run/RunETaxiScenarioIT/testAssignment/output_events.xml.gz index 625f9d0073a..0917a0cae6c 100644 Binary files a/contribs/taxi/test/input/org/matsim/contrib/etaxi/run/RunETaxiScenarioIT/testAssignment/output_events.xml.gz and b/contribs/taxi/test/input/org/matsim/contrib/etaxi/run/RunETaxiScenarioIT/testAssignment/output_events.xml.gz differ diff --git a/contribs/taxi/test/input/org/matsim/contrib/etaxi/run/RunETaxiScenarioIT/testOneTaxi/output_events.xml.gz b/contribs/taxi/test/input/org/matsim/contrib/etaxi/run/RunETaxiScenarioIT/testOneTaxi/output_events.xml.gz index 0afe8ff3430..7c73cd07e8b 100644 Binary files a/contribs/taxi/test/input/org/matsim/contrib/etaxi/run/RunETaxiScenarioIT/testOneTaxi/output_events.xml.gz and b/contribs/taxi/test/input/org/matsim/contrib/etaxi/run/RunETaxiScenarioIT/testOneTaxi/output_events.xml.gz differ diff --git a/contribs/taxi/test/input/org/matsim/contrib/etaxi/run/RunETaxiScenarioIT/testRuleBased/output_events.xml.gz b/contribs/taxi/test/input/org/matsim/contrib/etaxi/run/RunETaxiScenarioIT/testRuleBased/output_events.xml.gz index 625f9d0073a..0917a0cae6c 100644 Binary files a/contribs/taxi/test/input/org/matsim/contrib/etaxi/run/RunETaxiScenarioIT/testRuleBased/output_events.xml.gz and b/contribs/taxi/test/input/org/matsim/contrib/etaxi/run/RunETaxiScenarioIT/testRuleBased/output_events.xml.gz differ diff --git a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/assignment/AssignmentTaxiOptimizerIT/testAssignment_arrivalTime/output_events.xml.gz b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/assignment/AssignmentTaxiOptimizerIT/testAssignment_arrivalTime/output_events.xml.gz index 19b00860f2b..c2e1fc196a0 100644 Binary files a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/assignment/AssignmentTaxiOptimizerIT/testAssignment_arrivalTime/output_events.xml.gz and b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/assignment/AssignmentTaxiOptimizerIT/testAssignment_arrivalTime/output_events.xml.gz differ diff --git a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/assignment/AssignmentTaxiOptimizerIT/testAssignment_dse/output_events.xml.gz b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/assignment/AssignmentTaxiOptimizerIT/testAssignment_dse/output_events.xml.gz index 5d175bd18a1..05484003fd2 100644 Binary files a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/assignment/AssignmentTaxiOptimizerIT/testAssignment_dse/output_events.xml.gz and b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/assignment/AssignmentTaxiOptimizerIT/testAssignment_dse/output_events.xml.gz differ diff --git a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/assignment/AssignmentTaxiOptimizerIT/testAssignment_pickupTime/output_events.xml.gz b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/assignment/AssignmentTaxiOptimizerIT/testAssignment_pickupTime/output_events.xml.gz index 3e864de13a2..93800863af4 100644 Binary files a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/assignment/AssignmentTaxiOptimizerIT/testAssignment_pickupTime/output_events.xml.gz and b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/assignment/AssignmentTaxiOptimizerIT/testAssignment_pickupTime/output_events.xml.gz differ diff --git a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/assignment/AssignmentTaxiOptimizerIT/testAssignment_totalWaitTime/output_events.xml.gz b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/assignment/AssignmentTaxiOptimizerIT/testAssignment_totalWaitTime/output_events.xml.gz index 79c4783b2aa..a367ccfeded 100644 Binary files a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/assignment/AssignmentTaxiOptimizerIT/testAssignment_totalWaitTime/output_events.xml.gz and b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/assignment/AssignmentTaxiOptimizerIT/testAssignment_totalWaitTime/output_events.xml.gz differ diff --git a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/fifo/FifoTaxiOptimizerIT/testFifo/output_events.xml.gz b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/fifo/FifoTaxiOptimizerIT/testFifo/output_events.xml.gz index 60e5b2237a1..55c19031d4e 100644 Binary files a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/fifo/FifoTaxiOptimizerIT/testFifo/output_events.xml.gz and b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/fifo/FifoTaxiOptimizerIT/testFifo/output_events.xml.gz differ diff --git a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/rules/RuleBasedTaxiOptimizerIT/testRuleBased_dse/output_events.xml.gz b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/rules/RuleBasedTaxiOptimizerIT/testRuleBased_dse/output_events.xml.gz index 236b8d57ddd..8a2e2245312 100644 Binary files a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/rules/RuleBasedTaxiOptimizerIT/testRuleBased_dse/output_events.xml.gz and b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/rules/RuleBasedTaxiOptimizerIT/testRuleBased_dse/output_events.xml.gz differ diff --git a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/rules/RuleBasedTaxiOptimizerIT/testRuleBased_minPickupTime/output_events.xml.gz b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/rules/RuleBasedTaxiOptimizerIT/testRuleBased_minPickupTime/output_events.xml.gz index dc301f3138d..d45235d44da 100644 Binary files a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/rules/RuleBasedTaxiOptimizerIT/testRuleBased_minPickupTime/output_events.xml.gz and b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/rules/RuleBasedTaxiOptimizerIT/testRuleBased_minPickupTime/output_events.xml.gz differ diff --git a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/rules/RuleBasedTaxiOptimizerIT/testRuleBased_minWaitTime/output_events.xml.gz b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/rules/RuleBasedTaxiOptimizerIT/testRuleBased_minWaitTime/output_events.xml.gz index d99a059ff9d..7cb212a0d02 100644 Binary files a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/rules/RuleBasedTaxiOptimizerIT/testRuleBased_minWaitTime/output_events.xml.gz and b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/rules/RuleBasedTaxiOptimizerIT/testRuleBased_minWaitTime/output_events.xml.gz differ diff --git a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/zonal/ZonalTaxiOptimizerIT/testZonal_dse/output_events.xml.gz b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/zonal/ZonalTaxiOptimizerIT/testZonal_dse/output_events.xml.gz index 104bfcba196..5c9ac5c41c9 100644 Binary files a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/zonal/ZonalTaxiOptimizerIT/testZonal_dse/output_events.xml.gz and b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/zonal/ZonalTaxiOptimizerIT/testZonal_dse/output_events.xml.gz differ diff --git a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/zonal/ZonalTaxiOptimizerIT/testZonal_minWaitTime/output_events.xml.gz b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/zonal/ZonalTaxiOptimizerIT/testZonal_minWaitTime/output_events.xml.gz index c8863d97633..0e2895e47db 100644 Binary files a/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/zonal/ZonalTaxiOptimizerIT/testZonal_minWaitTime/output_events.xml.gz and b/contribs/taxi/test/input/org/matsim/contrib/taxi/optimizer/zonal/ZonalTaxiOptimizerIT/testZonal_minWaitTime/output_events.xml.gz differ