MATSIM
PtStop2StopAnalysis.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * *
4  * *********************************************************************** *
5  * *
6  * copyright : (C) 2021 by the members listed in the COPYING, *
7  * LICENSE and WARRANTY file. *
8  * email : info at matsim dot org *
9  * *
10  * *********************************************************************** *
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * See also COPYING, LICENSE and WARRANTY file *
17  * *
18  * *********************************************************************** */
19 
20 package org.matsim.analysis.pt.stop2stop;
21 
22 import org.apache.commons.csv.CSVFormat;
23 import org.apache.commons.csv.CSVPrinter;
24 import org.apache.logging.log4j.LogManager;
25 import org.apache.logging.log4j.Logger;
26 import org.matsim.api.core.v01.Id;
27 import org.matsim.api.core.v01.events.*;
35 import org.matsim.core.utils.io.IOUtils;
40 import org.matsim.vehicles.Vehicle;
43 
44 import java.io.IOException;
45 import java.net.URL;
46 import java.nio.file.Path;
47 import java.util.*;
48 import java.util.stream.Collectors;
49 
71 
72  private final Vehicles transitVehicles; // for vehicle capacity
73  private final Map<Id<Vehicle>, PtVehicleData> transitVehicle2temporaryVehicleData = new HashMap<>();
74  private final List<Stop2StopEntry> stop2StopEntriesForEachDeparture; // the output
75  private final double sampleUpscaleFactor;
76  private static final Logger log = LogManager.getLogger(PtStop2StopAnalysis.class);
77 
82  public PtStop2StopAnalysis(Vehicles transitVehicles, double sampleUpscaleFactor) {
83  this.transitVehicles = transitVehicles;
84  this.sampleUpscaleFactor = sampleUpscaleFactor;
85  // set initial capacity to rough estimate of 30 entries by vehicle (should be sufficient)
86  stop2StopEntriesForEachDeparture = new ArrayList<>(transitVehicles.getVehicles().size() * 30);
87  }
88 
92  @Override
94  transitVehicle2temporaryVehicleData.put(event.getVehicleId(), new PtVehicleData(event.getTransitLineId(),
95  event.getTransitRouteId(), event.getDepartureId(), event.getDriverId(),
96  transitVehicles.getVehicles().get(event.getVehicleId()).getType()));
97  }
98 
102  @Override
104  PtVehicleData ptVehicleData = transitVehicle2temporaryVehicleData.get(event.getVehicleId());
105  if (ptVehicleData == null) {
106  log.error("Encountered a VehicleArrivesAtFacilityEvent without a previous TransitDriverStartsEvent for vehicle {} at facility {} at time {}. This should not happen, this analysis might fail subsequently.", event.getVehicleId(), event.getFacilityId(), event.getTime());
107  } else {
108  ptVehicleData.lastVehicleArrivesAtFacilityEvent = event;
109  }
110  }
111 
115  @Override
117  PtVehicleData ptVehicleData = transitVehicle2temporaryVehicleData.get(event.getVehicleId());
118  if (ptVehicleData == null) {
119  log.error("Encountered a VehicleDepartsAtFacilityEvent without a previous TransitDriverStartsEvent for vehicle {} at facility {} at time {}. This should not happen, this analysis might fail subsequently.", event.getVehicleId(), event.getFacilityId(), event.getTime());
120  } else {
121  // produce output entry
122  stop2StopEntriesForEachDeparture.add(new Stop2StopEntry(ptVehicleData.transitLineId,
123  ptVehicleData.transitRouteId, ptVehicleData.departureId, event.getFacilityId(),
124  ptVehicleData.stopSequenceCounter, ptVehicleData.lastStopId,
126  ptVehicleData.lastVehicleArrivesAtFacilityEvent.getDelay(), event.getTime() - event.getDelay(),
127  event.getDelay(), ptVehicleData.currentPax * sampleUpscaleFactor, ptVehicleData.totalVehicleCapacity,
128  ptVehicleData.alightings * sampleUpscaleFactor, ptVehicleData.boardings * sampleUpscaleFactor,
129  List.copyOf(ptVehicleData.linksTravelledOnSincePreviousStop)));
130  // calculate number of passengers at departure
131  // (the Stop2StopEntry before needed the number of passengers at arrival so do not move this up!)
132  ptVehicleData.currentPax = ptVehicleData.currentPax - ptVehicleData.alightings + ptVehicleData.boardings;
133  // reset counters
134  ptVehicleData.alightings = 0;
135  ptVehicleData.boardings = 0;
136  ptVehicleData.lastVehicleArrivesAtFacilityEvent = null;
137  ptVehicleData.linksTravelledOnSincePreviousStop.clear();
138  // move forward stop
139  ptVehicleData.lastStopId = event.getFacilityId();
140  ptVehicleData.stopSequenceCounter++;
141  }
142  }
143 
147  @Override
149  PtVehicleData ptVehicleData = transitVehicle2temporaryVehicleData.get(event.getVehicleId());
150  // If this is a pt vehicle, we should have a non-null ptVehicleData object
151  // && do not count transitVehicle driver
152  if (ptVehicleData != null && event.getPersonId() != ptVehicleData.driverId) {
153  ptVehicleData.boardings++;
154  }
155  }
156 
160  @Override
162  PtVehicleData ptVehicleData = transitVehicle2temporaryVehicleData.get(event.getVehicleId());
163  // If this is a pt vehicle, we should have a non-null ptVehicleData object
164  // && do not count transitVehicle driver
165  if (ptVehicleData != null) {
166  if (event.getPersonId() == ptVehicleData.driverId) {
167  // end of service, remove from vehicle list
168  // this should happen after the terminus stop was left, so no need to save any data
169  transitVehicle2temporaryVehicleData.remove(event.getVehicleId());
170  } else {
171  // a real passenger alighting
172  ptVehicleData.alightings++;
173  }
174  }
175  }
176 
177  @Override
178  public void reset(int iteration) {
179  if(!transitVehicle2temporaryVehicleData.isEmpty()) {
180  log.warn("{} transit vehicles did not finish service in the last iteration.", transitVehicle2temporaryVehicleData.size());
181  }
182  transitVehicle2temporaryVehicleData.clear();
183  stop2StopEntriesForEachDeparture.clear();
184  }
185 
189  @Override
191  PtVehicleData ptVehicleData = transitVehicle2temporaryVehicleData.get(event.getVehicleId());
192  // If this is a pt vehicle, we should have a non-null ptVehicleData object
193  if (ptVehicleData != null) {
194  ptVehicleData.linksTravelledOnSincePreviousStop.add(event.getLinkId());
195  }
196  }
197 
201  @Override
202  public void handleEvent(LinkEnterEvent event) {
203  PtVehicleData ptVehicleData = transitVehicle2temporaryVehicleData.get(event.getVehicleId());
204  // If this is a pt vehicle, we should have a non-null ptVehicleData object
205  if (ptVehicleData != null) {
206  ptVehicleData.linksTravelledOnSincePreviousStop.add(event.getLinkId());
207  }
208  }
209 
213  private static class PtVehicleData {
216  private final Id<Departure> departureId;
217  private final Id<Person> driverId;
218  private final double totalVehicleCapacity; // use double for possible future capacity scaling issues
219  private int stopSequenceCounter = 0;
222  private int currentPax = 0;
223  private int alightings = 0;
224  private int boardings = 0;
225  private final List<Id<Link>> linksTravelledOnSincePreviousStop = new ArrayList<>(8);
226 
227  private PtVehicleData(Id<TransitLine> transitLineId, Id<TransitRoute> transitRouteId,
228  Id<Departure> departureId, Id<Person> driverId, VehicleType vehicleType) {
229  this.transitLineId = transitLineId;
230  this.transitRouteId = transitRouteId;
231  this.departureId = departureId;
232  this.driverId = driverId;
233  this.totalVehicleCapacity = vehicleType.getCapacity().getSeats() + vehicleType.getCapacity().getStandingRoom();
234  }
235  }
236 
243  int stopSequence, Id<TransitStopFacility> stopPreviousId, double arrivalTimeScheduled, double arrivalDelay,
244  double departureTimeScheduled, double departureDelay, double passengersAtArrival, double totalVehicleCapacity,
245  double passengersAlighting, double passengersBoarding, List<Id<Link>> linkIdsSincePreviousStop) {}
246 
247  static final String[] HEADER = {"transitLine", "transitRoute", "departure", "stop", "stopSequence",
248  "stopPrevious", "arrivalTimeScheduled", "arrivalDelay", "departureTimeScheduled", "departureDelay",
249  "passengersAtArrival", "totalVehicleCapacity", "passengersAlighting", "passengersBoarding",
250  "linkIdsSincePreviousStop"};
251 
252  static Comparator<Stop2StopEntry> stop2StopEntryByTransitLineComparator =
253  Comparator.nullsLast(Comparator.comparing(Stop2StopEntry::transitLineId));
254  static Comparator<Stop2StopEntry> stop2StopEntryByTransitRouteComparator =
255  Comparator.nullsLast(Comparator.comparing(Stop2StopEntry::transitRouteId));
256  static Comparator<Stop2StopEntry> stop2StopEntryByDepartureComparator =
257  Comparator.nullsLast(Comparator.comparing(Stop2StopEntry::departureId));
258  static Comparator<Stop2StopEntry> stop2StopEntryByStopSequenceComparator =
259  Comparator.nullsLast(Comparator.comparing(Stop2StopEntry::stopSequence));
260 
261  public void writeStop2StopEntriesByDepartureCsv(String fileName, String columnSeparator, String listSeparatorInsideColumn) {
262  writeStop2StopEntriesByDepartureCsv(IOUtils.getFileUrl(fileName), columnSeparator, listSeparatorInsideColumn);
263  }
264 
265  public void writeStop2StopEntriesByDepartureCsv(Path path, String columnSeparator, String listSeparatorInsideColumn) {
266  writeStop2StopEntriesByDepartureCsv(IOUtils.getFileUrl(path.toString()), columnSeparator, listSeparatorInsideColumn);
267  }
268 
269  public void writeStop2StopEntriesByDepartureCsv(URL url, String columnSeparator, String listSeparatorInsideColumn) {
270  stop2StopEntriesForEachDeparture.sort(stop2StopEntryByTransitLineComparator.
271  thenComparing(stop2StopEntryByTransitRouteComparator).
272  thenComparing(stop2StopEntryByDepartureComparator).
273  thenComparing(stop2StopEntryByStopSequenceComparator));
274  try (CSVPrinter printer = new CSVPrinter(IOUtils.getBufferedWriter(url),
275  CSVFormat.Builder.create()
276  .setDelimiter(columnSeparator)
277  .setHeader(HEADER)
278  .build())
279  ) {
280  for (Stop2StopEntry entry : stop2StopEntriesForEachDeparture) {
281  printer.print(entry.transitLineId);
282  printer.print(entry.transitRouteId);
283  printer.print(entry.departureId);
284  printer.print(entry.stopId);
285  printer.print(entry.stopSequence);
286  printer.print(entry.stopPreviousId);
287  printer.print(entry.arrivalTimeScheduled);
288  printer.print(entry.arrivalDelay);
289  printer.print(entry.departureTimeScheduled);
290  printer.print(entry.departureDelay);
291  printer.print(entry.passengersAtArrival);
292  printer.print(entry.totalVehicleCapacity);
293  printer.print(entry.passengersAlighting);
294  printer.print(entry.passengersBoarding);
295  printer.print(entry.linkIdsSincePreviousStop.stream().map(Object::toString).collect(Collectors.joining(listSeparatorInsideColumn)));
296  printer.println();
297  }
298  } catch (IOException e) {
299  log.error(e);
300  }
301  }
302 
303  List<Stop2StopEntry> getStop2StopEntriesByDeparture () {
304  return List.copyOf(stop2StopEntriesForEachDeparture);
305  }
306 }
PtVehicleData(Id< TransitLine > transitLineId, Id< TransitRoute > transitRouteId, Id< Departure > departureId, Id< Person > driverId, VehicleType vehicleType)
void handleEvent(VehicleDepartsAtFacilityEvent event)
static URL getFileUrl(String filename)
Definition: IOUtils.java:501
void writeStop2StopEntriesByDepartureCsv(Path path, String columnSeparator, String listSeparatorInsideColumn)
static BufferedWriter getBufferedWriter(URL url, Charset charset, boolean append)
Definition: IOUtils.java:390
PtStop2StopAnalysis(Vehicles transitVehicles, double sampleUpscaleFactor)
final VehicleCapacity getCapacity()
void handleEvent(VehicleArrivesAtFacilityEvent event)
void writeStop2StopEntriesByDepartureCsv(String fileName, String columnSeparator, String listSeparatorInsideColumn)
Map< Id< Vehicle >, Vehicle > getVehicles()
void writeStop2StopEntriesByDepartureCsv(URL url, String columnSeparator, String listSeparatorInsideColumn)
final Map< Id< Vehicle >, PtVehicleData > transitVehicle2temporaryVehicleData