MATSIM
PlanBasedDriverAgentImpl.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.* *
3  * *
4  * *********************************************************************** *
5  * *
6  * copyright : (C) 2008 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 package org.matsim.core.mobsim.qsim.agents;
20 
21 import java.util.List;
22 
23 import org.apache.logging.log4j.LogManager;
24 import org.apache.logging.log4j.Logger;
25 import org.matsim.api.core.v01.Id;
33 import org.matsim.vehicles.Vehicle;
34 
35 import com.google.common.base.MoreObjects;
36 
40 public final class PlanBasedDriverAgentImpl implements DriverAgent {
41 
42  private static final Logger log = LogManager.getLogger(PlanBasedDriverAgentImpl.class);
43 
45 
47  this.basicPlanAgentDelegate = basicAgent ;
48  }
49 
50  private static int expectedLinkWarnCount = 0;
51 
52  private Id<Link> cachedNextLinkId = null;
53 
54  @Override
55  public final void notifyMoveOverNode(Id<Link> newLinkId) {
56  if (expectedLinkWarnCount < 10 && !newLinkId.equals(this.cachedNextLinkId)) {
57  log.warn("Agent did not end up on expected link. Ok for within-day replanning agent, otherwise not. Continuing " + "anyway ... This warning is suppressed after the first 10 warnings.") ;
58  expectedLinkWarnCount++;
59  }
60  this.basicPlanAgentDelegate.setCurrentLinkId( newLinkId ) ;
61  this.basicPlanAgentDelegate.incCurrentLinkIndex();
62  this.cachedNextLinkId = null; //reset cached nextLink
63  }
64 
70  @Override
71  public final Id<Link> chooseNextLinkId() {
72  // To note: there is something really stupid going on here: A vehicle that is at the end of its route and on the destination link will arrive.
73  // However, a vehicle that is on the destination link BUT NOT AT THE END OF ITS ROUTE will NOT arrive. This makes the whole thing
74  // very extremely messy. kai, nov'14 (This behavior is no longer there. kai, nov'14)
75 
76  // Please, let's try, amidst all checking and caching, to have this method return the same thing
77  // if it is called several times in a row. Otherwise, you get Heisenbugs.
78  // I just fixed a situation where this method would give a warning about a bad route and return null
79  // the first time it is called, and happily return a link id when called the second time. michaz 2013-08
80 
81  // Agreed. One should also not assume that anything here is the result of one consistent design process. Rather, many people added
82  // and removed material as they needed it for their own studies. Making the whole code more consistent would be highly
83  // desirable. kai, nov'14
84 
85  // (1) if there is a cached link id, use that one:
86  if (this.cachedNextLinkId != null && !(this.cachedNextLinkId.equals(this.getCurrentLinkId())) ) {
87  // cachedNextLinkId used to be set to null when a leg started. Now the BasicPlanAgentImpl does not longer have access to cached
88  // value. kai, nov'14
89 
90  return this.cachedNextLinkId;
91  }
92 
93  // (2) routes that are not network routes cannot be interpreted
94  if ( ! ( this.basicPlanAgentDelegate.getCurrentLeg().getRoute() instanceof NetworkRoute ) ) {
95  return null ;
96  }
97 
98  List<Id<Link>> routeLinkIds = ((NetworkRoute) this.basicPlanAgentDelegate.getCurrentLeg().getRoute()).getLinkIds();
99 
100  // (3) if route has run dry, we return the destination link (except for one special case, which however may not be necessary any more):
101  if (this.basicPlanAgentDelegate.getCurrentLinkIndex() >= routeLinkIds.size() ) {
102 
103  // special case:
104  if (this.getCurrentLinkId().equals( this.getDestinationLinkId() ) && this.basicPlanAgentDelegate.getCurrentLinkIndex() > routeLinkIds.size()) {
105  // this can happen if the last link in a route is a loop link. Don't ask, it can happen in special transit simulation cases... mrieser/jan2014
106 
107  // the condition for arrival used to be "route has run dry AND destination link not attached to current link". now with loop links,
108  // this condition was not triggered. So no wonder that for such cases a special condition was needed. kai, nov'14
109 
110  // The special condition may not be necessary any more. kai, nov'14
111 
112  return null;
113  }
114 
115  this.cachedNextLinkId = this.getDestinationLinkId();
116  return this.cachedNextLinkId;
117 
118  }
119 
120  // (4) otherwise (normal case): return the next link of the plan (after caching it):
121  this.cachedNextLinkId = routeLinkIds.get(this.basicPlanAgentDelegate.getCurrentLinkIndex());
122  return this.cachedNextLinkId;
123 
124  }
125 
126  @Override
127  public final boolean isWantingToArriveOnCurrentLink( ) {
128 
129  if ( ! ( this.basicPlanAgentDelegate.getCurrentLeg().getRoute() instanceof NetworkRoute ) ) {
130  // non-network links in the past have always returned true (i.e. "null" to the chooseNextLink question). kai, nov'14
131  return true ;
132  }
133 
134  final List<Id<Link>> routeLinkIds = ((NetworkRoute) this.basicPlanAgentDelegate.getCurrentLeg().getRoute()).getLinkIds();
135  final int routeLinkIdsSize = routeLinkIds.size();
136 
137  // the standard condition used to be "route has run dry AND destination link not attached to current link":
138  // 2nd condition essentially meant "destination link EQUALS current link" but really stupid way of stating this. Thus
139  // changing the second condition to "being at destination". This breaks old code; I will fix as far as it is covered by tests. kai, nov'14
140  if ( this.basicPlanAgentDelegate.getCurrentLinkIndex() >= routeLinkIdsSize && this.getCurrentLinkId().equals( this.getDestinationLinkId() ) ) {
141  return true ;
142  }
143 
144  // the following are possible consistency checks on which previous code may have relied. Relatively expensive because of hash map lookups. kai, nov'14
145 
146  // Link currentLink = this.getScenario().getNetwork().getLinks().get( this.getCurrentLinkId() ) ;
147 // Link destinationLink = this.getScenario().getNetwork().getLinks().get( this.getDestinationLinkId() ) ;
148 //
149 // if ( this.currentLinkIndex >= routeLinkIdsSize ) { // route has run dry
150 // if ( currentLink.getToNode() == destinationLink.getFromNode() ) { // will arrive on next link
151 // return false ;
152 // } else { // will not arrive on next link
153 // log.error("route has run dry, and destination link is not attached to next node. In consequence, vehicle has no chance to continue "
154 // + "correctly. Make it arrive here rather than explode it at the intersection.") ;
155 // return true ;
156 // }
157 // }
158 
159  // Link nextLink = this.getScenario().getNetwork().getLinks().get( routeLinkIds.get(this.getCurrentLinkIndex()) ) ;
160 //
161 // if ( currentLink.getToNode() != nextLink.getFromNode() ) {
162 // log.error("route is inconsistent. In consequence, vehicle has no chance to continue correctly." +
163 // "Make it arrive here rather than explode it at the intersection." ) ;
164 // return true ;
165 // }
166 
167  return false ;
168  }
169 
170  // ============================================================================================================================
171  // below there only (package-)private methods or setters/getters
172 
181  /* package */ public final void resetCaches() {
182 
183  // moving this method not to WithinDay for the time being since it seems to make some sense to keep this where the internals are
184  // known best. kai, oct'10
185  // Compromise: package-private here; making it public in the Withinday class. kai, nov'10
186 
187  this.cachedNextLinkId = null;
188 
189  if( this.basicPlanAgentDelegate.getCurrentPlanElement()==null ) {
190  throw new RuntimeException("encountered unexpected null pointer" ) ;
191  }
192 
193  if (this.basicPlanAgentDelegate.getCurrentPlanElement() instanceof Leg) {
194  if (basicPlanAgentDelegate.getCurrentLeg().getRoute() == null) {
195  log.error("The agent " + this.getId() + " has no route in its leg. Setting agent state to abort." );
196  this.basicPlanAgentDelegate.setState(MobsimAgent.State.ABORT) ;
197  }
198  }
199 // else {
200 // this.basicPlanAgentDelegate.calculateAndSetDepartureTime((Activity) this.basicPlanAgentDelegate.getCurrentPlanElement());
201 // }
202  this.basicPlanAgentDelegate.resetCaches();
203  }
204 
205  @Override
206  public Id<Person> getId() {
207  return this.basicPlanAgentDelegate.getId();
208  }
209 
210  @Override
212  return this.basicPlanAgentDelegate.getCurrentLinkId() ;
213  }
214 
215  @Override
217  return this.basicPlanAgentDelegate.getDestinationLinkId() ;
218  }
219 
220  @Override
221  public void setVehicle(MobsimVehicle veh) {
222  this.basicPlanAgentDelegate.setVehicle( veh );
223  }
224 
225  @Override
227  return this.basicPlanAgentDelegate.getVehicle() ;
228  }
229 
230  @Override
232  return this.basicPlanAgentDelegate.getPlannedVehicleId();
233  }
234 
235  @Override
236  public String getMode() {
237  return this.basicPlanAgentDelegate.getMode();
238  }
239 
240  @Override
241  public String toString() {
242  return MoreObjects.toStringHelper(this).add("basicPlanAgentDelegate", basicPlanAgentDelegate).toString();
243  }
244 }
static< T > Id< T > get(int index, final Class< T > type)
Definition: Id.java:112
boolean equals(Object obj)
Definition: Id.java:139