MATSIM
OccupancyTracker.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.* *
3  *
4  * *
5  * *********************************************************************** *
6  * *
7  * copyright : (C) 2023 by the members listed in the COPYING, *
8  * LICENSE and WARRANTY file. *
9  * email : info at matsim dot org *
10  * *
11  * *********************************************************************** *
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * See also COPYING, LICENSE and WARRANTY file *
18  * *
19  * *********************************************************************** */
20 package ch.sbb.matsim.routing.pt.raptor;
21 
28 import java.util.HashSet;
29 import java.util.Iterator;
30 import java.util.Map;
31 import java.util.Set;
32 
34 import org.apache.logging.log4j.LogManager;
35 import org.apache.logging.log4j.Logger;
36 import org.matsim.api.core.v01.Id;
37 import org.matsim.api.core.v01.Scenario;
57 import org.matsim.core.utils.misc.Time;
61 import org.matsim.vehicles.Vehicle;
62 
63 import jakarta.inject.Inject;
64 
73 
74  private final static Logger LOG = LogManager.getLogger(OccupancyTracker.class);
75 
76  private final OccupancyData data;
77  private final Scenario scenario;
78  private final Set<Id<Person>> transitDrivers = new HashSet<>();
80  private final EventsManager events;
81  private final boolean useInVehCosts;
82 
83  private final static VehicleData DUMMY_VEHDATA = new VehicleData(null, null, null, null);
85 
86  @Inject
87  public OccupancyTracker(OccupancyData data, Scenario scenario, RaptorInVehicleCostCalculator inVehCostCalculator, EventsManager events, ScoringParametersForPerson scoringParams) {
88  this.data = data;
89  this.scenario = scenario;
90  this.inVehCostCalculator = inVehCostCalculator;
91  // the default in vehicle cost calculator can be ignored
92  this.useInVehCosts = !inVehCostCalculator.getClass().equals(DefaultRaptorInVehicleCostCalculator.class);
93  this.events = events;
94  this.scoringParams = scoringParams;
95  }
96 
97  @Override
98  public void handleEvent(PersonDepartureEvent event) {
99  PassengerData pd = this.data.paxData.computeIfAbsent(event.getPersonId(), k -> {
100  Person person = this.scenario.getPopulation().getPersons().get(k);
101  Map<String, ModeUtilityParameters> modeParams = this.scoringParams.getScoringParameters(person).modeParams;
102  return new PassengerData(person, modeParams);
103  });
104  pd.mode = event.getLegMode();
105  }
106 
107  @Override
109  this.transitDrivers.add(event.getDriverId());
110  // store information about the current service of the transit vehicle
111  Vehicle vehicle = this.scenario.getTransitVehicles().getVehicles().get(event.getVehicleId());
112  this.data.vehicleData.put(event.getVehicleId(), new VehicleData(vehicle, event.getTransitLineId(), event.getTransitRouteId(), event.getDepartureId()));
113  LineData line = this.data.lineData.computeIfAbsent(event.getTransitLineId(), id -> new LineData());
114  RouteData route = line.routeData.computeIfAbsent(event.getTransitRouteId(), id -> new RouteData(
115  this.scenario.getTransitSchedule().getTransitLines().get(event.getTransitLineId()).getRoutes().get(event.getTransitRouteId())
116  ));
117  }
118 
119  @Override
121  // store at what stop the transit vehicle currently is
122  this.data.vehicleData.getOrDefault(event.getVehicleId(), DUMMY_VEHDATA).stopFacilityId = event.getFacilityId();
123  }
124 
125  @Override
127  // if nobody entered, store the departure time as latest time
128  VehicleData vehData = this.data.vehicleData.get(event.getVehicleId());
129  if (vehData != null) {
130  LineData line = this.data.lineData.get(vehData.lineId);
131  RouteData route = line.routeData.get(vehData.routeId);
132  StopData stop = route.stopData.computeIfAbsent(vehData.stopFacilityId, id -> new StopData());
133  DepartureData dep = stop.getOrCreate(vehData.departureId);
134  dep.vehDepTime = event.getTime();
135  dep.paxCountAtDeparture = vehData.currentPaxCount;
136  }
137  }
138 
139  @Override
140  public void handleEvent(AgentWaitingForPtEvent event) {
141  PassengerData pd = this.data.paxData.get(event.getPersonId());
142  pd.waitingStartTime = event.getTime();
143  pd.boardingStopId = event.waitingAtStopId;
144  }
145 
146  @Override
148  VehicleData vehData = this.data.vehicleData.get(event.getVehicleId());
149  if (vehData != null && !this.transitDrivers.contains(event.getPersonId())) {
150  vehData.currentPaxCount++;
151  PassengerData passengerData = this.data.paxData.get(event.getPersonId());
152  double waitStart = passengerData.waitingStartTime;
153  LineData line = this.data.lineData.get(vehData.lineId);
154  RouteData route = line.routeData.get(vehData.routeId);
155  StopData stop = route.stopData.computeIfAbsent(vehData.stopFacilityId, id -> new StopData());
156  stop.getOrCreate(vehData.departureId).addWaitingPerson(waitStart);
157  passengerData.vehBoardingTime = event.getTime();
158  passengerData.departureId = vehData.departureId;
159  }
160  }
161 
162  @Override
164  VehicleData vehData = this.data.vehicleData.get(event.getVehicleId());
165  if (vehData != null && !this.transitDrivers.contains(event.getPersonId())) {
166  vehData.currentPaxCount--;
167  if (this.useInVehCosts) {
168  calculateInVehicleCosts(event.getTime(), this.data.paxData.get(event.getPersonId()), vehData);
169  }
170  }
171  }
172 
173  @Override
174  public void reset(int iteration) {
175  this.data.reset();
176  this.transitDrivers.clear();
177  }
178 
179  private void calculateInVehicleCosts(double time, PassengerData passengerData, VehicleData vehData) {
180  Person person = passengerData.person;
181 
182  double depTime = this.data.getRouteData(vehData.lineId, vehData.routeId).stopData.get(passengerData.boardingStopId).depData.get(passengerData.departureId).vehDepTime;
183 // double depTime = passengerData.vehBoardingTime;
184  double arrTime = time;
185  double travelTime = arrTime - depTime;
186 
187  ModeUtilityParameters modeParams = passengerData.modeParams.get(passengerData.mode);
188  double margUtil_s = modeParams.marginalUtilityOfTraveling_s;
189  double defaultScore = travelTime * margUtil_s;
190 
191  EffectiveRouteSegmentIterator iter = new EffectiveRouteSegmentIterator(this.data, passengerData, time, vehData);
192  double capacityScore = -this.inVehCostCalculator.getInVehicleCost(travelTime, margUtil_s, person, vehData.vehicle, null, iter);
193 
194  double scoreDiff = capacityScore - defaultScore;
195  if (Double.isNaN(scoreDiff)) {
196  LOG.warn("Getting NaN as score: " + passengerData.person.getId() + " " + vehData.lineId + " " + vehData.routeId + " " + Time.writeTime(time) + " " + depTime + " " + travelTime + " " + defaultScore + " " + capacityScore);
197  } else {
198  this.events.processEvent(new PersonScoreEvent(time, person.getId(), scoreDiff, "pt-occupancy"));
199  }
200  }
201 
202  public static class EffectiveRouteSegmentIterator implements RouteSegmentIterator {
203 
204  final PassengerData passengerData;
205  final VehicleData vehData;
206  final RouteData routeData;
207  final double alightingTime;
208  DepartureData currentDepData = null;
209  DepartureData nextFromStopDepData = null;
210  DepartureData nextToStopDepData = null;
211  Iterator<TransitRouteStop> stopIter;
212  boolean hasNext = false;
213  TransitRouteStop nextToStop = null;
214  TransitRouteStop nextFromStop = null;
215 
216  public EffectiveRouteSegmentIterator(OccupancyData data, PassengerData passengerData, double alightingTime, VehicleData vehData) {
217  this.passengerData = passengerData;
218  this.vehData = vehData;
219  this.alightingTime = alightingTime;
220  this.routeData = data.getRouteData(vehData.lineId, vehData.routeId);
221  TransitRoute ptRoute = this.routeData.route;
222  this.stopIter = ptRoute.getStops().iterator();
223  next();
224  }
225 
226  @Override
227  public boolean hasNext() {
228  return this.hasNext;
229  }
230 
231  @Override
232  public void next() {
233  this.currentDepData = this.nextFromStopDepData;
234  boolean searchStart = !this.hasNext;
235  this.hasNext = false;
236  this.nextFromStopDepData = this.nextToStopDepData;
237  Id<TransitStopFacility> boardingStopId = this.passengerData.boardingStopId;
238  Id<TransitStopFacility> alightingStopId = this.vehData.stopFacilityId;
239  while (this.stopIter.hasNext()) {
240  this.nextToStop = this.stopIter.next();
241  Id<TransitStopFacility> stopId = this.nextFromStop != null ? this.nextFromStop.getStopFacility().getId() : null;
242  if (searchStart && this.nextFromStop != null && stopId.equals(boardingStopId)) {
243  this.nextFromStopDepData = this.routeData.stopData.get(stopId).depData.get(this.passengerData.departureId);
244  this.hasNext = true;
245  break;
246  }
247  if (!searchStart) {
248  this.hasNext = !this.nextFromStop.getStopFacility().getId().equals(alightingStopId);
249  break;
250  }
251  this.nextFromStop = this.nextToStop;
252  }
253  if (this.hasNext) {
254  StopData stopData = this.routeData.stopData.get(this.nextToStop.getStopFacility().getId());
255  this.nextToStopDepData = stopData == null ? null : stopData.depData.get(this.passengerData.departureId);
256  if (this.nextToStopDepData == null) {
257  // this can happen if it is on the first service in the morning, and an agent leaves at this stop, where no vehicle yet has departed
258  this.nextToStopDepData = new DepartureData(this.passengerData.departureId);
259  this.nextToStopDepData.vehDepTime = this.alightingTime;
260  }
261  this.nextFromStop = this.nextToStop;
262  }
263  }
264 
265  @Override
266  public double getInVehicleTime() {
267  return this.nextFromStopDepData.vehDepTime - this.currentDepData.vehDepTime;
268  }
269 
270  @Override
271  public double getPassengerCount() {
272  return this.currentDepData.paxCountAtDeparture;
273  }
274 
275  @Override
276  public double getTimeOfDay() {
277  return this.currentDepData.vehDepTime;
278  }
279  }
280 
281 }
void calculateInVehicleCosts(double time, PassengerData passengerData, VehicleData vehData)
void handleEvent(AgentWaitingForPtEvent event)
double getInVehicleCost(double inVehicleTime, double marginalUtility_utl_s, Person person, Vehicle vehicle, RaptorParameters paramters, RouteSegmentIterator iterator)
void handleEvent(PersonLeavesVehicleEvent event)
final Map< String, ModeUtilityParameters > modeParams
void handleEvent(PersonEntersVehicleEvent event)
Map< Id< Person >,? extends Person > getPersons()
RouteData getRouteData(Id< TransitLine > transitLine, Id< TransitRoute > transitRoute)
void handleEvent(VehicleArrivesAtFacilityEvent event)
void handleEvent(PersonDepartureEvent event)
EffectiveRouteSegmentIterator(OccupancyData data, PassengerData passengerData, double alightingTime, VehicleData vehData)
static final String writeTime(final double seconds, final String timeformat)
Definition: Time.java:80
final ScoringParametersForPerson scoringParams
abstract TransitStopFacility getStopFacility()
void handleEvent(VehicleDepartsAtFacilityEvent event)
void handleEvent(TransitDriverStartsEvent event)
Map< Id< Vehicle >, Vehicle > getVehicles()
final RaptorInVehicleCostCalculator inVehCostCalculator
TransitSchedule getTransitSchedule()
boolean equals(Object obj)
Definition: Id.java:139
Map< Id< TransitLine >, TransitLine > getTransitLines()
OccupancyTracker(OccupancyData data, Scenario scenario, RaptorInVehicleCostCalculator inVehCostCalculator, EventsManager events, ScoringParametersForPerson scoringParams)