MATSIM
AbstractTransitDriverAgent.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * *
4  * *********************************************************************** *
5  * *
6  * copyright : (C) 2010 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.mobsim.qsim.pt;
21 
22 import java.util.List;
23 import java.util.ListIterator;
24 
25 import org.apache.logging.log4j.LogManager;
26 import org.apache.logging.log4j.Logger;
27 import org.matsim.api.core.v01.Id;
28 import org.matsim.api.core.v01.Scenario;
49 import org.matsim.vehicles.Vehicle;
50 
51 public abstract class AbstractTransitDriverAgent implements TransitDriverAgent, PlanAgent {
52 
53  private static final Logger log = LogManager.getLogger(AbstractTransitDriverAgent.class);
54 
56 
57  private TransitVehicle vehicle = null;
58 
59  private int nextLinkIndex = 0;
61  private TransitRouteStop currentStop = null;
63  private ListIterator<TransitRouteStop> stopIterator;
65 
66  private final PassengerAccessEgressImpl accessEgress;
67 
68  /* package */ MobsimAgent.State state = MobsimAgent.State.ACTIVITY ;
69  // yy not so great: implicit instantiation at activity. kai, nov'11
70  @Override
71  public final MobsimAgent.State getState() {
72  return this.state ;
73  }
74 
75  @Override
76  public abstract void endLegAndComputeNextState(final double now);
77  protected abstract NetworkRoute getCarRoute();
78  protected abstract TransitLine getTransitLine();
79  public abstract TransitRoute getTransitRoute();
80  protected abstract Departure getDeparture();
81  @Override
82  public abstract double getActivityEndTime();
83 
84  AbstractTransitDriverAgent(InternalInterface internalInterface, TransitStopAgentTracker agentTracker2) {
85  super();
86  this.internalInterface = internalInterface;
87  Scenario scenario = internalInterface.getMobsim().getScenario();
88  this.eventsManager = internalInterface.getMobsim().getEventsManager();
89  accessEgress = new PassengerAccessEgressImpl(this.internalInterface, agentTracker2, scenario, eventsManager);
90  }
91 
92  final void init() {
93  if (getTransitRoute() != null) {
94  this.stopIterator = getTransitRoute().getStops().listIterator();
95  this.nextStop = (stopIterator.hasNext() ? stopIterator.next() : null);
96  } else {
97  this.nextStop = null;
98  }
99  this.nextLinkIndex = 0;
100  }
101 
102  final void setDriver(Person personImpl) {
103  this.dummyPerson = personImpl;
104  }
105 
106  @Override
107  public final Id<Link> chooseNextLinkId() {
108  NetworkRoute netR = getCarRoute();
109  List<Id<Link>> linkIds = netR.getLinkIds();
110  if (this.nextLinkIndex < linkIds.size()) {
111  return linkIds.get(this.nextLinkIndex);
112  }
113  if (this.nextLinkIndex == linkIds.size()) {
114  if (linkIds.size() == 0 && netR.getStartLinkId().equals(netR.getEndLinkId())) {
115  // unfortunate exception for the unlikely but legal and test-covered case where a whole transit line
116  // takes place on a single link.
117  // would not need to be here if a route were simply a list of linkIds to traverse, with 1 being an allowed length.
118  // this used to return endLinkId, which would then require a transit-specific extra case for arriving vehicles
119  // in QLinkImpl, which was even worse.
120  return null;
121  }
122  return netR.getEndLinkId();
123  }
125  return null;
126  }
127 
128  @Override
129  public final void setStateToAbort( final double now ) {
130  this.state = MobsimAgent.State.ABORT ;
131  }
132 
133  @Override
134  public final Id<Link> getCurrentLinkId() {
135  int currentLinkIndex = this.nextLinkIndex - 1;
136  if (currentLinkIndex < 0) {
137  return getCarRoute().getStartLinkId();
138  } else if (currentLinkIndex >= getCarRoute().getLinkIds().size()) {
139  return getCarRoute().getEndLinkId();
140  } else {
141  return getCarRoute().getLinkIds().get(currentLinkIndex);
142  }
143  }
144 
145  @Override
146  public final void notifyMoveOverNode(Id<Link> nextLinkId) {
147  this.nextLinkIndex++;
148  }
149 
150  protected final int getNextLinkIndex() {
151  return nextLinkIndex;
152  }
153 
157  protected final void setNextLinkIndex(int idx) {
158  nextLinkIndex = idx;
159  }
160 
161  @Override
163  if (this.nextStop == null) {
164  return null;
165  }
166  return this.nextStop.getStopFacility();
167  }
168 
169  @Override
170  public double handleTransitStop(final TransitStopFacility stop, final double now) {
171  // yy can't make this final because of tests. kai, oct'12
172 
173  assertExpectedStop(stop);
174  processEventVehicleArrives(stop, now);
175 
176  TransitRoute route = this.getTransitRoute();
177  List<TransitRouteStop> stopsToCome = route.getStops().subList(stopIterator.nextIndex(), route.getStops().size());
178  /*
179  * If there are passengers leaving or entering, the stop time must be not greater than 1.0 in order to let them (de-)board every second.
180  * If a stopTime greater than 1.0 is used, this method is not necessarily triggered by the qsim, so (de-)boarding will not happen. Dg, 10-2012
181  */
182  double stopTime = this.accessEgress.calculateStopTimeAndTriggerBoarding(getTransitRoute(), getTransitLine(), this.vehicle, stop, stopsToCome, now);
183 
184  if(stopTime == 0.0){
185  stopTime = longerStopTimeIfWeAreAheadOfSchedule(now, stopTime);
186  }
187  if (stopTime == 0.0) {
188  depart(now);
189  }
190  return stopTime;
191  }
192 
193  final void sendTransitDriverStartsEvent(final double now) {
194  // A test initializes this Agent without internalInterface.
195  // Actually, I am not sure if agents should send Events (or just be reactive, so they can be
196  // tested / exercised as a unit, without a QSim. michaz
197  if (internalInterface != null) {
198  // check if "Wenden"
199  if(getTransitLine() == null){
200  eventsManager.processEvent(new TransitDriverStartsEvent(now, this.dummyPerson.getId(),
201  this.vehicle.getId(), Id.create("Wenden", TransitLine.class), Id.create("Wenden", TransitRoute.class), Id.create("Wenden", Departure.class)));
202  } else {
203  eventsManager.processEvent(new TransitDriverStartsEvent(now, this.dummyPerson.getId(),
204  this.vehicle.getId(), getTransitLine().getId(), getTransitRoute().getId(), getDeparture().getId()));
205  }
206  }
207  }
208 
209  @Override
210  public void notifyArrivalOnLinkByNonNetworkMode(final Id<Link> linkId) {
211  }
212 
220  final Person getPerson() {
221  return this.dummyPerson;
222  }
223 
224  @Override
225  public final TransitVehicle getVehicle() {
226  return this.vehicle;
227  }
228 
229  @Override
230  public final void setVehicle(final MobsimVehicle vehicle) {
231  // MobsimVehicle to fulfill the interface; should be a TransitVehicle at runtime!
232  this.vehicle = (TransitVehicle) vehicle;
233  }
234 
236  final double now) {
237  if (this.currentStop == null) {
238  this.currentStop = this.nextStop;
239  double delay = now - this.getDeparture().getDepartureTime();
240  delay -= this.currentStop.getArrivalOffset()
241  .or(this.currentStop::getDepartureOffset)
242  .orElseGet(() -> {
243  log.warn("Could not calculate delay!");
244  return 0;
245  }
246  );
247  eventsManager.processEvent(new VehicleArrivesAtFacilityEvent(now, this.vehicle.getVehicle().getId(), stop.getId(),
248  delay));
249  }
250  }
251 
252  private void assertExpectedStop(final TransitStopFacility stop) {
253  if (stop != this.nextStop.getStopFacility()) {
254  throw new RuntimeException("Expected different stop.");
255  }
256  }
257 
258  protected double longerStopTimeIfWeAreAheadOfSchedule(final double now,
259  final double stopTime) {
260  if ((this.nextStop.isAwaitDepartureTime()) && (this.nextStop.getDepartureOffset().isDefined())) {
261  double earliestDepTime = getActivityEndTime() + this.nextStop.getDepartureOffset().seconds();
262  if (now + stopTime < earliestDepTime) {
263  return earliestDepTime - now;
264  }
265  }
266  return stopTime;
267  }
268 
269  private void depart(final double now) {
270  double delay = now - this.getDeparture().getDepartureTime();
271  delay -= this.currentStop.getDepartureOffset()
272  .or(this.currentStop::getArrivalOffset)
273  .orElseGet(() -> {
274  log.warn("Could not calculate delay!");
275  return 0;
276  }
277  );
278  eventsManager.processEvent(new VehicleDepartsAtFacilityEvent(now, this.vehicle.getVehicle().getId(),
279  this.currentStop.getStopFacility().getId(),
280  delay));
281  this.nextStop = (stopIterator.hasNext() ? stopIterator.next() : null);
282  if(this.nextStop == null) {
284  }
285  this.currentStop = null;
286  }
287 
288  private void assertAllStopsServed() {
289  if (this.nextStop != null) {
290  RuntimeException e = new RuntimeException("Transit vehicle is not yet at last stop! vehicle-id = "
291  + this.vehicle.getVehicle().getId() + "; next-stop = " + this.nextStop.getStopFacility().getId());
292  log.error(e);
293  throw e;
294  }
295  }
296 
297  private void assertVehicleIsEmpty() {
298  if (this.vehicle.getPassengers().size() > 0) {
299  RuntimeException e = new RuntimeException("Transit vehicle is at last stop but still contains passengers that did not leave the vehicle!");
300  log.error("Transit vehicle must be empty after last stop! vehicle-id = " + this.vehicle.getVehicle().getId(), e);
301  for (PassengerAgent agent : this.vehicle.getPassengers()) {
302  if (agent instanceof PersonDriverAgentImpl) {
303  log.error("Agent is still in transit vehicle: agent-id = " + ((PersonDriverAgentImpl) agent).getPerson().getId());
304  }
305  }
306  throw e;
307  }
308  }
309 
310 
311  final NetworkRouteWrapper getWrappedCarRoute(NetworkRoute carRoute) {
312  return new NetworkRouteWrapper(carRoute);
313  }
314 
315  @Override
316  public Id<Person> getId() {
317  return this.dummyPerson.getId() ;
318  }
319 
323  abstract /*package*/ Leg getCurrentLeg() ;
324 
325 
334  private final class NetworkRouteWrapper implements NetworkRoute, Cloneable {
335 
336  private final NetworkRoute delegate;
337 
338  /*package*/ NetworkRouteWrapper(final NetworkRoute route) {
339  this.delegate = route;
340  }
341 
342  @Override
343  public List<Id<Link>> getLinkIds() {
344  return this.delegate.getLinkIds();
345  }
346 
347  @Override
348  public NetworkRoute getSubRoute(final Id<Link> fromLinkId, final Id<Link> toLinkId) {
349  return this.delegate.getSubRoute(fromLinkId, toLinkId);
350  }
351 
352  @Override
353  public double getTravelCost() {
354  return this.delegate.getTravelCost();
355  }
356 
357  @Override
360  }
361 
362  @Override
363  public void setLinkIds(final Id<Link> startLinkId, final List<Id<Link>> srcRoute, final Id<Link> endLinkId) {
364  throw new UnsupportedOperationException("read only route.");
365  }
366 
367  @Override
368  public void setTravelCost(final double travelCost) {
369  throw new UnsupportedOperationException("read only route.");
370  }
371 
372  @Override
373  public void setVehicleId(final Id<Vehicle> vehicleId) {
374  throw new UnsupportedOperationException("read only route.");
375  }
376 
377  @Override
378  public void setEndLinkId(final Id<Link> linkId) {
379  throw new UnsupportedOperationException("read only route.");
380  }
381 
382  @Override
383  public void setStartLinkId(final Id<Link> linkId) {
384  throw new UnsupportedOperationException("read only route.");
385  }
386 
387  @Override
388  public void setRouteDescription(String routeDescription) {
389  throw new UnsupportedOperationException("read only route.");
390  }
391 
392  @Override
393  public String getRouteDescription() {
394  return this.delegate.getRouteDescription();
395  }
396 
397  @Override
398  public String getRouteType() {
399  return this.delegate.getRouteType();
400  }
401 
402  @Override
403  @Deprecated
404  public double getDistance() {
405  return this.delegate.getDistance();
406  }
407 
408  @Override
410  return this.delegate.getEndLinkId();
411  }
412 
413  @Override
415  return this.delegate.getStartLinkId();
416  }
417 
418  @Deprecated
419  @Override
421  return this.delegate.getTravelTime();
422  }
423 
424  @Override
425  public void setDistance(final double distance) {
426  throw new UnsupportedOperationException("read only route.");
427  }
428 
429  @Override
430  public void setTravelTime(final double travelTime) {
431  throw new UnsupportedOperationException("read only route.");
432  }
433 
434  @Override
435  public void setTravelTimeUndefined() {
436  throw new UnsupportedOperationException("read only route.");
437  }
438 
439  @Override
441  try {
442  return (NetworkRouteWrapper) super.clone();
443  } catch (CloneNotSupportedException e) {
444  throw new AssertionError(e);
445  }
446  }
447 
448  }
449 
450 
451 }
void processEventVehicleArrives(final TransitStopFacility stop, final double now)
NetworkRoute getSubRoute(final Id< Link > fromLinkId, final Id< Link > toLinkId)
double longerStopTimeIfWeAreAheadOfSchedule(final double now, final double stopTime)
Collection<? extends PassengerAgent > getPassengers()
abstract void endLegAndComputeNextState(final double now)
NetworkRoute getSubRoute(final Id< Link > fromLinkId, final Id< Link > toLinkId)
static< T > Id< T > create(final long key, final Class< T > type)
Definition: Id.java:68
double handleTransitStop(final TransitStopFacility stop, final double now)
double orElseGet(DoubleSupplier supplier)
EventsManager getEventsManager()
Definition: QSim.java:565
abstract TransitStopFacility getStopFacility()
void setLinkIds(final Id< Link > startLinkId, final List< Id< Link >> srcRoute, final Id< Link > endLinkId)
OptionalTime or(OptionalTime optionalTime)