MATSIM
LinkPaxVolumesAnalysis.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * LinkPaxVolumesAnalysis.java
4  * *
5  * *********************************************************************** *
6  * *
7  * copyright : (C) 2021 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 
21 package org.matsim.analysis.linkpaxvolumes;
22 
23 import org.apache.logging.log4j.LogManager;
24 import org.apache.logging.log4j.Logger;
25 import org.matsim.api.core.v01.Id;
26 import org.matsim.api.core.v01.IdMap;
27 import org.matsim.api.core.v01.IdSet;
28 import org.matsim.api.core.v01.events.*;
32 import org.matsim.vehicles.Vehicle;
35 
36 import java.util.*;
37 
55 
56  private final static Logger log = LogManager.getLogger(LinkPaxVolumesAnalysis.class);
57  private final int timeBinSize;
58  private final int maxTime; // TODO: maybe 24h is too restrictive with plans rather 3:00 - 27:00
59  private final int maxSlotIndex;
63  private final Vehicles vehicles;
64  private final Vehicles transitVehicles;
65  private final Id<VehicleType> nullVehicleType = Id.create("nullVehicleType", VehicleType.class);
66 
67  // for multi-modal / multi vehicle type support
68  final boolean observeNetworkModes;
69  final boolean observePassengerModes;
70  final boolean observeVehicleTypes;
82 
83  public LinkPaxVolumesAnalysis(Vehicles vehicles, Vehicles transitVehicles /* TODO: add some config settings */) {
84  this(3600, 30 * 3600 - 1, vehicles, transitVehicles, true, true, true);
85  }
86 
87  LinkPaxVolumesAnalysis(final int timeBinSize, final int maxTime, final Vehicles vehicles,
88  final Vehicles transitVehicles, boolean observeNetworkModes, boolean observePassengerModes,
89  boolean observeVehicleTypes) {
90  this.timeBinSize = timeBinSize;
91  this.maxTime = maxTime;
92  this.maxSlotIndex = (this.maxTime/this.timeBinSize) + 1;
93  this.linkVehicleVolumes = new IdMap<>(Link.class);
94  this.linkPaxVolumes = new IdMap<>(Link.class);
95  this.vehiclesData = new IdMap<>(Vehicle.class);
96  this.vehicles = vehicles;
97  this.transitVehicles = transitVehicles;
98  this.person2passengerMode = new IdMap<>(Person.class);
99  this.vehiclesAboutToLeave = new IdSet<>(Vehicle.class);
100  this.vehicleType2timeOnNetwork = new IdMap<>(VehicleType.class);
101  this.vehicleType2numberSeen = new IdMap<>(VehicleType.class);
102  this.vehicleIdsSeen = new IdSet<>(Vehicle.class);
103 
104  this.observeNetworkModes = observeNetworkModes;
105  if (this.observeNetworkModes) {
106  this.linkVehicleVolumesPerNetworkMode = new IdMap<>(Link.class);
107  this.linkPaxVolumesPerNetworkMode = new IdMap<>(Link.class);
108  } else {
109  this.linkVehicleVolumesPerNetworkMode = null;
110  this.linkPaxVolumesPerNetworkMode = null;
111  }
112  this.observePassengerModes = observePassengerModes;
113  if (this.observePassengerModes) {
114  this.linkVehicleVolumesPerPassengerMode = new IdMap<>(Link.class);
115  this.linkPaxVolumesPerPassengerMode = new IdMap<>(Link.class);
116  } else {
117  this.linkVehicleVolumesPerPassengerMode = null;
118  this.linkPaxVolumesPerPassengerMode = null;
119  }
120  this.observeVehicleTypes = observeVehicleTypes;
121  if (this.observeVehicleTypes) {
122  this.linkVehicleVolumesPerVehicleType = new IdMap<>(Link.class);
123  this.linkPaxVolumesPerVehicleType = new IdMap<>(Link.class);
124  } else {
125  this.linkVehicleVolumesPerVehicleType = null;
126  this.linkPaxVolumesPerVehicleType = null;
127  }
128  }
129 
130  @Override
131  public void handleEvent(PersonDepartureEvent event) {
132  this.person2passengerMode.put(event.getPersonId(), event.getLegMode());
133  }
134 
135  @Override
137  VehicleData vehicleData = this.vehiclesData.get(event.getVehicleId());
138  if (vehicleData == null) {
139  Vehicle vehicle = vehicles.getVehicles().get(event.getVehicleId());
140  if (vehicle == null) {
141  // TODO: Why can the transit vehicles not be found in the general scenario.getVehicles() ?
142  vehicle = transitVehicles.getVehicles().get(event.getVehicleId());
143  }
144  vehicleData = new VehicleData(event.getVehicleId(),
145  vehicle == null ? nullVehicleType : vehicle.getType().getId(),
146  event.getPersonId());
147  this.vehiclesData.put(event.getVehicleId(), vehicleData);
148  }
149  String passengerMode = person2passengerMode.get(event.getPersonId());
150  Map<String, Integer> passengersByMode = this.vehiclesData.get(event.getVehicleId()).passengerMode2currentPax;
151  passengersByMode.put(passengerMode, passengersByMode.getOrDefault(passengerMode, 0) + 1);
152  }
153 
154  @Override
156  VehicleData vehicleData = this.vehiclesData.get(event.getVehicleId());
157  vehicleData.networkMode = event.getNetworkMode();
158  vehicleData.enteredNetworkTime = event.getTime();
159 
160  // count number of vehicles
161  if (!vehicleIdsSeen.contains(event.getVehicleId())) {
162  vehicleIdsSeen.add(event.getVehicleId());
163  this.vehicleType2numberSeen.put(vehicleData.vehicleTypeId,
164  this.vehicleType2numberSeen.computeIfAbsent(vehicleData.vehicleTypeId, k -> 0) + 1);
165  }
166  }
167 
168  @Override
169  public void handleEvent(final LinkEnterEvent event) {
170  int[] vehicleVolumesAll = this.linkVehicleVolumes.get(event.getLinkId());
171  if (vehicleVolumesAll == null) {
172  vehicleVolumesAll = new int[this.maxSlotIndex + 1]; // initialized to 0 by default, according to JVM specs
173  this.linkVehicleVolumes.put(event.getLinkId(), vehicleVolumesAll);
174  }
175  int timeslot = getTimeSlotIndex(event.getTime());
176  vehicleVolumesAll[timeslot]++;
177 
178  VehicleData vehicleData = this.vehiclesData.get(event.getVehicleId());
179  int currentPaxAllPassengerModes = 0;
180  for (int i : vehicleData.passengerMode2currentPax.values()) {
181  currentPaxAllPassengerModes += i;
182  }
183 
184  int[] passengerVolumesAll = this.linkPaxVolumes.get(event.getLinkId());
185  if (passengerVolumesAll == null) {
186  passengerVolumesAll = new int[this.maxSlotIndex + 1]; // initialized to 0 by default, according to JVM specs
187  this.linkPaxVolumes.put(event.getLinkId(), passengerVolumesAll);
188  }
189  passengerVolumesAll[timeslot] += currentPaxAllPassengerModes;
190 
191  if (this.observeNetworkModes) {
192  String mode = vehicleData.networkMode;
193 
194  Map<String, int[]> modeVehicleVolumes = this.linkVehicleVolumesPerNetworkMode.
195  computeIfAbsent(event.getLinkId(), k -> new HashMap<>());
196  int[] vehicleVolumes = modeVehicleVolumes.get(mode);
197  if (vehicleVolumes == null) {
198  vehicleVolumes = new int[this.maxSlotIndex + 1]; // initialized to 0 by default, according to JVM specs
199  modeVehicleVolumes.put(mode, vehicleVolumes);
200  }
201  vehicleVolumes[timeslot]++;
202 
203  Map<String, int[]> modePassengerVolumes = this.linkPaxVolumesPerNetworkMode.
204  computeIfAbsent(event.getLinkId(), k -> new HashMap<>());
205  int[] passengerVolumes = modePassengerVolumes.get(mode);
206  if (passengerVolumes == null) {
207  passengerVolumes = new int[this.maxSlotIndex + 1]; // initialized to 0 by default, according to JVM specs
208  modePassengerVolumes.put(mode, passengerVolumes);
209  }
210  passengerVolumes[timeslot] += currentPaxAllPassengerModes;
211  }
212 
213  if (this.observePassengerModes) {
214  // There is no clear way how to count a vehicle which is used by passengers of different passenger modes
215  // Here we simply count multiple times the same vehicle (once per passenger mode)
216  for (Map.Entry<String, Integer> passengerMode2modePax: vehicleData.passengerMode2currentPax.entrySet()) {
217 
218  Map<String, int[]> modeVehicleVolumes = this.linkVehicleVolumesPerPassengerMode.
219  computeIfAbsent(event.getLinkId(), k -> new HashMap<>());
220  int[] vehicleVolumes = modeVehicleVolumes.get(passengerMode2modePax.getKey());
221  if (vehicleVolumes == null) {
222  vehicleVolumes = new int[this.maxSlotIndex + 1]; // initialized to 0 by default, according to JVM specs
223  modeVehicleVolumes.put(passengerMode2modePax.getKey(), vehicleVolumes);
224  }
225  vehicleVolumes[timeslot]++;
226 
227  Map<String, int[]> modePassengerVolumes = this.linkPaxVolumesPerPassengerMode.
228  computeIfAbsent(event.getLinkId(), k -> new HashMap<>());
229  int[] passengerVolumes = modePassengerVolumes.get(passengerMode2modePax.getKey());
230  if (passengerVolumes == null) {
231  passengerVolumes = new int[this.maxSlotIndex + 1]; // initialized to 0 by default, according to JVM specs
232  modePassengerVolumes.put(passengerMode2modePax.getKey(), passengerVolumes);
233  }
234  passengerVolumes[timeslot] += passengerMode2modePax.getValue();
235  }
236  }
237 
238  if (this.observeVehicleTypes) {
239  Id<VehicleType> vehicleType = vehicleData.vehicleTypeId;
240 
241  IdMap<VehicleType, int[]> typeVehicleVolumes = this.linkVehicleVolumesPerVehicleType.
242  computeIfAbsent(event.getLinkId(), k -> new IdMap<>(VehicleType.class));
243  int[] vehicleVolumes = typeVehicleVolumes.get(vehicleType);
244  if (vehicleVolumes == null) {
245  vehicleVolumes = new int[this.maxSlotIndex + 1]; // initialized to 0 by default, according to JVM specs
246  typeVehicleVolumes.put(vehicleType, vehicleVolumes);
247  }
248  vehicleVolumes[timeslot]++;
249 
250  IdMap<VehicleType, int[]> modePassengerVolumes = this.linkPaxVolumesPerVehicleType.
251  computeIfAbsent(event.getLinkId(), k -> new IdMap<>(VehicleType.class));
252  int[] passengerVolumes = modePassengerVolumes.get(vehicleType);
253  if (passengerVolumes == null) {
254  passengerVolumes = new int[this.maxSlotIndex + 1]; // initialized to 0 by default, according to JVM specs
255  modePassengerVolumes.put(vehicleType, passengerVolumes);
256  }
257  passengerVolumes[timeslot] += currentPaxAllPassengerModes;
258  }
259  }
260 
261  @Override
263  String passengerMode = person2passengerMode.get(event.getPersonId());
264  Map<String, Integer> passengersByMode = this.vehiclesData.get(event.getVehicleId()).passengerMode2currentPax;
265  passengersByMode.put(passengerMode, passengersByMode.get(passengerMode) - 1);
266  if (vehiclesAboutToLeave.contains(event.getVehicleId())) {
267  // drt vehicles have a VehicleLeavesTrafficEvent at each stop, then alights the driver and after that
268  // the remaining passengers
269  // -> only remove vehicle when empty
270  int totalPax = 0;
271  for (int i: passengersByMode.values()) {
272  totalPax += i;
273  }
274  if (totalPax == 0) {
275  this.vehiclesData.remove(event.getVehicleId());
276  vehiclesAboutToLeave.remove(event.getVehicleId());
277  }
278  }
279  }
280 
281  @Override
283  this.vehiclesAboutToLeave.add(event.getVehicleId());
284  VehicleData vehicleData = this.vehiclesData.get(event.getVehicleId());
285  this.vehicleType2timeOnNetwork.put(vehicleData.vehicleTypeId,
286  this.vehicleType2timeOnNetwork.getOrDefault(vehicleData.vehicleTypeId, 0.0) +
287  event.getTime() - vehicleData.enteredNetworkTime);
288  }
289 
290  private int getTimeSlotIndex(final double time) {
291  if (time > this.maxTime) {
292  return this.maxSlotIndex;
293  }
294  return ((int)time / this.timeBinSize);
295  }
296 
302  int[] getVehicleVolumesForLink(final Id<Link> linkId) {
303  return this.linkVehicleVolumes.get(linkId);
304  }
305 
312  int[] getVehicleVolumesForLinkPerNetworkMode(final Id<Link> linkId, String networkMode) {
313  if (observeNetworkModes) {
314  Map<String, int[]> modeVolumes = this.linkVehicleVolumesPerNetworkMode.get(linkId);
315  if (modeVolumes != null) return modeVolumes.get(networkMode);
316  }
317  return null;
318  }
319 
326  int[] getVehicleVolumesForLinkPerPassengerMode(final Id<Link> linkId, String passengerMode) {
327  if (observePassengerModes) {
328  Map<String, int[]> modeVolumes = this.linkVehicleVolumesPerPassengerMode.get(linkId);
329  if (modeVolumes != null) return modeVolumes.get(passengerMode);
330  }
331  return null;
332  }
333 
340  int[] getVehicleVolumesForLinkPerVehicleType(final Id<Link> linkId, Id<VehicleType> vehicleType) {
341  if (observeVehicleTypes) {
342  IdMap<VehicleType, int[]> typeVolumes = this.linkVehicleVolumesPerVehicleType.get(linkId);
343  if (typeVolumes != null) return typeVolumes.get(vehicleType);
344  }
345  return null;
346  }
347 
353  public int[] getPaxVolumesForLink(final Id<Link> linkId) {
354  return this.linkPaxVolumes.get(linkId);
355  }
356 
363  int[] getPaxVolumesForLinkPerNetworkMode(final Id<Link> linkId, String networkMode) {
364  if (observeNetworkModes) {
365  Map<String, int[]> modeVolumes = this.linkPaxVolumesPerNetworkMode.get(linkId);
366  if (modeVolumes != null) return modeVolumes.get(networkMode);
367  }
368  return null;
369  }
370 
377  int[] getPaxVolumesForLinkPerPassengerMode(final Id<Link> linkId, String passengerMode) {
378  if (observePassengerModes) {
379  Map<String, int[]> modeVolumes = this.linkPaxVolumesPerPassengerMode.get(linkId);
380  if (modeVolumes != null) return modeVolumes.get(passengerMode);
381  }
382  return null;
383  }
384 
391  int[] getPaxVolumesForLinkPerVehicleType(final Id<Link> linkId, Id<VehicleType> vehicleType) {
392  if (observeVehicleTypes) {
393  IdMap<VehicleType, int[]> typeVolumes = this.linkPaxVolumesPerVehicleType.get(linkId);
394  if (typeVolumes != null) return typeVolumes.get(vehicleType);
395  }
396  return null;
397  }
398 
404  int getVolumesArraySize() {
405  return this.maxSlotIndex + 1;
406  }
407 
408  /*
409  * This procedure is only working if (hour % timeBinSize == 0)
410  *
411  * Example: 15 minutes bins
412  * ___________________
413  * | 0 | 1 | 2 | 3 |
414  * |____|____|____|____|
415  * 0 900 1800 2700 3600
416  ___________________
417  * | hour 0 |
418  * |___________________|
419  * 0 3600
420  *
421  * hour 0 = bins 0,1,2,3
422  * hour 1 = bins 4,5,6,7
423  * ...
424  *
425  * getTimeSlotIndex = (int)time / this.timeBinSize => jumps at 3600.0!
426  * Thus, starting time = (hour = 0) * 3600.0
427  */
428  int[] getVolumePerHourFromTimeBinArray(int[] volumesForLink) {
429  if (3600.0 % this.timeBinSize != 0) log.error("Volumes per hour and per link probably not correct!");
430 
431  int[] volumes = new int[30];
432  if (volumesForLink == null) return volumes;
433 
434  int slotsPerHour = (int)(3600.0 / this.timeBinSize);
435  for (int hour = 0; hour < 30; hour++) {
436  double time = hour * 3600.0;
437  for (int i = 0; i < slotsPerHour; i++) {
438  volumes[hour] += volumesForLink[this.getTimeSlotIndex(time)];
439  time += this.timeBinSize;
440  }
441  }
442  return volumes;
443  }
444 
445  int getVolumePerDayFromTimeBinArray(int[] volumesForLink) {
446  int volumePerDay= 0;
447  for (int i = 0; i < this.maxSlotIndex; i++) {
448  volumePerDay += volumesForLink[i];
449  }
450  return volumePerDay;
451  }
452 
453  Map<Id<VehicleType>, Integer> getVehicleType2numberSeen() {
454  return Collections.unmodifiableMap(vehicleType2numberSeen);
455  }
456 
457  Map<Id<VehicleType>, Double> getVehicleType2timeOnNetwork() {
458  return Collections.unmodifiableMap(vehicleType2timeOnNetwork);
459  }
460 
464  Set<String> getNetworkModes() {
465  Set<String> modes = new TreeSet<>();
466 
467  for (Map<String, int[]> map : this.linkVehicleVolumesPerNetworkMode.values()) {
468  modes.addAll(map.keySet());
469  }
470 
471  return modes;
472  }
473 
477  Set<String> getPassengerModes() {
478  Set<String> modes = new TreeSet<>();
479 
480  for (Map<String, int[]> map : this.linkVehicleVolumesPerPassengerMode.values()) {
481  modes.addAll(map.keySet());
482  }
483 
484  return modes;
485  }
486 
490  IdSet<VehicleType> getVehicleTypes() {
491  IdSet<VehicleType> vehicleTypes = new IdSet<>(VehicleType.class);
492 
493  for (IdMap<VehicleType, int[]> map : this.linkVehicleVolumesPerVehicleType.values()) {
494  vehicleTypes.addAll(map.keySet());
495  }
496 
497  return vehicleTypes;
498  }
499 
503  Set<Id<Link>> getLinkIds() {
504  return this.linkVehicleVolumes.keySet();
505  }
506 
507  int getNumberOfHours() {
508  return maxSlotIndex * timeBinSize / 3600;
509  }
510 
511  @Override
512  public void reset(final int iteration) {
513  this.linkVehicleVolumes.clear();
514  this.linkPaxVolumes.clear();
515  this.person2passengerMode.clear();
516  this.vehiclesAboutToLeave.clear();
517  this.vehiclesData.clear();
518  this.vehicleIdsSeen.clear();
519  this.vehicleType2numberSeen.clear();
520  this.vehicleType2timeOnNetwork.clear();
521 
522  if (observeNetworkModes) {
523  this.linkVehicleVolumesPerNetworkMode.clear();
524  this.linkPaxVolumesPerNetworkMode.clear();
525  }
526  if (this.observePassengerModes) {
527  this.linkVehicleVolumesPerPassengerMode.clear();
528  this.linkPaxVolumesPerPassengerMode.clear();
529  }
530  if (this.observeVehicleTypes) {
531  this.linkVehicleVolumesPerVehicleType.clear();
532  this.linkPaxVolumesPerVehicleType.clear();
533  }
534  }
535 
539  private static class VehicleData {
540  private final Id<Vehicle> vehicleId;
542  private final Id<Person> driverId;
543  private String networkMode;
544  private Map<String, Integer> passengerMode2currentPax = new HashMap<>();
545  private double enteredNetworkTime;
546 
547  public VehicleData(Id<Vehicle> vehicleId, Id<VehicleType> vehicleTypeId, Id<Person> driverId) {
548  this.vehicleId = vehicleId;
549  this.vehicleTypeId = vehicleTypeId;
550  this.driverId = driverId;
551  }
552  }
553 }
Set< Id< T > > keySet()
Definition: IdMap.java:189
boolean contains(Object key)
Definition: IdSet.java:34
Collection< V > values()
Definition: IdMap.java:204
static< T > Id< T > create(final long key, final Class< T > type)
Definition: Id.java:68
boolean remove(Object key)
Definition: IdSet.java:97
boolean addAll(Collection<? extends Id< T >> c)
Definition: IdSet.java:132
final Id< VehicleType > getId()
boolean add(Id< T > value)
Definition: IdSet.java:202
Map< Id< Vehicle >, Vehicle > getVehicles()
V put(Id< T > key, V value)
Definition: IdMap.java:141