From 42ae66d12857f9c8244238d225745478eca8a574 Mon Sep 17 00:00:00 2001 From: paulh Date: Tue, 11 Feb 2025 10:16:27 +0100 Subject: [PATCH] add initializer and change to injection during tests --- .../prepare/RunOpenBerlinCalibration.java | 4 +- .../network/NetworkAddParkingSpots.java | 15 ++- .../matsim/run/OpenBerlinParkingScenario.java | 39 ++++++++ .../parking/BellochePenaltyFunction.java | 2 +- .../parking/ConstantKernelFunction.java | 3 + .../parking/ParkingCapacityInitializer.java | 13 +++ .../scoring/parking/ParkingEventsHandler.java | 27 ++++++ .../run/scoring/parking/ParkingObserver.java | 31 ++++-- .../PlanBasedParkingCapacityInitializer.java | 53 ++++++++++ .../ZeroParkingCapacityInitializer.java | 33 +++++++ .../scoring/parking/ParkingObserverTest.java | 96 ++++++++++++++----- .../ZeroParkingCapacityInitializerTest.java | 34 +++++++ 12 files changed, 311 insertions(+), 39 deletions(-) create mode 100644 src/main/java/org/matsim/run/OpenBerlinParkingScenario.java create mode 100644 src/main/java/org/matsim/run/scoring/parking/ParkingCapacityInitializer.java create mode 100644 src/main/java/org/matsim/run/scoring/parking/ParkingEventsHandler.java create mode 100644 src/main/java/org/matsim/run/scoring/parking/PlanBasedParkingCapacityInitializer.java create mode 100644 src/main/java/org/matsim/run/scoring/parking/ZeroParkingCapacityInitializer.java create mode 100644 src/test/java/org/matsim/run/scoring/parking/ZeroParkingCapacityInitializerTest.java diff --git a/src/main/java/org/matsim/prepare/RunOpenBerlinCalibration.java b/src/main/java/org/matsim/prepare/RunOpenBerlinCalibration.java index 95559b7f7..8d58b1551 100644 --- a/src/main/java/org/matsim/prepare/RunOpenBerlinCalibration.java +++ b/src/main/java/org/matsim/prepare/RunOpenBerlinCalibration.java @@ -58,7 +58,9 @@ import org.matsim.prepare.drt.CreateDrtVehicles; import org.matsim.prepare.facilities.CreateMATSimFacilities; import org.matsim.prepare.facilities.ExtractFacilityGeoPkg; +import org.matsim.prepare.network.NetworkAddParkingSpots; import org.matsim.prepare.opt.ExtractPlanIndexFromType; +import org.matsim.prepare.network.NetworkAddParkingSpots; import org.matsim.prepare.opt.RunCountOptimization; import org.matsim.prepare.opt.SelectPlansFromIndex; import org.matsim.prepare.population.*; @@ -95,7 +97,7 @@ GenerateSmallScaleCommercialTrafficDemand.class, CreateDataDistributionOfStructureData.class, RunCountOptimization.class, SelectPlansFromIndex.class, ExtractPlanIndexFromType.class, AssignReferencePopulation.class, ExtractRelevantFreightTrips.class, CheckCarAvailability.class, FixSubtourModes.class, ComputeTripChoices.class, ComputePlanChoices.class, - ApplyNetworkParams.class, SetCarAvailabilityByAge.class, CreateDrtVehicles.class, EndlessCircleLineScheduleModifier.class + ApplyNetworkParams.class, SetCarAvailabilityByAge.class, CreateDrtVehicles.class, EndlessCircleLineScheduleModifier.class, NetworkAddParkingSpots.class }) public class RunOpenBerlinCalibration extends MATSimApplication { diff --git a/src/main/java/org/matsim/prepare/network/NetworkAddParkingSpots.java b/src/main/java/org/matsim/prepare/network/NetworkAddParkingSpots.java index 0370bb1a4..cf4e9cd10 100644 --- a/src/main/java/org/matsim/prepare/network/NetworkAddParkingSpots.java +++ b/src/main/java/org/matsim/prepare/network/NetworkAddParkingSpots.java @@ -23,7 +23,7 @@ public class NetworkAddParkingSpots implements MATSimAppCommand { @CommandLine.Option(names = "--network", description = "Path to input network", required = true) private Path network; - @CommandLine.Option(names = "--parking-sports", description = "Path to parking spots csv", required = true) + @CommandLine.Option(names = "--parking-spots", description = "Path to parking spots csv", required = true) private Path parkingSpots; @CommandLine.Option(names = "--output", description = "Desired output path", required = true) @@ -53,15 +53,22 @@ private List readParkingSpots() throws IOException { try (BufferedReader reader = Files.newBufferedReader(parkingSpots)) { CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT.withHeader()); for (CSVRecord csvRecord : csvParser) { - String linkId = csvRecord.get("linkId"); - double onStreet = Double.parseDouble(csvRecord.get("onStreet")); - double offStreet = Double.parseDouble(csvRecord.get("offStreet")); + String linkId = csvRecord.get("id"); + double onStreet = catchNa(csvRecord.get("onstreet_spots")); + double offStreet = catchNa(csvRecord.get("offstreet_spots")); parkingSpotEntries.add(new ParkingSpotEntry(linkId, onStreet, offStreet)); } } return parkingSpotEntries; } + private Double catchNa(String string) { + if (string.equals("NA")) { + return 0.0; + } + return Double.parseDouble(string); + } + private record ParkingSpotEntry(String linkId, double onStreet, double offStreet) { } } diff --git a/src/main/java/org/matsim/run/OpenBerlinParkingScenario.java b/src/main/java/org/matsim/run/OpenBerlinParkingScenario.java new file mode 100644 index 000000000..39d262612 --- /dev/null +++ b/src/main/java/org/matsim/run/OpenBerlinParkingScenario.java @@ -0,0 +1,39 @@ +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.*; + + +/** + * This class extends the Berlin scenario by parking search times. Currently, only one iteration is run based on that, scoring is performed. + * By default, it uses the Belloche parking search model with a kernel of 500m distance. + */ +public class OpenBerlinParkingScenario extends OpenBerlinScenario { + @Override + protected Config prepareConfig(Config config) { + super.prepareConfig(config); + + config.controller().setLastIteration(1); + config.network().setInputFile("with-parking"); + config.controller().setOutputDirectory(config.controller().getOutputDirectory() + "-parking"); + config.controller().setRunId(config.controller().getRunId() + "-parking"); + + return 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); + } + }); + } +} diff --git a/src/main/java/org/matsim/run/scoring/parking/BellochePenaltyFunction.java b/src/main/java/org/matsim/run/scoring/parking/BellochePenaltyFunction.java index bf1377913..29b60f301 100644 --- a/src/main/java/org/matsim/run/scoring/parking/BellochePenaltyFunction.java +++ b/src/main/java/org/matsim/run/scoring/parking/BellochePenaltyFunction.java @@ -23,7 +23,7 @@ public double calculatePenalty(Map, ParkingCount> parkingCount) { Tuple weightedOccK = getWeightedOccK(parkingCount); if (weightedOccK.getSecond() == 0) { - log.warn("The total capacity of parking spots is 0. As fallback, we assume that the occupancy rate is 1, so each link is full."); + // The total capacity of parking spots is 0. As fallback, we assume that the occupancy rate is 1, so each link is full. return alpha * Math.exp(-beta); } diff --git a/src/main/java/org/matsim/run/scoring/parking/ConstantKernelFunction.java b/src/main/java/org/matsim/run/scoring/parking/ConstantKernelFunction.java index ef2fcb555..522519859 100644 --- a/src/main/java/org/matsim/run/scoring/parking/ConstantKernelFunction.java +++ b/src/main/java/org/matsim/run/scoring/parking/ConstantKernelFunction.java @@ -1,5 +1,6 @@ package org.matsim.run.scoring.parking; +import com.google.inject.Inject; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; @@ -12,8 +13,10 @@ * A kernel function that assigns a constant weight to all links within a certain distance. Takes the middle of the link as the center of the disk. */ public class ConstantKernelFunction implements KernelFunction { + // this might be replaced by a LinkQuadTree from the network, but the getDisk method would have to be implemented there. QuadTree> quadTree; + @Inject public ConstantKernelFunction(Network network) { double xMin = network.getNodes().values().parallelStream().mapToDouble(node -> node.getCoord().getX()).min().orElse(Double.POSITIVE_INFINITY); double yMin = network.getNodes().values().parallelStream().mapToDouble(node -> node.getCoord().getY()).min().orElse(Double.POSITIVE_INFINITY); diff --git a/src/main/java/org/matsim/run/scoring/parking/ParkingCapacityInitializer.java b/src/main/java/org/matsim/run/scoring/parking/ParkingCapacityInitializer.java new file mode 100644 index 000000000..6877934f1 --- /dev/null +++ b/src/main/java/org/matsim/run/scoring/parking/ParkingCapacityInitializer.java @@ -0,0 +1,13 @@ +package org.matsim.run.scoring.parking; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; + +import java.util.Map; + +public interface ParkingCapacityInitializer { + Map, InitialParkingCapacity> initialize(); + + record InitialParkingCapacity(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 new file mode 100644 index 000000000..acac991a2 --- /dev/null +++ b/src/main/java/org/matsim/run/scoring/parking/ParkingEventsHandler.java @@ -0,0 +1,27 @@ +package org.matsim.run.scoring.parking; + +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; + +public class ParkingEventsHandler implements VehicleEntersTrafficEventHandler, VehicleLeavesTrafficEventHandler, TransitDriverStartsEventHandler { + + + @Override + public void handleEvent(TransitDriverStartsEvent event) { + + } + + @Override + public void handleEvent(VehicleEntersTrafficEvent event) { + + } + + @Override + public void handleEvent(VehicleLeavesTrafficEvent event) { + + } +} 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 87f06bf6c..7764223b3 100644 --- a/src/main/java/org/matsim/run/scoring/parking/ParkingObserver.java +++ b/src/main/java/org/matsim/run/scoring/parking/ParkingObserver.java @@ -13,6 +13,8 @@ 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.modechoice.estimators.ActivityEstimator; +import org.matsim.modechoice.estimators.LegEstimator; import org.matsim.vehicles.Vehicle; import java.util.HashMap; @@ -24,12 +26,12 @@ public class ParkingObserver implements VehicleEntersTrafficEventHandler, Vehicl static final String LINK_ON_STREET_SPOTS = "onstreet_spots"; static final String LINK_OFF_STREET_SPOTS = "offstreet_spots"; - //injected Network network; KernelFunction kernelFunction; PenaltyFunction penaltyFunction; EventsManager eventsManager; - + ActivityEstimator activityEstimator; + LegEstimator legEstimator; //state Set> knownPtVehicles = new HashSet<>(); @@ -38,19 +40,23 @@ public class ParkingObserver implements VehicleEntersTrafficEventHandler, Vehicl int[] capacity; //TODO - double kernelDistance = 0; + double kernelDistance = 500; @Inject - public ParkingObserver(Network network, KernelFunction kernelFunction, PenaltyFunction penaltyFunction, EventsManager eventsManager) { + 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; - initCapacity(network); + this.activityEstimator = activityEstimator; + this.legEstimator = legEstimator; + + initCapacity(network, parkingCapacityInitializer); } - private void initCapacity(Network network) { + private void initCapacity(Network network, ParkingCapacityInitializer parkingCapacityInitializer) { int counter = 0; for (Id id : network.getLinks().keySet()) { indexByLinkId.put(id, counter++); @@ -58,12 +64,16 @@ private void initCapacity(Network network) { int linkCount = network.getLinks().size(); capacity = new int[linkCount]; + parkingCount = new int[linkCount]; + + Map, ParkingCapacityInitializer.InitialParkingCapacity> initialize = parkingCapacityInitializer.initialize(); for (Link link : network.getLinks().values()) { - int onStreet = (int) link.getAttributes().getAttribute(LINK_ON_STREET_SPOTS); - int offStreet = (int) link.getAttributes().getAttribute(LINK_OFF_STREET_SPOTS); - capacity[indexByLinkId.get(link.getId())] = onStreet + offStreet; + ParkingCapacityInitializer.InitialParkingCapacity initialParkingCapacity = initialize.get(link.getId()); + int index = indexByLinkId.get(link.getId()); + + capacity[index] = initialParkingCapacity.capacity(); + parkingCount[index] = initialParkingCapacity.initial(); } - parkingCount = new int[linkCount]; } @Override @@ -114,6 +124,7 @@ private Map, ParkingCount> applyWeights(Map, Double> weightedL private void applyPenalty(double time, Id personId, double penaltyInSec, Id linkId) { //TODO convert penalty to money + double score = 0.0; PersonScoreEvent personScoreEvent = new PersonScoreEvent(time, personId, score, "parking"); diff --git a/src/main/java/org/matsim/run/scoring/parking/PlanBasedParkingCapacityInitializer.java b/src/main/java/org/matsim/run/scoring/parking/PlanBasedParkingCapacityInitializer.java new file mode 100644 index 000000000..e06dde7e0 --- /dev/null +++ b/src/main/java/org/matsim/run/scoring/parking/PlanBasedParkingCapacityInitializer.java @@ -0,0 +1,53 @@ +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 new file mode 100644 index 000000000..2972d435a --- /dev/null +++ b/src/main/java/org/matsim/run/scoring/parking/ZeroParkingCapacityInitializer.java @@ -0,0 +1,33 @@ +package org.matsim.run.scoring.parking; + +import com.google.inject.Inject; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +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 ZeroParkingCapacityInitializer implements ParkingCapacityInitializer { + private Network network; + + @Inject + ZeroParkingCapacityInitializer(Network network) { + this.network = network; + } + + @Override + public Map, InitialParkingCapacity> initialize() { + 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); + res.put(link.getId(), new InitialParkingCapacity(onStreet + offStreet, 0)); + } + return res; + } +} 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 abde23591..c5bb3c270 100644 --- a/src/test/java/org/matsim/run/scoring/parking/ParkingObserverTest.java +++ b/src/test/java/org/matsim/run/scoring/parking/ParkingObserverTest.java @@ -1,17 +1,29 @@ package org.matsim.run.scoring.parking; -import org.jetbrains.annotations.NotNull; +import com.google.inject.Injector; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; 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.Scenario; import org.matsim.api.core.v01.events.PersonScoreEvent; import org.matsim.api.core.v01.events.VehicleEntersTrafficEvent; import org.matsim.api.core.v01.events.VehicleLeavesTrafficEvent; import org.matsim.api.core.v01.events.handler.PersonScoreEventHandler; import org.matsim.api.core.v01.network.Network; -import org.matsim.core.events.EventsManagerImpl; -import org.matsim.core.network.NetworkUtils; +import org.matsim.core.api.experimental.events.EventsManager; +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.Controller; +import org.matsim.core.controler.OutputDirectoryHierarchy; +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; @@ -20,9 +32,12 @@ class ParkingObserverTest { @RegisterExtension MatsimTestUtils testUtils = new MatsimTestUtils(); - /** - * what should be tested: full parking - */ + private Injector injector; + + @BeforeEach + void setUp() { + injector = null; + } @Test void testScoreEvents_sameLink() { @@ -30,7 +45,7 @@ void testScoreEvents_sameLink() { new PersonScoreEvent(0, Id.createPersonId("p1"), 0.0, "parking"), new PersonScoreEvent(10, Id.createPersonId("p2"), 0.0, "parking") ); - EventsManagerImpl eventsManager = prepareParkingObserver(expectedScoreEvents); + EventsManager eventsManager = prepareParkingObserver(expectedScoreEvents, true); // Person p1 parks at link 55. eventsManager.processEvent(new VehicleLeavesTrafficEvent(0, Id.createPersonId("p1"), Id.createLinkId("55"), Id.createVehicleId("v1"), "car", 0)); @@ -39,12 +54,12 @@ void testScoreEvents_sameLink() { } @Test - void testScoreEvents_sameLink_vehicleLeft() { + void testScoreEvents_sameLink_OneVehicleLeft() { List expectedScoreEvents = List.of( new PersonScoreEvent(0, Id.createPersonId("p1"), 0.0, "parking"), new PersonScoreEvent(10, Id.createPersonId("p2"), 0.0, "parking") //TODO change amount ); - EventsManagerImpl eventsManager = prepareParkingObserver(expectedScoreEvents); + EventsManager eventsManager = prepareParkingObserver(expectedScoreEvents, true); // Person p1 parks at link 55. eventsManager.processEvent(new VehicleLeavesTrafficEvent(0, Id.createPersonId("p1"), Id.createLinkId("55"), Id.createVehicleId("v1"), "car", 0)); @@ -54,25 +69,60 @@ void testScoreEvents_sameLink_vehicleLeft() { eventsManager.processEvent(new VehicleLeavesTrafficEvent(10, Id.createPersonId("p2"), Id.createLinkId("55"), Id.createVehicleId("v2"), "car", 0)); } - @NotNull - private EventsManagerImpl prepareParkingObserver(List expectedScoreEvents) { - Network network = loadAndPrepareNetwork(); - KernelFunction kernelFunction = new ConstantKernelFunction(network); - PenaltyFunction penaltyFunction = new BellochePenaltyFunction(0.4, -6); - EventsManagerImpl eventsManager = new EventsManagerImpl(); - eventsManager.addHandler(new TestHandler(expectedScoreEvents)); - ParkingObserver parkingObserver = new ParkingObserver(network, kernelFunction, penaltyFunction, eventsManager); - eventsManager.addHandler(parkingObserver); - return eventsManager; + @Test + void testScoreEvents_onlyOffStreetSpots() { + List expectedScoreEvents = List.of( + new PersonScoreEvent(0, Id.createPersonId("p1"), 0.0, "parking"), + new PersonScoreEvent(10, Id.createPersonId("p2"), 0.0, "parking") + ); + EventsManager eventsManager = prepareParkingObserver(expectedScoreEvents, false); + + // Person p1 parks at link 55. + 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)); + } + + EventsManager prepareParkingObserver(List expectedScoreEvents, boolean offStreet) { + Config config = ConfigUtils.createConfig(); + config.network().setInputFile(testUtils.getPackageInputDirectory() + "chessboard_network.xml"); + config.controller().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(testUtils.getOutputDirectory()); + + Scenario scenario = ScenarioUtils.loadScenario(config); + prepareNetwork(scenario.getNetwork(), offStreet); + + Controller controller = new Controler(scenario); + 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)); + } + }); + + injector = controller.getInjector(); + return injector.getInstance(EventsManager.class); } - private Network loadAndPrepareNetwork() { - Network network = NetworkUtils.readNetwork(testUtils.getPackageInputDirectory() + "chessboard_network.xml"); + private void prepareNetwork(Network network, boolean offStreet) { network.getLinks().values().forEach(l -> { l.getAttributes().putAttribute(ParkingObserver.LINK_ON_STREET_SPOTS, 1); - l.getAttributes().putAttribute(ParkingObserver.LINK_OFF_STREET_SPOTS, 1); + if (offStreet) { + l.getAttributes().putAttribute(ParkingObserver.LINK_OFF_STREET_SPOTS, 1); + } }); - return network; } private static class TestHandler implements PersonScoreEventHandler { diff --git a/src/test/java/org/matsim/run/scoring/parking/ZeroParkingCapacityInitializerTest.java b/src/test/java/org/matsim/run/scoring/parking/ZeroParkingCapacityInitializerTest.java new file mode 100644 index 000000000..53d5a9196 --- /dev/null +++ b/src/test/java/org/matsim/run/scoring/parking/ZeroParkingCapacityInitializerTest.java @@ -0,0 +1,34 @@ +package org.matsim.run.scoring.parking; + +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.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.network.NetworkUtils; +import org.matsim.testcases.MatsimTestUtils; + +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ZeroParkingCapacityInitializerTest { + @RegisterExtension + MatsimTestUtils testUtils = new MatsimTestUtils(); + + @Test + void testInitialize() { + Network network = getNetwork(); + + ZeroParkingCapacityInitializer zeroParkingCapacityInitializer = new ZeroParkingCapacityInitializer(network); + Map, ParkingCapacityInitializer.InitialParkingCapacity> initialize = zeroParkingCapacityInitializer.initialize(); + for (ParkingCapacityInitializer.InitialParkingCapacity value : initialize.values()) { + assertEquals(0, value.initial()); + } + } + + 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. + return NetworkUtils.readNetwork(testUtils.getPackageInputDirectory() + "./chessboard_network.xml"); + } +}