MATSIM
EventsToLegs.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * *
4  * *********************************************************************** *
5  * *
6  * copyright : (C) 2011 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.core.scoring;
21 
22 import com.google.inject.Inject;
23 import org.apache.logging.log4j.LogManager;
24 import org.matsim.api.core.v01.Id;
25 import org.matsim.api.core.v01.IdMap;
26 import org.matsim.api.core.v01.Scenario;
27 import org.matsim.api.core.v01.events.*;
38 import org.matsim.core.gbl.Gbl;
48 import org.matsim.vehicles.Vehicle;
49 
50 import java.util.ArrayList;
51 import java.util.List;
52 import java.util.Map;
53 
65 public final class EventsToLegs
69 
70  public static final String ENTER_VEHICLE_TIME_ATTRIBUTE_NAME = "enterVehicleTime";
71  public static final String VEHICLE_ID_ATTRIBUTE_NAME = "vehicleId";
72 
73  private record PendingTransitTravel(Id<Vehicle> vehicleId, Id<TransitStopFacility> accessStop, double boardingTime) {
74  }
75 
76  private static class LineAndRoute {
77  final Id<TransitLine> transitLineId;
78  final Id<TransitRoute> transitRouteId;
79  final Id<Person> driverId;
80  Id<TransitStopFacility> lastFacilityId;
81 
82  LineAndRoute(Id<TransitLine> transitLineId, Id<TransitRoute> transitRouteId, Id<Person> driverId) {
83  this.transitLineId = transitLineId;
84  this.transitRouteId = transitRouteId;
85  this.driverId = driverId;
86  }
87 
88  @Override
89  public String toString() {
90  return "["
91  + super.toString()
92  + " transitLineId="
93  + transitLineId
94  + " transitRouteId="
95  + transitRouteId
96  + " driverId="
97  + driverId
98  + " lastFacilityId="
99  + lastFacilityId
100  + "]";
101  }
102  }
103 
104  private static class PendingVehicleTravel {
105  private final int accessLinkIdx;
106  private final VehicleRoute route;
108 
109  private PendingVehicleTravel(VehicleRoute route, int accessLinkIdx) {
110  this.route = route;
111  this.accessLinkIdx = accessLinkIdx;
112  }
113  }
114 
115  private static class VehicleRoute {
116  private final List<Id<Link>> links = new ArrayList<>();
117  private final List<PendingVehicleTravel> newVehicleTravels = new ArrayList<>();
119  }
120 
121  public interface LegHandler {
122  void handleLeg(PersonExperiencedLeg leg);
123  }
124 
125  private final Network network;
127 
128  @Inject(optional = true)
129  public void setTransitSchedule(TransitSchedule transitSchedule) {
130  this.transitSchedule = transitSchedule;
131  }
132 
133  private final Map<Id<Person>, Leg> legs = new IdMap<>(Person.class);
134  private final Map<Id<Person>, List<Id<Link>>> experiencedRoutes = new IdMap<>(Person.class);
135  private final Map<Id<Person>, Double> relPosOnDepartureLinkPerPerson = new IdMap<>(Person.class);
136  private final Map<Id<Person>, Double> relPosOnArrivalLinkPerPerson = new IdMap<>(Person.class);
137 
138  private final Map<Id<Person>, TeleportationArrivalEvent> routelessTravels = new IdMap<>(Person.class);
139  private final Map<Id<Person>, PendingTransitTravel> transitTravels = new IdMap<>(Person.class);
140  private final Map<Id<Person>, PendingVehicleTravel> vehicleTravels = new IdMap<>(Person.class);
141 
142  private final Map<Id<Vehicle>, LineAndRoute> transitVehicle2currentRoute = new IdMap<>(Vehicle.class);
143  private final Map<Id<Vehicle>, VehicleRoute> vehicle2route = new IdMap<>(Vehicle.class);
144 
145  private final List<LegHandler> legHandlers = new ArrayList<>();
146 
147  public EventsToLegs(Scenario scenario) {
148  this.network = scenario.getNetwork();
149  if (scenario.getConfig().transit().isUseTransit()) {
150  this.transitSchedule = scenario.getTransitSchedule();
151  }
152  }
153 
154  @Inject
155  EventsToLegs(Network network) {
156  this.network = network;
157  }
158 
159  @Override
160  public void reset(int iteration) {
161  legs.clear();
162  experiencedRoutes.clear();
163 
164  transitTravels.clear();
165  vehicleTravels.clear();
166  routelessTravels.clear();
167 
168  transitVehicle2currentRoute.clear();
169  vehicle2route.clear();
170 
171  relPosOnDepartureLinkPerPerson.clear();
172  relPosOnArrivalLinkPerPerson.clear();
173  }
174 
175  @Override
176  public void handleEvent(PersonDepartureEvent event) {
177  Leg leg = PopulationUtils.createLeg(event.getLegMode());
179  leg.setDepartureTime(event.getTime());
180  legs.put(event.getPersonId(), leg);
181 
182  List<Id<Link>> route = new ArrayList<>();
183  route.add(event.getLinkId());
184  experiencedRoutes.put(event.getPersonId(), route);
185  }
186 
187  @Override
189  Leg leg = legs.get(event.getPersonId());
190  leg.getAttributes().putAttribute(ENTER_VEHICLE_TIME_ATTRIBUTE_NAME, event.getTime());
191  leg.getAttributes().putAttribute(VEHICLE_ID_ATTRIBUTE_NAME, event.getVehicleId());
192  LineAndRoute lineAndRoute = transitVehicle2currentRoute.get(event.getVehicleId());
193  if (lineAndRoute != null) {
194  if (!event.getPersonId().equals(lineAndRoute.driverId)) {
195  // transit drivers are not considered to travel by transit
196  transitTravels.put(event.getPersonId(),
197  new PendingTransitTravel(event.getVehicleId(), lineAndRoute.lastFacilityId, event.getTime()));
198  }
199  } else {
200  VehicleRoute route = vehicle2route.computeIfAbsent(event.getVehicleId(), vehicleId -> new VehicleRoute());
201  int currentLinkIdx = Math.max(0, route.links.size() - 1);
202  PendingVehicleTravel vehicleTravel = new PendingVehicleTravel(route, currentLinkIdx);
203  vehicleTravels.put(event.getPersonId(), vehicleTravel);
204  route.newVehicleTravels.add(vehicleTravel);
205  }
206  }
207 
208  @Override
210  VehicleRoute route = vehicle2route.get(event.getVehicleId());
211  if (route != null) {
212  if (route.links.isEmpty()) {
213  route.links.add(event.getLinkId());
214  } else {
215  // in case vehicle was teleported (TODO assuming teleportation is not possible with people on board??)
216  route.links.set(route.links.size() - 1, event.getLinkId());
217  }
218 
219  //update relativePositionOnDepartureLink for each new passenger and the driver
220  route.newVehicleTravels.forEach(
221  vehicleTravel -> vehicleTravel.relativePositionOnDepartureLink = event.getRelativePositionOnLink());
222  route.newVehicleTravels.clear();
223  }
224  }
225 
226  @Override
227  public void handleEvent(LinkEnterEvent event) {
228  VehicleRoute route = vehicle2route.get(event.getVehicleId());
229  if (route != null) {
230  route.links.add(event.getLinkId());
231  }
232  }
233 
234  @Override
236  VehicleRoute route = vehicle2route.get(event.getVehicleId());
237  if (route != null) {
238  route.relativePositionOnLastArrivalLink = event.getRelativePositionOnLink();
239  }
240  }
241 
242  @Override
244  LineAndRoute lineAndRoute = transitVehicle2currentRoute.get(event.getVehicleId());
245  if (lineAndRoute != null) {
246  lineAndRoute.lastFacilityId = event.getFacilityId();
247  }
248  }
249 
250  @Override
251  public void handleEvent(TeleportationArrivalEvent travelEvent) {
252  routelessTravels.put(travelEvent.getPersonId(), travelEvent);
253  }
254 
255  @Override
256  public void handleEvent(PersonArrivalEvent event) {
257  Leg leg = legs.get(event.getPersonId());
258  leg.setTravelTime(event.getTime() - leg.getDepartureTime().seconds());
259  double travelTime = leg.getDepartureTime().seconds()
260  + leg.getTravelTime().seconds() - leg.getDepartureTime().seconds();
261  leg.setTravelTime(travelTime);
262  List<Id<Link>> experiencedRoute = experiencedRoutes.get(event.getPersonId());
263  assert !experiencedRoute.isEmpty();
264  PendingTransitTravel pendingTransitTravel;
265  PendingVehicleTravel pendingVehicleTravel;
266  if (experiencedRoute.size() > 1) { // different links processed
267  NetworkRoute networkRoute = RouteUtils.createNetworkRoute(experiencedRoute );
268  networkRoute.setTravelTime(travelTime);
269 
270  /* use the relative position of vehicle enter/leave traffic events on first/last links
271  * to calculate the correct route distance including the first/last link.
272  * (see MATSIM-227) tt feb'16
273  */
274  double relPosOnDepartureLink = relPosOnDepartureLinkPerPerson.get(event.getPersonId());
275  Double relPosOnArrivalLink = relPosOnArrivalLinkPerPerson.get(event.getPersonId());
276  Gbl.assertNotNull(relPosOnArrivalLink);
277  networkRoute.setDistance(
278  RouteUtils.calcDistance(networkRoute, relPosOnDepartureLink, relPosOnArrivalLink, network));
279 
280  leg.setRoute(networkRoute);
281  } else if ((pendingTransitTravel = transitTravels.remove(event.getPersonId())) != null) {
282  // i.e. experiencedRoute.size()==1 && pending transit travel (= person has entered a vehicle)
283 
284  final LineAndRoute lineAndRoute = transitVehicle2currentRoute.get(pendingTransitTravel.vehicleId);
285  assert lineAndRoute != null;
286 
287  final TransitStopFacility accessFacility = transitSchedule.getFacilities()
288  .get(pendingTransitTravel.accessStop);
289  assert accessFacility != null;
290 
291  final TransitLine line = transitSchedule.getTransitLines().get(lineAndRoute.transitLineId);
292  assert line != null;
293 
294  final TransitRoute route = line.getRoutes().get(lineAndRoute.transitRouteId);
295  assert route != null;
296 
297  final Id<TransitStopFacility> lastFacilityId = lineAndRoute.lastFacilityId;
298  if (lastFacilityId == null) {
299  LogManager.getLogger(this.getClass()).warn("breakpoint");
300  }
301  assert lastFacilityId != null;
302 
303  final TransitStopFacility egressFacility = transitSchedule.getFacilities().get(lastFacilityId);
304  assert egressFacility != null;
305 
306  DefaultTransitPassengerRoute passengerRoute = new DefaultTransitPassengerRoute(accessFacility, line, route, egressFacility);
307  passengerRoute.setBoardingTime(pendingTransitTravel.boardingTime);
308  passengerRoute.setTravelTime(travelTime);
309  passengerRoute.setDistance(RouteUtils.calcDistance(passengerRoute, transitSchedule, network));
310  leg.setRoute(passengerRoute);
311  } else if ((pendingVehicleTravel = vehicleTravels.remove(event.getPersonId())) != null) {
312  VehicleRoute vehicleRoute = pendingVehicleTravel.route;
313  List<Id<Link>> traveledLinks = vehicleRoute.links.subList(pendingVehicleTravel.accessLinkIdx,
314  vehicleRoute.links.size());
315  Route route;
316  if (traveledLinks.isEmpty()) {//special case: enter and leave vehicle without entering traffic
317  route = RouteUtils.createGenericRouteImpl(experiencedRoute.getFirst(), event.getLinkId());
318  route.setDistance(0.0);
319  } else {
320  route = RouteUtils.createNetworkRoute(traveledLinks );
321  double relPosOnDepartureLink = pendingVehicleTravel.relativePositionOnDepartureLink;
322  double relPosOnArrivalLink = vehicleRoute.relativePositionOnLastArrivalLink;
323  route.setDistance(
324  RouteUtils.calcDistance((NetworkRoute)route, relPosOnDepartureLink, relPosOnArrivalLink,
325  network));
326  }
327  route.setTravelTime(travelTime);
328  leg.setRoute(route);
329 
330  } else {
331  // i.e. experiencedRoute.size()==1 and no pendingTransitTravel
332  TeleportationArrivalEvent travelEvent = routelessTravels.remove(event.getPersonId());
333  Route genericRoute = RouteUtils.createGenericRouteImpl(experiencedRoute.getFirst(), event.getLinkId());
334  genericRoute.setTravelTime(travelTime);
335  if (travelEvent != null) {
336  genericRoute.setDistance(travelEvent.getDistance());
337  } else {
338  genericRoute.setDistance(0.0);
339  }
340  leg.setRoute(genericRoute);
341  }
342 
343  PersonExperiencedLeg personExperiencedLeg = new PersonExperiencedLeg(event.getPersonId(), leg);
344  for (LegHandler legHandler : legHandlers) {
345  legHandler.handleLeg(personExperiencedLeg);
346  }
347  }
348 
349  @Override
351  LineAndRoute lineAndRoute = new LineAndRoute(event.getTransitLineId(), event.getTransitRouteId(),
352  event.getDriverId());
353  transitVehicle2currentRoute.put(event.getVehicleId(), lineAndRoute);
354  }
355 
356  public void addLegHandler(LegHandler legHandler) {
357  this.legHandlers.add(legHandler);
358  }
359 }
final Map< Id< Person >, PendingVehicleTravel > vehicleTravels
void addLegHandler(LegHandler legHandler)
Map< Id< TransitRoute >, TransitRoute > getRoutes()
void setDistance(final double distance)
void handleEvent(PersonArrivalEvent event)
final Map< Id< Vehicle >, VehicleRoute > vehicle2route
Map< Id< TransitStopFacility >, TransitStopFacility > getFacilities()
final Map< Id< Person >, TeleportationArrivalEvent > routelessTravels
static Route createGenericRouteImpl(Id< Link > startLinkId, Id< Link > endLinkId)
final void setTravelTime(final double travTime)
PendingVehicleTravel(VehicleRoute route, int accessLinkIdx)
void handleEvent(TeleportationArrivalEvent travelEvent)
final Map< Id< Person >, Leg > legs
final List< PendingVehicleTravel > newVehicleTravels
void setDepartureTime(final double seconds)
void handleEvent(PersonDepartureEvent event)
void setTransitSchedule(TransitSchedule transitSchedule)
static final String ENTER_VEHICLE_TIME_ATTRIBUTE_NAME
void handleEvent(TransitDriverStartsEvent event)
final List< LegHandler > legHandlers
final Map< Id< Person >, List< Id< Link > > > experiencedRoutes
void handleEvent(VehicleLeavesTrafficEvent event)
void handleEvent(VehicleEntersTrafficEvent event)
void handleEvent(VehicleArrivesAtFacilityEvent event)
static final String VEHICLE_ID_ATTRIBUTE_NAME
final Map< Id< Person >, PendingTransitTravel > transitTravels
static void setRoutingMode(Leg leg, String mode)
final Map< Id< Person >, Double > relPosOnArrivalLinkPerPerson
record PendingTransitTravel(Id< Vehicle > vehicleId, Id< TransitStopFacility > accessStop, double boardingTime)
void handleEvent(PersonEntersVehicleEvent event)
TransitConfigGroup transit()
Definition: Config.java:451
static Leg createLeg(String transportMode)
Object putAttribute(final String attribute, final Object value)
static NetworkRoute createNetworkRoute(List< Id< Link >> routeLinkIds, Network network)
static void assertNotNull(Object obj)
Definition: Gbl.java:212
final Map< Id< Person >, Double > relPosOnDepartureLinkPerPerson
static double calcDistance(final NetworkRoute networkRoute, final double relPosOnDepartureLink, final double relPosOnArrivalLink, final Network network)
void setTravelTime(final double seconds)
final Map< Id< Vehicle >, LineAndRoute > transitVehicle2currentRoute
TransitSchedule getTransitSchedule()
void handleEvent(LinkEnterEvent event)
Map< Id< TransitLine >, TransitLine > getTransitLines()
void setTravelTime(final double travelTime)