diff --git a/src/main/java/org/matsim/run/OpenBerlinParkingScenario.java b/src/main/java/org/matsim/run/OpenBerlinParkingScenario.java index 39d262612..a1e7305b6 100644 --- a/src/main/java/org/matsim/run/OpenBerlinParkingScenario.java +++ b/src/main/java/org/matsim/run/OpenBerlinParkingScenario.java @@ -1,9 +1,8 @@ package org.matsim.run; import org.matsim.core.config.Config; -import org.matsim.core.controler.AbstractModule; import org.matsim.core.controler.Controler; -import org.matsim.run.scoring.parking.*; +import org.matsim.run.scoring.parking.ParkingModule; /** @@ -26,14 +25,6 @@ protected Config prepareConfig(Config config) { @Override protected void prepareControler(Controler controler) { super.prepareControler(controler); - - controler.addOverridingModule(new AbstractModule() { - @Override - public void install() { - bind(KernelFunction.class).to(ConstantKernelFunction.class); - bind(PenaltyFunction.class).toInstance(new BellochePenaltyFunction(0.4, -6)); - addEventHandlerBinding().to(ParkingObserver.class); - } - }); + controler.addOverridingModule(new ParkingModule()); } } diff --git a/src/main/java/org/matsim/run/scoring/parking/EventBasedParkingCapacityInitializer.java b/src/main/java/org/matsim/run/scoring/parking/EventBasedParkingCapacityInitializer.java new file mode 100644 index 000000000..f9914e417 --- /dev/null +++ b/src/main/java/org/matsim/run/scoring/parking/EventBasedParkingCapacityInitializer.java @@ -0,0 +1,45 @@ +package org.matsim.run.scoring.parking; + +import com.google.inject.Inject; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.events.VehicleEntersTrafficEvent; +import org.matsim.api.core.v01.events.VehicleLeavesTrafficEvent; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.api.core.v01.population.Person; + +import java.util.*; +import java.util.stream.Collectors; + +import static org.matsim.run.scoring.parking.ParkingObserver.LINK_OFF_STREET_SPOTS; +import static org.matsim.run.scoring.parking.ParkingObserver.LINK_ON_STREET_SPOTS; + +public class EventBasedParkingCapacityInitializer implements ParkingCapacityInitializer { + @Inject + private Network network; + + @Override + public Map, ParkingInitialCapacity> initialize(List vehicleEntersTrafficEvents, List vehicleLeavesTrafficEvents) { + Map, Long> initialParkingByPlans = getInitialParkingByPlans(vehicleEntersTrafficEvents); + + Map, ParkingInitialCapacity> res = new HashMap<>(network.getLinks().size()); + for (Link link : network.getLinks().values()) { + int onStreet = (int) Optional.ofNullable(link.getAttributes().getAttribute(LINK_ON_STREET_SPOTS)).orElse(0); + int offStreet = (int) Optional.ofNullable(link.getAttributes().getAttribute(LINK_OFF_STREET_SPOTS)).orElse(0); + + int initialParking = initialParkingByPlans.getOrDefault(link.getId(), 0L).intValue(); + res.put(link.getId(), new ParkingInitialCapacity(onStreet + offStreet, initialParking)); + } + return res; + } + + // Returns the number of parking spots on the link where the first car trip starts + private Map, Long> getInitialParkingByPlans(List vehicleEntersTrafficEvents) { + + + Set> visitedPerson = new HashSet<>(); + return vehicleEntersTrafficEvents.stream() + .filter(e -> visitedPerson.add(e.getPersonId())) + .collect(Collectors.groupingBy(VehicleEntersTrafficEvent::getLinkId, Collectors.counting())); + } +} diff --git a/src/main/java/org/matsim/run/scoring/parking/ParkingCapacityInitializer.java b/src/main/java/org/matsim/run/scoring/parking/ParkingCapacityInitializer.java index 6877934f1..84e44d396 100644 --- a/src/main/java/org/matsim/run/scoring/parking/ParkingCapacityInitializer.java +++ b/src/main/java/org/matsim/run/scoring/parking/ParkingCapacityInitializer.java @@ -1,13 +1,16 @@ package org.matsim.run.scoring.parking; import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.events.VehicleEntersTrafficEvent; +import org.matsim.api.core.v01.events.VehicleLeavesTrafficEvent; import org.matsim.api.core.v01.network.Link; +import java.util.List; import java.util.Map; public interface ParkingCapacityInitializer { - Map, InitialParkingCapacity> initialize(); + Map, ParkingInitialCapacity> initialize(List vehicleEntersTrafficEvents, List vehicleLeavesTrafficEvents); - record InitialParkingCapacity(int capacity, int initial) { + record ParkingInitialCapacity(int capacity, int initial) { } } diff --git a/src/main/java/org/matsim/run/scoring/parking/ParkingEventsHandler.java b/src/main/java/org/matsim/run/scoring/parking/ParkingEventsHandler.java index acac991a2..d0e9ad68e 100644 --- a/src/main/java/org/matsim/run/scoring/parking/ParkingEventsHandler.java +++ b/src/main/java/org/matsim/run/scoring/parking/ParkingEventsHandler.java @@ -1,27 +1,76 @@ package org.matsim.run.scoring.parking; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.TransportMode; import org.matsim.api.core.v01.events.TransitDriverStartsEvent; import org.matsim.api.core.v01.events.VehicleEntersTrafficEvent; import org.matsim.api.core.v01.events.VehicleLeavesTrafficEvent; import org.matsim.api.core.v01.events.handler.TransitDriverStartsEventHandler; import org.matsim.api.core.v01.events.handler.VehicleEntersTrafficEventHandler; import org.matsim.api.core.v01.events.handler.VehicleLeavesTrafficEventHandler; +import org.matsim.vehicles.Vehicle; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; public class ParkingEventsHandler implements VehicleEntersTrafficEventHandler, VehicleLeavesTrafficEventHandler, TransitDriverStartsEventHandler { - + private List vehicleEntersTrafficEvents = new ArrayList<>(); + private List vehicleLeavesTrafficEvents = new ArrayList<>(); + + private boolean locked = false; + private Set> knownPtVehicles = new HashSet<>(); @Override public void handleEvent(TransitDriverStartsEvent event) { - + checkLocked(); + knownPtVehicles.add(event.getVehicleId()); } @Override public void handleEvent(VehicleEntersTrafficEvent event) { + checkLocked(); + if (knownPtVehicles.contains(event.getVehicleId())) { + return; + } + + if (!event.getNetworkMode().equals(TransportMode.car)) { + return; + } + vehicleEntersTrafficEvents.add(event); } @Override public void handleEvent(VehicleLeavesTrafficEvent event) { + checkLocked(); + if (knownPtVehicles.contains(event.getVehicleId())) { + return; + } + + if (!event.getNetworkMode().equals(TransportMode.car)) { + return; + } + + vehicleLeavesTrafficEvents.add(event); + } + + public List getVehicleEntersTrafficEvents() { + return vehicleEntersTrafficEvents; + } + + public List getVehicleLeavesTrafficEvents() { + return vehicleLeavesTrafficEvents; + } + + public void lock() { + locked = true; + } + private void checkLocked() { + if (locked) { + throw new IllegalStateException("This handler is locked. It is expected that it is only locked after processing all events."); + } } } diff --git a/src/main/java/org/matsim/run/scoring/parking/ParkingModule.java b/src/main/java/org/matsim/run/scoring/parking/ParkingModule.java new file mode 100644 index 000000000..f9058bcc0 --- /dev/null +++ b/src/main/java/org/matsim/run/scoring/parking/ParkingModule.java @@ -0,0 +1,27 @@ +package org.matsim.run.scoring.parking; + +import com.google.inject.Singleton; +import org.matsim.core.controler.AbstractModule; +import org.matsim.modechoice.estimators.ActivityEstimator; +import org.matsim.modechoice.estimators.DefaultActivityEstimator; +import org.matsim.modechoice.estimators.DefaultLegScoreEstimator; +import org.matsim.modechoice.estimators.LegEstimator; + +public class ParkingModule extends AbstractModule { + @Override + public void install() { + // bind classes from informed mode choice explicitly + bind(ActivityEstimator.class).to(DefaultActivityEstimator.class); + bind(LegEstimator.class).to(DefaultLegScoreEstimator.class); + + // bind parking classes + bind(KernelFunction.class).to(ConstantKernelFunction.class); + bind(PenaltyFunction.class).toInstance(new BellochePenaltyFunction(0.4, -6)); + bind(ParkingCapacityInitializer.class).to(ZeroParkingCapacityInitializer.class); + + bind(ParkingObserver.class).in(Singleton.class); + bind(ParkingEventsHandler.class).in(Singleton.class); + addEventHandlerBinding().to(ParkingEventsHandler.class); + addControlerListenerBinding().to(ParkingObserver.class); + } +} diff --git a/src/main/java/org/matsim/run/scoring/parking/ParkingObserver.java b/src/main/java/org/matsim/run/scoring/parking/ParkingObserver.java index 7764223b3..2a036e080 100644 --- a/src/main/java/org/matsim/run/scoring/parking/ParkingObserver.java +++ b/src/main/java/org/matsim/run/scoring/parking/ParkingObserver.java @@ -3,36 +3,42 @@ import com.google.inject.Inject; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.events.PersonScoreEvent; -import org.matsim.api.core.v01.events.TransitDriverStartsEvent; import org.matsim.api.core.v01.events.VehicleEntersTrafficEvent; import org.matsim.api.core.v01.events.VehicleLeavesTrafficEvent; -import org.matsim.api.core.v01.events.handler.TransitDriverStartsEventHandler; -import org.matsim.api.core.v01.events.handler.VehicleEntersTrafficEventHandler; -import org.matsim.api.core.v01.events.handler.VehicleLeavesTrafficEventHandler; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.population.Person; import org.matsim.core.api.experimental.events.EventsManager; +import org.matsim.core.controler.events.AfterMobsimEvent; +import org.matsim.core.controler.listener.AfterMobsimListener; import org.matsim.modechoice.estimators.ActivityEstimator; import org.matsim.modechoice.estimators.LegEstimator; import org.matsim.vehicles.Vehicle; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; -public class ParkingObserver implements VehicleEntersTrafficEventHandler, VehicleLeavesTrafficEventHandler, TransitDriverStartsEventHandler { +public class ParkingObserver implements AfterMobsimListener { static final String LINK_ON_STREET_SPOTS = "onstreet_spots"; static final String LINK_OFF_STREET_SPOTS = "offstreet_spots"; + @Inject Network network; + @Inject KernelFunction kernelFunction; + @Inject PenaltyFunction penaltyFunction; + @Inject EventsManager eventsManager; + @Inject ActivityEstimator activityEstimator; + @Inject LegEstimator legEstimator; + @Inject + ParkingCapacityInitializer parkingCapacityInitializer; + @Inject + ParkingEventsHandler parkingEventsHandler; + //state Set> knownPtVehicles = new HashSet<>(); Map, Integer> indexByLinkId; @@ -42,56 +48,43 @@ public class ParkingObserver implements VehicleEntersTrafficEventHandler, Vehicl //TODO double kernelDistance = 500; - @Inject - public ParkingObserver(Network network, KernelFunction kernelFunction, PenaltyFunction penaltyFunction, EventsManager eventsManager, - ParkingCapacityInitializer parkingCapacityInitializer, ActivityEstimator activityEstimator, LegEstimator legEstimator) { - this.indexByLinkId = new HashMap<>(network.getLinks().size()); - this.network = network; - this.kernelFunction = kernelFunction; - this.penaltyFunction = penaltyFunction; - this.eventsManager = eventsManager; - this.activityEstimator = activityEstimator; - this.legEstimator = legEstimator; - - initCapacity(network, parkingCapacityInitializer); + @Override + public void notifyAfterMobsim(AfterMobsimEvent event) { + parkingEventsHandler.lock(); + initializeParking(); + run(); } - private void initCapacity(Network network, ParkingCapacityInitializer parkingCapacityInitializer) { - int counter = 0; - for (Id id : network.getLinks().keySet()) { - indexByLinkId.put(id, counter++); - } + private void run() { + List vehicleLeavesTrafficEvents = parkingEventsHandler.getVehicleLeavesTrafficEvents(); + List vehicleEntersTrafficEvents = parkingEventsHandler.getVehicleEntersTrafficEvents(); - int linkCount = network.getLinks().size(); - capacity = new int[linkCount]; - parkingCount = new int[linkCount]; + double maxEntersTime = vehicleEntersTrafficEvents.stream().mapToDouble(VehicleEntersTrafficEvent::getTime).max().orElse(0.0); + double maxLeavesTime = vehicleLeavesTrafficEvents.stream().mapToDouble(VehicleLeavesTrafficEvent::getTime).max().orElse(0.0); - Map, ParkingCapacityInitializer.InitialParkingCapacity> initialize = parkingCapacityInitializer.initialize(); - for (Link link : network.getLinks().values()) { - ParkingCapacityInitializer.InitialParkingCapacity initialParkingCapacity = initialize.get(link.getId()); - int index = indexByLinkId.get(link.getId()); + int indexEnterEvents = 0; + int indexLeaveEvents = 0; - capacity[index] = initialParkingCapacity.capacity(); - parkingCount[index] = initialParkingCapacity.initial(); + for (int i = 0; i <= Math.max(maxLeavesTime, maxEntersTime); i++) { + while (indexEnterEvents < vehicleEntersTrafficEvents.size() && vehicleEntersTrafficEvents.get(indexEnterEvents).getTime() == i) { + handleEvent(vehicleEntersTrafficEvents.get(indexEnterEvents++)); + } + + while (indexLeaveEvents < vehicleLeavesTrafficEvents.size() && vehicleLeavesTrafficEvents.get(indexLeaveEvents).getTime() == i) { + handleEvent(vehicleLeavesTrafficEvents.get(indexLeaveEvents++)); + } } - } - @Override - public void handleEvent(TransitDriverStartsEvent event) { - knownPtVehicles.add(event.getVehicleId()); } - @Override - public void handleEvent(VehicleEntersTrafficEvent event) { + private void handleEvent(VehicleEntersTrafficEvent event) { if (knownPtVehicles.contains(event.getVehicleId())) { return; } - unparkVehicle(event.getLinkId()); } - @Override - public void handleEvent(VehicleLeavesTrafficEvent event) { + private void handleEvent(VehicleLeavesTrafficEvent event) { if (knownPtVehicles.contains(event.getVehicleId())) { return; } @@ -130,4 +123,28 @@ private void applyPenalty(double time, Id personId, double penaltyInSec, PersonScoreEvent personScoreEvent = new PersonScoreEvent(time, personId, score, "parking"); eventsManager.processEvent(personScoreEvent); } + + private void initializeParking() { + int counter = 0; + indexByLinkId = new HashMap<>(network.getLinks().size()); + + for (Id id : network.getLinks().keySet()) { + indexByLinkId.put(id, counter++); + } + + int linkCount = network.getLinks().size(); + capacity = new int[linkCount]; + parkingCount = new int[linkCount]; + + Map, ParkingCapacityInitializer.ParkingInitialCapacity> initialize = + parkingCapacityInitializer.initialize(parkingEventsHandler.getVehicleEntersTrafficEvents(), parkingEventsHandler.getVehicleLeavesTrafficEvents()); + + for (Link link : network.getLinks().values()) { + ParkingCapacityInitializer.ParkingInitialCapacity parkingInitialCapacity = initialize.get(link.getId()); + int index = indexByLinkId.get(link.getId()); + + capacity[index] = parkingInitialCapacity.capacity(); + parkingCount[index] = parkingInitialCapacity.initial(); + } + } } diff --git a/src/main/java/org/matsim/run/scoring/parking/PlanBasedParkingCapacityInitializer.java b/src/main/java/org/matsim/run/scoring/parking/PlanBasedParkingCapacityInitializer.java deleted file mode 100644 index e06dde7e0..000000000 --- a/src/main/java/org/matsim/run/scoring/parking/PlanBasedParkingCapacityInitializer.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.matsim.run.scoring.parking; - -import com.google.inject.Inject; -import org.matsim.api.core.v01.Id; -import org.matsim.api.core.v01.TransportMode; -import org.matsim.api.core.v01.network.Link; -import org.matsim.api.core.v01.network.Network; -import org.matsim.api.core.v01.population.Population; -import org.matsim.core.router.TripStructureUtils; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -import static org.matsim.run.scoring.parking.ParkingObserver.LINK_OFF_STREET_SPOTS; -import static org.matsim.run.scoring.parking.ParkingObserver.LINK_ON_STREET_SPOTS; - -public class PlanBasedParkingCapacityInitializer implements ParkingCapacityInitializer { - private Network network; - private Population population; - - @Inject - PlanBasedParkingCapacityInitializer(Network network, Population population) { - this.network = network; - this.population = population; - } - - @Override - public Map, InitialParkingCapacity> initialize() { - Map, Long> initialParkingByPlans = getInitialParkingByPlans(); - - Map, InitialParkingCapacity> res = new HashMap<>(network.getLinks().size()); - for (Link link : network.getLinks().values()) { - int onStreet = (int) Optional.ofNullable(link.getAttributes().getAttribute(LINK_ON_STREET_SPOTS)).orElse(0); - int offStreet = (int) Optional.ofNullable(link.getAttributes().getAttribute(LINK_OFF_STREET_SPOTS)).orElse(0); - - int initialParking = initialParkingByPlans.getOrDefault(link.getId(), 0L).intValue(); - res.put(link.getId(), new InitialParkingCapacity(onStreet + offStreet, initialParking)); - } - return res; - } - - // Returns the number of parking spots on the link where the first car trip starts - private Map, Long> getInitialParkingByPlans() { - return population.getPersons().values().stream().map(p -> p.getSelectedPlan()) - .map(p -> TripStructureUtils.findAccessWalksWithPreviousActivity(p, TransportMode.car).stream().findFirst()) - .filter(Optional::isPresent) - .map(Optional::get) - .map(lap -> lap.act.getLinkId()) - .collect(Collectors.groupingBy(l -> l, Collectors.counting())); - } -} diff --git a/src/main/java/org/matsim/run/scoring/parking/ZeroParkingCapacityInitializer.java b/src/main/java/org/matsim/run/scoring/parking/ZeroParkingCapacityInitializer.java index 2972d435a..c3046345a 100644 --- a/src/main/java/org/matsim/run/scoring/parking/ZeroParkingCapacityInitializer.java +++ b/src/main/java/org/matsim/run/scoring/parking/ZeroParkingCapacityInitializer.java @@ -2,10 +2,13 @@ import com.google.inject.Inject; import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.events.VehicleEntersTrafficEvent; +import org.matsim.api.core.v01.events.VehicleLeavesTrafficEvent; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; @@ -21,12 +24,12 @@ public class ZeroParkingCapacityInitializer implements ParkingCapacityInitialize } @Override - public Map, InitialParkingCapacity> initialize() { - Map, InitialParkingCapacity> res = new HashMap<>(network.getLinks().size()); + public Map, ParkingInitialCapacity> initialize(List vehicleEntersTrafficEvents, List vehicleLeavesTrafficEvents) { + Map, ParkingInitialCapacity> res = new HashMap<>(network.getLinks().size()); for (Link link : network.getLinks().values()) { int onStreet = (int) Optional.ofNullable(link.getAttributes().getAttribute(LINK_ON_STREET_SPOTS)).orElse(0); int offStreet = (int) Optional.ofNullable(link.getAttributes().getAttribute(LINK_OFF_STREET_SPOTS)).orElse(0); - res.put(link.getId(), new InitialParkingCapacity(onStreet + offStreet, 0)); + res.put(link.getId(), new ParkingInitialCapacity(onStreet + offStreet, 0)); } return res; } diff --git a/src/test/java/org/matsim/run/scoring/parking/EventBasedParkingCapacityInitializerTest.java b/src/test/java/org/matsim/run/scoring/parking/EventBasedParkingCapacityInitializerTest.java new file mode 100644 index 000000000..4bc549e70 --- /dev/null +++ b/src/test/java/org/matsim/run/scoring/parking/EventBasedParkingCapacityInitializerTest.java @@ -0,0 +1,121 @@ +package org.matsim.run.scoring.parking; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Injector; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.events.VehicleEntersTrafficEvent; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.network.NetworkUtils; +import org.matsim.testcases.MatsimTestUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +class EventBasedParkingCapacityInitializerTest { + @RegisterExtension + MatsimTestUtils testUtils = new MatsimTestUtils(); + + @Test + void testEmpty() { + Map, ParkingCapacityInitializer.ParkingInitialCapacity> initialize = getParkingCapacityInitializer().initialize(List.of(), List.of()); + + Assertions.assertEquals(180, initialize.size()); + for (int i = 1; i <= 180; i++) { + Assertions.assertEquals(i, initialize.get(Id.createLinkId(String.valueOf(i))).capacity()); + Assertions.assertEquals(0, initialize.get(Id.createLinkId(String.valueOf(i))).initial()); + } + } + + @Test + void testFullInitial() { + List enterEvents = new ArrayList<>(); + //For all links: On link i, register i vehicle enters traffic events with different person ids. + for (int i = 1; i <= 180; i++) { + for (int j = 0; j < i; j++) { + enterEvents.add(new VehicleEntersTrafficEvent(i + j, Id.createPersonId("p" + i + "," + j), Id.createLinkId(String.valueOf(i)), null, TransportMode.car, 0)); + } + } + + Map, ParkingCapacityInitializer.ParkingInitialCapacity> initialize = getParkingCapacityInitializer().initialize(enterEvents, List.of()); + + Assertions.assertEquals(180, initialize.size()); + for (int i = 1; i <= 180; i++) { + Assertions.assertEquals(i, initialize.get(Id.createLinkId(String.valueOf(i))).capacity()); + Assertions.assertEquals(i, initialize.get(Id.createLinkId(String.valueOf(i))).initial()); + } + } + + @Test + void testSamePersonEntersTraffic() { + List enterEvents = new ArrayList<>(); + + //even though two enter events are registered, only one should be counted because the person is the same. + enterEvents.add(new VehicleEntersTrafficEvent(0, Id.createPersonId("testPerson"), Id.createLinkId(1), null, TransportMode.car, 0)); + enterEvents.add(new VehicleEntersTrafficEvent(10, Id.createPersonId("testPerson"), Id.createLinkId(2), null, TransportMode.car, 0)); + + Map, ParkingCapacityInitializer.ParkingInitialCapacity> initialize = getParkingCapacityInitializer().initialize(enterEvents, List.of()); + + Assertions.assertEquals(180, initialize.size()); + Assertions.assertEquals(1, initialize.get(Id.createLinkId("1")).capacity()); + Assertions.assertEquals(1, initialize.get(Id.createLinkId("1")).initial()); + + //checks in particular that on link 2 no initial parking is registered + for (int i = 2; i <= 180; i++) { + Assertions.assertEquals(i, initialize.get(Id.createLinkId(String.valueOf(i))).capacity()); + Assertions.assertEquals(0, initialize.get(Id.createLinkId(String.valueOf(i))).initial()); + } + } + + @Test + void testMoreInitialThanCapacity() { + List enterEvents = new ArrayList<>(); + + //Register 2 parking cars on link 1. We allow over subscription of parking spots. + enterEvents.add(new VehicleEntersTrafficEvent(0, Id.createPersonId("p1"), Id.createLinkId(1), null, TransportMode.car, 0)); + enterEvents.add(new VehicleEntersTrafficEvent(0, Id.createPersonId("p2"), Id.createLinkId(1), null, TransportMode.car, 0)); + + Map, ParkingCapacityInitializer.ParkingInitialCapacity> initialize = getParkingCapacityInitializer().initialize(enterEvents, List.of()); + + Assertions.assertEquals(180, initialize.size()); + Assertions.assertEquals(1, initialize.get(Id.createLinkId("1")).capacity()); + Assertions.assertEquals(2, initialize.get(Id.createLinkId("1")).initial()); + + for (int i = 2; i <= 180; i++) { + Assertions.assertEquals(i, initialize.get(Id.createLinkId(String.valueOf(i))).capacity()); + Assertions.assertEquals(0, initialize.get(Id.createLinkId(String.valueOf(i))).initial()); + } + } + + private ParkingCapacityInitializer getParkingCapacityInitializer() { + Injector injector = Guice.createInjector( + new AbstractModule() { + @Override + protected void configure() { + bind(Network.class).toInstance(getNetwork()); + bind(ParkingCapacityInitializer.class).to(EventBasedParkingCapacityInitializer.class); + } + }); + + ParkingCapacityInitializer initializer = injector.getInstance(ParkingCapacityInitializer.class); + return initializer; + } + + private Network getNetwork() { + // Chessboard network has 10x10 nodes, starting from (0,0) to (9000,9000). The distance between two adjacent nodes is 1000 on the x- or y-axis. + Network network = NetworkUtils.readNetwork(testUtils.getPackageInputDirectory() + "./chessboard_network.xml"); + network.getLinks().values().forEach(l -> { + l.getAttributes().putAttribute(ParkingObserver.LINK_ON_STREET_SPOTS, Integer.valueOf(l.getId().toString())); + l.getAttributes().putAttribute(ParkingObserver.LINK_OFF_STREET_SPOTS, 0); + }); + + return network; + } + +} diff --git a/src/test/java/org/matsim/run/scoring/parking/ParkingObserverTest.java b/src/test/java/org/matsim/run/scoring/parking/ParkingObserverTest.java index c5bb3c270..f5ef88556 100644 --- a/src/test/java/org/matsim/run/scoring/parking/ParkingObserverTest.java +++ b/src/test/java/org/matsim/run/scoring/parking/ParkingObserverTest.java @@ -19,11 +19,8 @@ import org.matsim.core.controler.Controler; import org.matsim.core.controler.Controller; import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.controler.events.AfterMobsimEvent; import org.matsim.core.scenario.ScenarioUtils; -import org.matsim.modechoice.estimators.ActivityEstimator; -import org.matsim.modechoice.estimators.DefaultActivityEstimator; -import org.matsim.modechoice.estimators.DefaultLegScoreEstimator; -import org.matsim.modechoice.estimators.LegEstimator; import org.matsim.testcases.MatsimTestUtils; import java.util.List; @@ -51,6 +48,8 @@ void testScoreEvents_sameLink() { eventsManager.processEvent(new VehicleLeavesTrafficEvent(0, Id.createPersonId("p1"), Id.createLinkId("55"), Id.createVehicleId("v1"), "car", 0)); // Person p2 parks at link 55. eventsManager.processEvent(new VehicleLeavesTrafficEvent(10, Id.createPersonId("p2"), Id.createLinkId("55"), Id.createVehicleId("v2"), "car", 0)); + + runAndCheckEvents(); } @Test @@ -67,6 +66,8 @@ void testScoreEvents_sameLink_OneVehicleLeft() { eventsManager.processEvent(new VehicleEntersTrafficEvent(5, Id.createPersonId("p1"), Id.createLinkId("55"), Id.createVehicleId("v1"), "car", 0)); // Person p2 parks at link 55. eventsManager.processEvent(new VehicleLeavesTrafficEvent(10, Id.createPersonId("p2"), Id.createLinkId("55"), Id.createVehicleId("v2"), "car", 0)); + + runAndCheckEvents(); } @Test @@ -81,6 +82,13 @@ void testScoreEvents_onlyOffStreetSpots() { eventsManager.processEvent(new VehicleLeavesTrafficEvent(0, Id.createPersonId("p1"), Id.createLinkId("55"), Id.createVehicleId("v1"), "car", 0)); // Person p2 parks at link 55. eventsManager.processEvent(new VehicleLeavesTrafficEvent(10, Id.createPersonId("p2"), Id.createLinkId("55"), Id.createVehicleId("v2"), "car", 0)); + + runAndCheckEvents(); + } + + private void runAndCheckEvents() { + injector.getInstance(ParkingObserver.class).notifyAfterMobsim(new AfterMobsimEvent(null, 0, false)); + injector.getInstance(TestHandler.class).checkAllEventsProcessed(); } EventsManager prepareParkingObserver(List expectedScoreEvents, boolean offStreet) { @@ -93,22 +101,13 @@ EventsManager prepareParkingObserver(List expectedScoreEvents, prepareNetwork(scenario.getNetwork(), offStreet); Controller controller = new Controler(scenario); + controller.addOverridingModule(new ParkingModule()); controller.addOverridingModule(new AbstractModule() { @Override public void install() { - // bind classes from informed mode choice explicitly - bind(ActivityEstimator.class).to(DefaultActivityEstimator.class); - bind(LegEstimator.class).to(DefaultLegScoreEstimator.class); - - // bind parking classes - bind(KernelFunction.class).to(ConstantKernelFunction.class); - bind(PenaltyFunction.class).toInstance(new BellochePenaltyFunction(0.4, -6)); - bind(ParkingCapacityInitializer.class).to(ZeroParkingCapacityInitializer.class); - bind(ParkingObserver.class); - addEventHandlerBinding().to(ParkingObserver.class); - // bind test event handler - addEventHandlerBinding().toInstance(new TestHandler(expectedScoreEvents)); + bind(TestHandler.class).toInstance(new TestHandler(expectedScoreEvents)); + addEventHandlerBinding().to(TestHandler.class); } }); @@ -139,5 +138,9 @@ public void handleEvent(PersonScoreEvent personScoreEvent) { Assertions.assertEquals(expectedEvent, personScoreEvent); eventCounter++; } + + public void checkAllEventsProcessed() { + Assertions.assertEquals(expectedEvents.size(), eventCounter); + } } } diff --git a/src/test/java/org/matsim/run/scoring/parking/ZeroParkingCapacityInitializerTest.java b/src/test/java/org/matsim/run/scoring/parking/ZeroParkingCapacityInitializerTest.java index 53d5a9196..8a6c15445 100644 --- a/src/test/java/org/matsim/run/scoring/parking/ZeroParkingCapacityInitializerTest.java +++ b/src/test/java/org/matsim/run/scoring/parking/ZeroParkingCapacityInitializerTest.java @@ -8,6 +8,7 @@ import org.matsim.core.network.NetworkUtils; import org.matsim.testcases.MatsimTestUtils; +import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -21,8 +22,8 @@ void testInitialize() { Network network = getNetwork(); ZeroParkingCapacityInitializer zeroParkingCapacityInitializer = new ZeroParkingCapacityInitializer(network); - Map, ParkingCapacityInitializer.InitialParkingCapacity> initialize = zeroParkingCapacityInitializer.initialize(); - for (ParkingCapacityInitializer.InitialParkingCapacity value : initialize.values()) { + Map, ParkingCapacityInitializer.ParkingInitialCapacity> initialize = zeroParkingCapacityInitializer.initialize(List.of(), List.of()); + for (ParkingCapacityInitializer.ParkingInitialCapacity value : initialize.values()) { assertEquals(0, value.initial()); } }