Skip to content

Commit

Permalink
add event bases initialization
Browse files Browse the repository at this point in the history
  • Loading branch information
paulheinr committed Feb 11, 2025
1 parent 42ae66d commit eabdf0f
Show file tree
Hide file tree
Showing 11 changed files with 340 additions and 133 deletions.
13 changes: 2 additions & 11 deletions src/main/java/org/matsim/run/OpenBerlinParkingScenario.java
Original file line number Diff line number Diff line change
@@ -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;


/**
Expand All @@ -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());
}
}
Original file line number Diff line number Diff line change
@@ -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<Id<Link>, ParkingInitialCapacity> initialize(List<VehicleEntersTrafficEvent> vehicleEntersTrafficEvents, List<VehicleLeavesTrafficEvent> vehicleLeavesTrafficEvents) {
Map<Id<Link>, Long> initialParkingByPlans = getInitialParkingByPlans(vehicleEntersTrafficEvents);

Map<Id<Link>, 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<Id<Link>, Long> getInitialParkingByPlans(List<VehicleEntersTrafficEvent> vehicleEntersTrafficEvents) {


Set<Id<Person>> visitedPerson = new HashSet<>();
return vehicleEntersTrafficEvents.stream()
.filter(e -> visitedPerson.add(e.getPersonId()))
.collect(Collectors.groupingBy(VehicleEntersTrafficEvent::getLinkId, Collectors.counting()));
}
}
Original file line number Diff line number Diff line change
@@ -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<Id<Link>, InitialParkingCapacity> initialize();
Map<Id<Link>, ParkingInitialCapacity> initialize(List<VehicleEntersTrafficEvent> vehicleEntersTrafficEvents, List<VehicleLeavesTrafficEvent> vehicleLeavesTrafficEvents);

record InitialParkingCapacity(int capacity, int initial) {
record ParkingInitialCapacity(int capacity, int initial) {
}
}
Original file line number Diff line number Diff line change
@@ -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<VehicleEntersTrafficEvent> vehicleEntersTrafficEvents = new ArrayList<>();
private List<VehicleLeavesTrafficEvent> vehicleLeavesTrafficEvents = new ArrayList<>();

private boolean locked = false;
private Set<Id<Vehicle>> 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<VehicleEntersTrafficEvent> getVehicleEntersTrafficEvents() {
return vehicleEntersTrafficEvents;
}

public List<VehicleLeavesTrafficEvent> 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.");
}
}
}
27 changes: 27 additions & 0 deletions src/main/java/org/matsim/run/scoring/parking/ParkingModule.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
105 changes: 61 additions & 44 deletions src/main/java/org/matsim/run/scoring/parking/ParkingObserver.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Id<Vehicle>> knownPtVehicles = new HashSet<>();
Map<Id<Link>, Integer> indexByLinkId;
Expand All @@ -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<Link> id : network.getLinks().keySet()) {
indexByLinkId.put(id, counter++);
}
private void run() {
List<VehicleLeavesTrafficEvent> vehicleLeavesTrafficEvents = parkingEventsHandler.getVehicleLeavesTrafficEvents();
List<VehicleEntersTrafficEvent> 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<Id<Link>, 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;
}
Expand Down Expand Up @@ -130,4 +123,28 @@ private void applyPenalty(double time, Id<Person> 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<Link> id : network.getLinks().keySet()) {
indexByLinkId.put(id, counter++);
}

int linkCount = network.getLinks().size();
capacity = new int[linkCount];
parkingCount = new int[linkCount];

Map<Id<Link>, 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();
}
}
}
Loading

0 comments on commit eabdf0f

Please sign in to comment.