Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add parking tests and comments #3637

Merged
merged 11 commits into from
Dec 11, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@

package org.matsim.contrib.dynagent;

import java.util.List;

import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.events.ActivityEndEvent;
import org.matsim.api.core.v01.events.ActivityStartEvent;
Expand All @@ -40,6 +38,8 @@
import org.matsim.pt.transitSchedule.api.TransitStopFacility;
import org.matsim.vehicles.Vehicle;

import java.util.List;

public final class DynAgent implements MobsimDriverPassengerAgent {
private final DynAgentLogic agentLogic;

Expand Down Expand Up @@ -83,11 +83,11 @@ private void computeNextAction(DynAction oldDynAction, double now) {
DynAction nextDynAction = agentLogic.computeNextAction(oldDynAction, now);

if (nextDynAction instanceof DynActivity) {
dynActivity = (DynActivity)nextDynAction;
dynActivity = (DynActivity) nextDynAction;
state = MobsimAgent.State.ACTIVITY;
events.processEvent(new ActivityStartEvent(now, id, currentLinkId, null, dynActivity.getActivityType()));
} else {
dynLeg = (DynLeg)nextDynAction;
dynLeg = (DynLeg) nextDynAction;
state = MobsimAgent.State.LEG;
}
}
Expand Down Expand Up @@ -145,7 +145,7 @@ public String getMode() {
// VehicleUsingAgent
@Override
public final Id<Vehicle> getPlannedVehicleId() {
Id<Vehicle> vehId = ((DriverDynLeg)dynLeg).getPlannedVehicleId();
Id<Vehicle> vehId = ((DriverDynLeg) dynLeg).getPlannedVehicleId();
// according to BasicPlanAgentImpl
return vehId != null ? vehId : Id.create(id, Vehicle.class);
}
Expand Down Expand Up @@ -177,13 +177,13 @@ public Id<Link> getDestinationLinkId() {
// DriverAgent
@Override
public Id<Link> chooseNextLinkId() {
return ((DriverDynLeg)dynLeg).getNextLinkId();
return ((DriverDynLeg) dynLeg).getNextLinkId();
}

// DriverAgent
@Override
public void notifyMoveOverNode(Id<Link> newLinkId) {
((DriverDynLeg)dynLeg).movedOverNode(newLinkId);
((DriverDynLeg) dynLeg).movedOverNode(newLinkId);
currentLinkId = newLinkId;
}

Expand Down Expand Up @@ -226,26 +226,28 @@ public boolean isWantingToArriveOnCurrentLink() {
// PTPassengerAgent
@Override
public boolean getEnterTransitRoute(TransitLine line, TransitRoute transitRoute, List<TransitRouteStop> stopsToCome,
TransitVehicle transitVehicle) {
return ((PTPassengerDynLeg)dynLeg).getEnterTransitRoute(line, transitRoute, stopsToCome, transitVehicle);
TransitVehicle transitVehicle) {
return ((PTPassengerDynLeg) dynLeg).getEnterTransitRoute(line, transitRoute, stopsToCome, transitVehicle);
}

// PTPassengerAgent
// yyyy seems a bit odd, that this and the following methods are implemented for DynAgent as not every DynAgent is a PTPassengerAgent. paul,
// nov'24
@Override
public boolean getExitAtStop(TransitStopFacility stop) {
return ((PTPassengerDynLeg)dynLeg).getExitAtStop(stop);
return ((PTPassengerDynLeg) dynLeg).getExitAtStop(stop);
}

// PTPassengerAgent
@Override
public Id<TransitStopFacility> getDesiredAccessStopId() {
return ((PTPassengerDynLeg)dynLeg).getDesiredAccessStopId();
return ((PTPassengerDynLeg) dynLeg).getDesiredAccessStopId();
}

// PTPassengerAgent
@Override
public Id<TransitStopFacility> getDesiredDestinationStopId() {
return ((PTPassengerDynLeg)dynLeg).getDesiredDestinationStopId();
return ((PTPassengerDynLeg) dynLeg).getDesiredDestinationStopId();
}

// PTPassengerAgent
Expand Down
32 changes: 31 additions & 1 deletion contribs/parking/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,34 @@ approaches as to how parking can be handled in MATSim, depending on the use case
. This was designed for large scenarios where it's not feasable to fully simulate parking agents. Rather, the
additional time needed for parking is estimated
- Parking Costs, developed by Marcel Rieser and Joschka Bischoff at SBB. This modules allows the integration of parking
costs based on link attribute data.
costs based on link attribute data.

## Implementations

### Parking Search

Model parking search, including walking segments and parking search traffic.

Different Parking Search Logics:

1. **Random:**
1. Drive to the destination.
2. The next link is chosen randomly.
2. **DistanceMemoryParkingSearch:**
1. Drive to the destination.
2. Select the next link:
1. Choose an unknown link with the shortest straight-line distance to the destination.
2. If all links are known, choose randomly.
3. **NearestParkingSpotSearchLogic:**
1. Drive to the destination (??).
2. Search for the facility with the shortest distance to the current location, considering the expected driving time and parking duration (and
possibly parking time restrictions).
3. If no suitable facility is found ?
4. **BenensonParkingSearchLogic:** A more sophisticated strategy based on the Benenson
model: https://www.sciencedirect.com/science/article/pii/S0198971508000689

### Parking Proxy

### Parking Costs

### Parking Choice
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,30 @@
/**
* @author schlenther
* <p>
* Benenson et al defined 3 phases of parking search
* Benenson et al. defined 3 phases of parking search
* OBSERVING: observation of parking situation while driving towards destination
* SEARCH_WHILE_APPROACH: estimating the amount of free parking lots on the way to destination
* and if applicable parking before arriving
* SEARCH_FOR_NEXT: taking the next free parking space if it isn't too far away from destination
*/
enum ParkingMode {
DRIVING, OBSERVING, SEARCH_WHILE_APPROACH, SEARCH_FOR_NEXT
DRIVING, OBSERVING, SEARCH_WHILE_APPROACH, SEARCH_FOR_NEXT
}

public class BenensonDynLeg extends ParkingDynLeg{
public class BenensonDynLeg extends ParkingDynLeg {

private static final Logger logger = LogManager.getLogger(BenensonDynLeg.class);
private static final boolean logForDebug = false;

private double totalObservedParkingSpaces = 0.0;
private double observedFreeParkingSpaces = 0.0;
private double firstDestinationLinkEnterTime = 0;
private ParkingMode legStage = ParkingMode.DRIVING;
private double firstDestinationLinkEnterTime = 0;
private ParkingMode legStage = ParkingMode.DRIVING;

public BenensonDynLeg(String mode, NetworkRoute route, ParkingSearchLogic logic,
ParkingSearchManager parkingManager, Id<Vehicle> vehicleId, MobsimTimer timer, EventsManager events) {
ParkingSearchManager parkingManager, Id<Vehicle> vehicleId, MobsimTimer timer, EventsManager events) {
super(mode, route, logic, parkingManager, vehicleId, timer, events);
if (!(logic instanceof BenensonParkingSearchLogic)){
if (!(logic instanceof BenensonParkingSearchLogic)) {
throw new RuntimeException();
}
}
Expand All @@ -55,56 +55,68 @@ public void movedOverNode(Id<Link> newLinkId) {
currentLinkId = newLinkId;
if (this.legStage == ParkingMode.DRIVING) {

if (((BenensonParkingSearchLogic) this.logic).transitionToObservingBehaviour(currentLinkId, this.route.getEndLinkId())) {
this.legStage = ParkingMode.OBSERVING;
if (((BenensonParkingSearchLogic) this.logic).transitionToObservingBehaviour(currentLinkId, this.route.getEndLinkId())) {
this.legStage = ParkingMode.OBSERVING;
this.events.processEvent(new StartParkingSearchEvent(timer.getTimeOfDay(), vehicleId, currentLinkId));
if(logForDebug)logger.error("vehicle " + this.vehicleId + " goes into observing on link " + this.currentLinkId);
if (logForDebug) {
logger.error("vehicle " + this.vehicleId + " goes into observing on link " + this.currentLinkId);
}
}
}
if(this.legStage == ParkingMode.OBSERVING ){
if (this.legStage == ParkingMode.OBSERVING) {
memorizeParkingSituationAndIsSomethingFree();

if (((BenensonParkingSearchLogic) this.logic).transitionToParkingBehaviour(currentLinkId, this.route.getEndLinkId())) {
this.legStage = ParkingMode.SEARCH_WHILE_APPROACH;
if(logForDebug)logger.error("vehicle " + this.vehicleId + " goes into parking on link " + this.currentLinkId);
if (((BenensonParkingSearchLogic) this.logic).transitionToParkingBehaviour(currentLinkId, this.route.getEndLinkId())) {
this.legStage = ParkingMode.SEARCH_WHILE_APPROACH;
if (logForDebug) {
logger.error("vehicle " + this.vehicleId + " goes into parking on link " + this.currentLinkId);
}
}
}
if(this.legStage == ParkingMode.SEARCH_WHILE_APPROACH){
if(currentLinkId.equals(route.getEndLinkId())){
if (this.legStage == ParkingMode.SEARCH_WHILE_APPROACH) {
if (currentLinkId.equals(route.getEndLinkId())) {
this.legStage = ParkingMode.SEARCH_FOR_NEXT;
this.firstDestinationLinkEnterTime = timer.getTimeOfDay();
}
else{
if(memorizeParkingSituationAndIsSomethingFree()){
this.firstDestinationLinkEnterTime = timer.getTimeOfDay();
} else {
if (memorizeParkingSituationAndIsSomethingFree()) {
double pUnoccupied = 0;
if(this.totalObservedParkingSpaces > 0){
if (this.totalObservedParkingSpaces > 0) {
pUnoccupied = this.observedFreeParkingSpaces / this.totalObservedParkingSpaces;
}
if ( ((BenensonParkingSearchLogic)this.logic).wantToParkHere(pUnoccupied, currentLinkId, route.getEndLinkId())){
if (logForDebug) logger.error("vehicle " + this.vehicleId + " would like to park on link" + currentLinkId
+ "\n \t pUnoccupied = " + pUnoccupied + "\n\t totalObservedParkingSpaces = " + totalObservedParkingSpaces + "\n\t observedFreeSpaces = " + this.observedFreeParkingSpaces);
hasFoundParking = parkingManager.reserveSpaceIfVehicleCanParkHere(vehicleId, currentLinkId);
}
}
else{
if(logForDebug)logger.error("nothing free for vehicle " + vehicleId + " on link " + currentLinkId);
if (((BenensonParkingSearchLogic) this.logic).wantToParkHere(pUnoccupied, currentLinkId, route.getEndLinkId())) {
if (logForDebug) {
logger.error("vehicle " + this.vehicleId + " would like to park on link" + currentLinkId
+ "\n \t pUnoccupied = " + pUnoccupied + "\n\t totalObservedParkingSpaces = " + totalObservedParkingSpaces + "\n\t " +
"observedFreeSpaces = " + this.observedFreeParkingSpaces);
}
hasFoundParking = parkingManager.reserveSpaceIfVehicleCanParkHere(vehicleId, currentLinkId);
}
} else {
if (logForDebug) {
logger.error("nothing free for vehicle " + vehicleId + " on link " + currentLinkId);
}
}
}
}
if (this.legStage == ParkingMode.SEARCH_FOR_NEXT){
if (logForDebug) logger.error("vehicle " + this.vehicleId + " is in PHASE3 on link " + this.currentLinkId);
//if( ((BenensonParkingSearchLogic)this.logic).isDriverInAcceptableDistance(currentLinkId, route.getEndLinkId(), this.firstDestLinkEnterTimer, timer.getTimeOfDay()) ){
if (this.legStage == ParkingMode.SEARCH_FOR_NEXT) {
if (logForDebug) {
logger.error("vehicle " + this.vehicleId + " is in PHASE3 on link " + this.currentLinkId);
}
//if( ((BenensonParkingSearchLogic)this.logic).isDriverInAcceptableDistance(currentLinkId, route.getEndLinkId(), this
// .firstDestLinkEnterTimer, timer.getTimeOfDay()) ){

hasFoundParking = parkingManager.reserveSpaceIfVehicleCanParkHere(vehicleId, currentLinkId);
hasFoundParking = parkingManager.reserveSpaceIfVehicleCanParkHere(vehicleId, currentLinkId);

if (logForDebug) logger.error("vehicle " + this.vehicleId + " tries in PHASE3 to park on link " + this.currentLinkId + ", " +
(int) (timer.getTimeOfDay() - this.firstDestinationLinkEnterTime) / 60 + ":" + (int) (timer.getTimeOfDay() - this.firstDestinationLinkEnterTime) % 60
+ " min after passing destination. Result: " + hasFoundParking);
//}
}
}
if (logForDebug) {
logger.error("vehicle " + this.vehicleId + " tries in PHASE3 to park on link " + this.currentLinkId + ", " +
(int) (timer.getTimeOfDay() - this.firstDestinationLinkEnterTime) / 60 + ":" + (int) (timer.getTimeOfDay() - this.firstDestinationLinkEnterTime) % 60
+ " min after passing destination. Result: " + hasFoundParking);
}
//}
}
}

/**
/**
* returns true if there is at least one empty slot on the current link
*/
private boolean memorizeParkingSituationAndIsSomethingFree() {
Expand All @@ -124,13 +136,14 @@ public Id<Link> getNextLinkId() {
return route.getEndLinkId();
}
return linkIds.get(currentLinkIdx + 1);
}
else {
} else {
if (hasFoundParking) {
if(logForDebug)logger.error("vehicle " + this.vehicleId + " has found a parking on link " + this.currentLinkId + " after passing " + Math.abs((this.route.getLinkIds().size() - this.currentLinkIdx - 3)) + " links");
if (logForDebug) {
logger.error("vehicle " + this.vehicleId + " has found a parking on link " + this.currentLinkId + " after passing " + Math.abs((this.route.getLinkIds()
.size() - this.currentLinkIdx - 3)) + " links");
}
return null;
}
else {
} else {
if (this.currentAndNextParkLink != null) {
if (currentAndNextParkLink.getFirst().equals(currentLinkId)) {
// we already calculated this
Expand All @@ -139,15 +152,15 @@ public Id<Link> getNextLinkId() {
}

Id<Link> nextLinkId;
if(this.legStage == ParkingMode.SEARCH_FOR_NEXT){
nextLinkId = ((BenensonParkingSearchLogic) this.logic).getNextLinkRandomInAcceptableDistance(currentLinkId, this.route.getEndLinkId(),
vehicleId, firstDestinationLinkEnterTime, this.timer.getTimeOfDay(), mode);
}
else{
if (this.legStage == ParkingMode.SEARCH_FOR_NEXT) {
nextLinkId = ((BenensonParkingSearchLogic) this.logic).getNextLinkRandomInAcceptableDistance(currentLinkId,
this.route.getEndLinkId(),
vehicleId, firstDestinationLinkEnterTime, this.timer.getTimeOfDay(), mode);
} else {
nextLinkId = ((BenensonParkingSearchLogic) (this.logic)).getNextLinkBenensonRouting(currentLinkId, route.getEndLinkId(), mode);
}
currentAndNextParkLink = new Tuple<>(currentLinkId, nextLinkId);
return nextLinkId;
}
currentAndNextParkLink = new Tuple<>(currentLinkId, nextLinkId);
return nextLinkId;
}
}
}
Expand Down
Loading
Loading