MATSIM
EditTrips.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * EditTrips.java
4  * *
5  * *********************************************************************** *
6  * *
7  * copyright : (C) 2019 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.withinday.utils;
22 
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.stream.Collectors;
27 
28 import org.apache.logging.log4j.LogManager;
29 import org.apache.logging.log4j.Logger;
30 import org.matsim.api.core.v01.Id;
31 import org.matsim.api.core.v01.Scenario;
40 import org.matsim.core.gbl.Gbl;
60 import org.matsim.pt.PtConstants;
70 
82 public final class EditTrips {
83  private static final Logger log = LogManager.getLogger(EditTrips.class) ;
84 
85  private final TripRouter tripRouter;
86  private final PopulationFactory pf;
88  private Scenario scenario;
92 
93  public EditTrips( TripRouter tripRouter, Scenario scenario, InternalInterface internalInterface, TimeInterpretation timeInterpretation ) {
94 // For other log level, find log4j.xml and add something like
95 //<logger name="org.matsim.withinday.utils.EditTrips">
96 // <level value="info"/>
97 //</logger>
98  // We need InternalInterface to move waiting passengers from a transit stop to the next leg if replanning tells them not to board a bus there.
99  if (internalInterface == null) {
100  log.warn("InternalInterface is null. Replanning of pt/transit legs will not work properly and will likely fail.");
101  } else {
102  this.eventsManager = internalInterface.getMobsim().getEventsManager();
103  for (AgentTracker tracker : (internalInterface.getMobsim().getAgentTrackers())) {
104  if (tracker instanceof TransitStopAgentTracker) {
105  transitAgentTracker = (TransitStopAgentTracker) tracker;
106  break;
107  }
108  }
109  }
110 
111  this.tripRouter = tripRouter;
112  this.scenario = scenario;
113  this.pf = scenario.getPopulation().getFactory() ;
114  this.internalInterface = internalInterface;
115  this.timeInterpretation = timeInterpretation;
116 
117  if (transitAgentTracker == null) {
118  log.warn("no TransitStopAgentTracker found in qsim. Replanning of pt/transit legs will not work properly and will likely fail.");
119  }
120 
121  }
122  public static Trip findCurrentTrip( MobsimAgent agent ) {
124  return findTripAtPlanElement(agent, pe);
125  }
127 // log.debug("plan element to be found=" + pe ) ;
129  for ( Trip trip : trips ) {
130  for ( PlanElement te : trip.getTripElements() ) {
131 // log.debug("trip element to be compared with=" + te ) ;
132  if ( te==pe ) {
133 // log.debug("found trip element") ;
134  return trip;
135  }
136  }
137  }
138  throw new ReplanningException("trip not found") ;
139  }
140  public static Trip findTripAtPlanElementIndex( MobsimAgent agent, int index ) {
141  return findTripAtPlanElement( agent, WithinDayAgentUtils.getModifiablePlan(agent).getPlanElements().get(index) ) ;
142  }
143  // current trip:
144  public final boolean replanCurrentTrip(MobsimAgent agent, double now, String routingMode ) {
145  log.debug("entering replanCurrentTrip with routingMode=" + routingMode) ;
146 
147  // I will treat this here in the way that it will make the trip consistent with the activities. So if the activity in the
148  // plan has changed, the trip will go to a new location.
149 
150  // what matters is the external interface, which is the method call. Everything below is internal so it does not matter so much.
151 
152  Trip trip = findCurrentTrip( agent ) ;
153  final PlanElement currentPlanElement = WithinDayAgentUtils.getCurrentPlanElement(agent) ;
154  final List<PlanElement> tripElements = trip.getTripElements();
155  int tripElementsIndex = tripElements.indexOf( currentPlanElement ) ;
156 
157  if ( currentPlanElement instanceof Activity ) {
158  // we are on a stage activity. Take it from there:
159  // TODO: this method fails with exception
160  replanCurrentTripFromStageActivity(trip, tripElementsIndex, routingMode, now, agent);
161  } else {
162  // we are on a leg
163  replanCurrentTripFromLeg(trip.getDestinationActivity(), currentPlanElement, routingMode, now, agent, trip.getTripAttributes());
164  }
165 
166  if (eventsManager != null) {
167  ReplanningEvent replanningEvent = new ReplanningEvent(now, agent.getId(), "EditTrips.replanCurrentTrip");
168  eventsManager.processEvent(replanningEvent);
169  }
171  return true ;
172  }
173  private void replanCurrentTripFromLeg(Activity newAct, final PlanElement currentPlanElement, final String routingMode, double now, MobsimAgent agent, Attributes routingAttributes) {
174  log.debug("entering replanCurrentTripFromLeg for agent" + agent.getId());
175  Leg currentLeg = (Leg) currentPlanElement ;
176  if ( currentLeg.getRoute() instanceof NetworkRoute ) {
177  replanCurrentLegWithNetworkRoute(newAct, routingMode, currentLeg, now, agent, routingAttributes);
178  } else if ( currentLeg.getRoute() instanceof TransitPassengerRoute ) {
179  // public transit leg
180  replanCurrentLegWithTransitRoute(newAct, routingMode, currentLeg, now, agent, routingAttributes);
181  } else if ( currentLeg.getRoute() instanceof GenericRouteImpl ) {
182  // teleported leg
183  replanCurrentLegWithGenericRoute(newAct, routingMode, currentLeg, now, agent);
184  } else {
185  throw new ReplanningException("not implemented for the route type of the current leg") ;
186  }
188  }
189 
190  private void replanCurrentLegWithNetworkRoute(Activity newAct, String mainMode, Leg currentLeg, double now, MobsimAgent agent, Attributes routingAttributes) {
191  log.debug("entering replanCurrentLegWithNetworkRoute for agent" + agent.getId()) ;
192 
194  List<PlanElement> planElements = plan.getPlanElements() ;
195  Person person = plan.getPerson() ;
196 
197  // (1) get new trip from current position to new activity:
198  Link currentLink = scenario.getNetwork().getLinks().get( agent.getCurrentLinkId() ) ;
199  Facility currentLocationFacility = FacilitiesUtils.wrapLink( currentLink ) ;
200  List<? extends PlanElement> newTripElements = newTripToNewActivity(currentLocationFacility, newAct, mainMode, now, person, routingAttributes );
201 
202  // (2) there should be no access leg even with access/egress routing
203  Gbl.assertIf( (((Leg)newTripElements.get(0)).getRoute() instanceof NetworkRoute) );
204 
205  // (3) modify current route within current leg:
206  replaceRemainderOfCurrentRoute(currentLeg, newTripElements, agent);
207 
208  // (4) remove remainder of old trip after current leg in plan:
209  int pos = WithinDayAgentUtils.getCurrentPlanElementIndex(agent) + 1 ;
210  while ( !planElements.get(pos).equals(newAct) ) {
211  planElements.remove(pos) ;
212  }
213 
214  // (5) insert new trip after current leg:
215  for ( int ijk = 1 ; ijk < newTripElements.size() ; ijk++ ) {
216  planElements.add( pos, newTripElements.get(ijk) ) ;
217  }
218 
220  }
221 
222  private void replanCurrentLegWithTransitRoute(Activity newAct, String routingMode, Leg currentLeg, double now, MobsimAgent agent, Attributes routingAttributes) {
223  log.debug("entering replanCurrentLegWithTransitRoute for agentId=" + agent.getId()) ;
224 
226  List<PlanElement> planElements = plan.getPlanElements() ;
227  Person person = plan.getPerson() ;
228 
229  // find current (if transit vehicle is at a stop) or next stop
230 
231  if (! (agent instanceof PTPassengerAgent) ) {
232  throw new RuntimeException("transit leg, but agent is not an PTPassengerAgent: not implemented! agent id: " + agent.getId());
233  }
234  PTPassengerAgent ptPassengerAgent = (PTPassengerAgent) agent;
235 
236  MobsimVehicle mobsimVehicle = ptPassengerAgent.getVehicle();
237  TransitPassengerRoute oldPtRoute = (TransitPassengerRoute) currentLeg.getRoute();
238 
239  /*
240  * In AbstractTransitDriverAgent nextStop is moved forward only at departure, so
241  * while the vehicle stops "nextStop" is the stop where the vehicle stops at.
242  * (see AbstractTransitDriverAgent.depart() and
243  * AbstractTransitDriverAgent.processEventVehicleArrives())
244  *
245  * So if the vehicle stops at a stop facility, driver.getNextTransitStop() will
246  * return that stop facility and we can replan the agent from that stop facility.
247  * gl may'19
248  */
249 
250  /*
251  * TODO: Routing with the current vehicle as a start: If the agent is currently
252  * on a delayed bus, the router won't find that bus when looking for shortest
253  * paths from the next stop, because it assumes the bus has already departed. It
254  * will suggest to take another later bus even if staying on the current
255  * (delayed) bus is better. A real-time schedule based router would solve this
256  * apart from transfer times and disutilities (it won't take into account that
257  * staying on the same bus is one transfer less than getting off at the next
258  * stop and taking another bus from there). Otherwise one might route from all
259  * following stop facilities the delayed bus will still serve (high computation
260  * time, maybe less so with some special kind of many-to-one tree) or move only
261  * the corresponding departure in the schedule (high computation time for
262  * preparing the Raptor router's internal data structures, probably worst
263  * option). Not solving this will likely lead to change of routes without a
264  * proper reason / some kind of oscillation between two best or at least
265  * similarly good paths.
266  *
267  * Idea 1: Use scheduled departure time instead of real current time to keep
268  * (delayed) bus the passenger is sitting on available from the router's
269  * perspective. Idea 2: Use input schedule file which has real (delayed)
270  * departure times as far as known at the time of withinday-replanning.
271  *
272  * gl may'19
273  */
274 
275  boolean wantsToLeaveStop = false ;
276 
277  TransitStopFacility currentOrNextStop = null;
278  List<? extends PlanElement> newTripElements = null;
279  // (1) get new trip from current position to new activity:
280  if (mobsimVehicle == null) {
281  currentOrNextStop = scenario.getTransitSchedule().getFacilities().get(oldPtRoute.getAccessStopId());
282  log.debug( "agent with ID=" + agent.getId() + " is waiting at a stop=" + currentOrNextStop ) ;
283  newTripElements = newTripToNewActivity(currentOrNextStop, newAct, routingMode, now, person, routingAttributes );
284  Gbl.assertIf( newTripElements.get(0) instanceof Leg ); // that is what TripRouter should do. kai, jul'19
285 
286  wantsToLeaveStop = true ;
287  if (newTripElements.size() >= 2) {
288  // check if the agent has a useless teleport leg from a transit stop to the very same stop
289  Leg newPtLeg = (Leg) newTripElements.get(2);
290  if (newPtLeg.getRoute() instanceof TransitPassengerRoute) {
291  TransitPassengerRoute newPtRoute = (TransitPassengerRoute) newPtLeg.getRoute();
292  if (newPtRoute.getAccessStopId().equals(currentOrNextStop.getId())) {
293  // the agent will stay at the same stop where the agent is already waiting
294  log.debug( "agent with ID=" + agent.getId() + " will wait for vehicle departing at the same stop facility." ) ;
295  // don't remove the agent from the stop tracker
296  currentLeg.setRoute(newPtRoute);
297  // There is an access_walk leg in the new trip (router assumes the trip begins
298  // here) so we should remove the access_walk leg and the pt interaction
299  // element 0 is the useless walk from the stop to the same stop
300  // element 1 is a pt interaction between the walk and the first pt leg
301  // element 2 is the first pt leg, which we don't need because we updated the
302  // current pt leg
303  // so remove elements 0, 1 and 2, i.e. remove first element 3 times (index is moving)
304  newTripElements.remove(0);
305  newTripElements.remove(0);
306  newTripElements.remove(0);
307  wantsToLeaveStop = false;
309  }
310  }
311  }
312 
313  // in all other cases leave the stop
314  if (wantsToLeaveStop) {
315  // The agent will not board any bus at the transit stop and will walk away or
316  // do something else. We have to remove him from the list of waiting agents.
317  log.debug("agent with ID=" + agent.getId() + " will leave the stop facility.") ;
318  newTripElements = defaultMergeOldAndNewCurrentPtLeg(currentLeg, newTripElements, agent, currentOrNextStop, oldPtRoute);
319  }
320 
321  } else {
322  log.debug( "agent with ID=" + agent.getId() + " is on a vehicle" );
323  // agent is asked whether she intends to leave at each stop, so no need to tell
324  // mobsim about changed plan in any particular way
325  TransitDriverAgent driver = (TransitDriverAgent) mobsimVehicle.getDriver();
326  currentOrNextStop = driver.getNextTransitStop();
327  /*
328  * Look up scheduled arrival time at next transit stop and replan from that time.
329  * Use planned arrival time instead of some kind of real arrival including delay in order to allow the router
330  * to find the transit route the agent is currently staying on. Otherwise the router would assume that this bus has
331  * already departed and cannot be reached by the agent even though the agent is currently located on that very same
332  * bus (which the router does not know :-( )
333  * We have no router or schedule data in "real time", i.e. considering delays, so lets assume that all pt departures
334  * are punctual. If we would route from the current time (= "now") instead, it is unclear how long it will take to
335  * arrive at the next stop and we risk that the agent misses the bus he is already riding on. - gl jul'19
336  */
337  double reRoutingTime;
338  if (driver instanceof TransitDriverAgentImpl) { // this is ugly, but there seems to be no other way to find out the scheduled arrival time. Maybe add to interface?
339  TransitDriverAgentImpl driverImpl = (TransitDriverAgentImpl) driver;
340  double departureFirstTransitRouteStop = driverImpl.getDeparture().getDepartureTime();
341  double arrivalOffsetNextTransitRouteStop = driverImpl.getTransitRoute().getStop(currentOrNextStop).getArrivalOffset().seconds();
342  reRoutingTime = departureFirstTransitRouteStop + arrivalOffsetNextTransitRouteStop;
343  } else {
344  throw new RuntimeException("transit driver is not a TransitDriverAgentImpl, not implemented!");
345  }
346  log.debug( "agent with ID=" + agent.getId() + " is re-routed from next stop " + currentOrNextStop.getId() + " scheduled arrival at " + reRoutingTime);
347  newTripElements = newTripToNewActivity(currentOrNextStop, newAct, routingMode, reRoutingTime, person, routingAttributes );
348  // yyyy as discussed elswhere, would make more sense to compute this once arrived at that stop.
349 
350  boolean agentStaysOnSameVehicle = false;
351  if (newTripElements.size() >= 2) {
352  // check if the agent has a useless teleport leg from a transit stop to the very same stop
353  Leg firstPtLeg = (Leg) newTripElements.get(2);
354  if (firstPtLeg.getRoute() instanceof TransitPassengerRoute) {
355  TransitPassengerRoute newPtRoute = (TransitPassengerRoute) firstPtLeg.getRoute();
356  if (newPtRoute.getAccessStopId().equals(currentOrNextStop.getId())) {
357  // the agent will take a pt vehicle from the stop where the bus will arrive next
358  if (oldPtRoute.getLineId().equals(newPtRoute.getLineId())
359  && (oldPtRoute.getRouteId().equals(newPtRoute.getRouteId())
360  || transitRouteLaterStopsAt(oldPtRoute.getLineId(), oldPtRoute.getRouteId(),
361  currentOrNextStop.getId(), newPtRoute.getEgressStopId()))) {
362  // Same TransitRoute or other TransitRoute which also serves the new egress stop
363  // -> Agent can stay on the same vehicle
365  oldPtRoute.getStartLinkId(), newPtRoute.getEndLinkId(), //
366  oldPtRoute.getAccessStopId(), newPtRoute.getEgressStopId(), //
367  oldPtRoute.getLineId(), oldPtRoute.getRouteId()
368  );
369  if (newPtRoute.getBoardingTime().isDefined()) {
370  route.setBoardingTime(newPtRoute.getBoardingTime().seconds());
371  }
372  if (newPtRoute.getTravelTime().isDefined()) {
373  // this is wrong but better than nothing.
374  // TODO: calculate travel time from original boarding stop to new alighting stop.
375  route.setTravelTime(newPtRoute.getTravelTime().seconds());
376  }
377  currentLeg.setRoute(route);
378  // There is an access_walk leg in the new trip (router assumes the trip begins
379  // here) so we should remove the access_walk leg and the pt interaction
380  // element 0 is the useless walk from the stop to the same stop
381  // element 1 is a pt interaction between the walk and the first pt leg
382  // element 2 is the first pt leg, which we don't need because we updated the
383  // current pt leg
384  // so remove elements 0, 1 and 2, i.e. remove first element 3 times (index is moving)
385  newTripElements.remove(0);
386  newTripElements.remove(0);
387  newTripElements.remove(0);
389  agentStaysOnSameVehicle = true;
390  }
391  }
392  }
393  }
394 
395  // in all other cases disembark at next stop
396  if (!agentStaysOnSameVehicle) {
397  newTripElements = defaultMergeOldAndNewCurrentPtLeg(currentLeg, newTripElements, agent, currentOrNextStop, oldPtRoute);
398  }
399  }
400 
401  log.debug("") ;
402  log.debug("newTrip for agentId=" + agent.getId() );
403  for( PlanElement planElement : newTripElements ){
404  log.debug(planElement) ;
405  }
406  log.debug("") ;
407 
408  // (3) remove remainder of old trip after current leg in plan:
409  int pos = WithinDayAgentUtils.getCurrentPlanElementIndex(agent) + 1 ;
410 
411  while ( !planElements.get(pos).equals(newAct) ) {
412  planElements.remove(pos) ;
413  }
414 
415  // (4) insert new trip after current leg:
416  for ( int ijk = 0 ; ijk < newTripElements.size() ; ijk++ ) {
417  planElements.add( pos + ijk, newTripElements.get(ijk) ) ;
418  }
419 
420  {
421  // some simplified output:
422  StringBuilder stb = new StringBuilder();
423  boolean first = true;
424  for( PlanElement planElement : planElements ){
425  if( first ){
426  first = false;
427  } else{
428  stb.append( "---" );
429  }
430  if( planElement instanceof Leg ){
431  stb.append( ((Leg) planElement).getMode() );
432  } else if( planElement instanceof Activity ){
433  stb.append( ((Activity) planElement).getType() );
434  }
435  }
436  log.debug("") ;
437  log.debug( "agent" + agent.getId() + " new plan: " + stb.toString() );
438  }
439  log.debug("") ;
440  log.debug("agent" + agent.getId() + " new plan: " ) ;
441  for( PlanElement planElement : planElements ){
442  log.debug(planElement) ;
443  }
444  log.debug("") ;
445 
447 
448  if ( wantsToLeaveStop ) {
449  if (transitAgentTracker == null) {
450  log.error("Replanning a pt/transit leg, but there is no TransitStopAgentTracker found in qsim. Failing...");
451  throw new RuntimeException("no TransitStopAgentTracker found in qsim");
452  }
453 
454  transitAgentTracker.removeAgentFromStop(ptPassengerAgent, currentOrNextStop.getId());
455  ((MobsimAgent) ptPassengerAgent).endLegAndComputeNextState( now );
456  this.internalInterface.arrangeNextAgentState( (MobsimAgent) ptPassengerAgent );
457  }
458 
460  }
461 
468  private void replanCurrentLegWithGenericRoute(Activity newAct, String routingMode, Leg currentLeg, double now, MobsimAgent agent) {
469 
471 
472  /*
473  * Some TransportModes/TripRouters might have no
474  * StageActivityType registered, so we might need to invent a new one, add
475  * scoring parameters and register it as StageActivityType.
476  *
477  * For the time being, we have no elegant way to access the teleportation engine
478  * to redirect current teleportation legs after departure. So we have to let the
479  * teleportation legs end at their originally planned destination and replan from
480  * there.
481  *
482  * It would be better to break teleportation legs at their current position in
483  * line with how EditTrips treats NetworkRoutes (re-route from current link
484  * without stage activity rather than from originally planned destination link).
485  * This could be done by replacing typical teleportation modes with NetworkRoutes
486  * (e.g. bike and walk as network mode or at least teleported along a route on
487  * the network so we would know where on that NetworkRoute they currently are.).
488  * So only short access/egress legs would remain as teleported legs.
489  *
490  * gl may'19
491  */
492  int currPosPlanElements = WithinDayAgentUtils.getCurrentPlanElementIndex(agent);
493  Activity nextAct = (Activity) plan.getPlanElements().get(currPosPlanElements + 1);
494 
496  Trip trip = findCurrentTrip( agent ) ;
497  Facility fromFacility = FacilitiesUtils.toFacility(nextAct, scenario.getActivityFacilities());
499  /*
500  * PopulationUtils.decideOnActivityEndTime() does not take into account that the agent might be on a PlanElement
501  * before the activity and assumes instead that the agent starts the activity at the time passed as parameter and
502  * calculates a suitable activity end time based on that start time. This is not useful here :-(
503  * The end time of the previous activity is not updated when the agent departs for the leg.
504  * Leg departure time exists as variable but is -Infinity....
505  * So we have no clear and reliable information when the agent will finish its teleport leg.
506  * Do some estimation and hope for a TODO better solution in the future :-(
507  * - gl jul'19
508  */
509  // double departureTime = PopulationUtils.decideOnActivityEndTime( nextAct, now, scenario.getConfig() );
510  Activity previousActivity = (Activity) plan.getPlanElements().get(currPosPlanElements - 1);
511  // We don't know where the agent is located on its teleport leg and when it will arrive. Let's assume the agent is
512  // located half way between origin and destination of the teleport leg.
513 
514  double travelTime = timeInterpretation.decideOnLegTravelTime(currentLeg).seconds();
515 
516  double departureTime = now + 0.5 * travelTime;
517  // Check whether looking into previousActivity.getEndTime() gives plausible estimation results (potentially more precise)
518  // Not clear whether this is more precise than using now. If agents end their activities on time it is, otherwise unclear.
519  if (previousActivity.getEndTime().isDefined() && previousActivity.getEndTime().seconds() < now) {
520  // the last activity has a planned end time defined, hope that the end time is close to the real end time:
521  double departureTimeAccordingToPlannedActivityEnd = previousActivity.getEndTime().seconds() + travelTime;
522  // plausibility check: The agent can only arrive after the current time
523  if (departureTimeAccordingToPlannedActivityEnd > now) {
524  departureTime = departureTimeAccordingToPlannedActivityEnd;
525  }
526  }
527  // Replace InteractionActivity with ActivityImpl since they need to be editable.
528  final List<? extends PlanElement> newTrip = tripRouter.calcRoute(routingMode, fromFacility, toFacility, departureTime, plan.getPerson(), trip.getTripAttributes() )
529  .stream()
530  .map(p -> {
531  if (p instanceof Activity && StageActivityTypeIdentifier.isStageActivity(((Activity) p).getType())) {
533  } else return p;
534  })
535  .collect(Collectors.toList());
536 
537  TripRouter.insertTrip(plan, nextAct, newTrip, trip.getDestinationActivity() ) ;
538  } else {
539  /*
540  * The agent is on a teleported leg and the trip will end at a real activity
541  * directly after it. So there is nothing we can replan.
542  */
543  return;
544  }
545 
547  }
548 
549  private List<? extends PlanElement> newTripToNewActivity( Facility currentLocationFacility, Activity newAct, String mainMode, double now, Person person, Attributes routingAttributes ) {
550  log.debug("entering newTripToNewActivity") ;
551 
552  Facility toFacility = FacilitiesUtils.toFacility( newAct, scenario.getActivityFacilities() );
553 
554  return tripRouter.calcRoute(mainMode, currentLocationFacility, toFacility, now, person, routingAttributes )
555  .stream()
556  .map(p -> {
557  if (p instanceof Activity && StageActivityTypeIdentifier.isStageActivity(((Activity) p).getType())) {
559  } else return p;
560  })
561  .collect(Collectors.toList());
562  }
563 
564  // replan from stage activity:
565  private void replanCurrentTripFromStageActivity(Trip trip, int tripElementsIndex,
566  String mainMode, double now, MobsimAgent agent) {
567 
568  log.debug("entering replanCurrentTripFromStageActivity for agent" + agent.getId()) ;
569 
571  List<PlanElement> planElements = plan.getPlanElements() ;
572  Person person = plan.getPerson() ;
573 
574  if ( ! ( trip.getTripElements().get(tripElementsIndex) instanceof Activity) ) {
575  throw new RuntimeException("Expected a stage activity as current plan element");
576  }
577  Activity currentStageActivity = (Activity) trip.getTripElements().get(tripElementsIndex);
578 
579  // (1) get new trip from current position to new activity:
580  Facility currentLocationFacility = FacilitiesUtils.toFacility(currentStageActivity, scenario.getActivityFacilities());
581  List<? extends PlanElement> newTripElements = newTripToNewActivity(currentLocationFacility, trip.getDestinationActivity(), mainMode,
582  now, person, trip.getTripAttributes() );
583 
584  // (2) prune the new trip up to the current leg:
585  // do nothing ?!
586 
587  // (2) modify current route:
588  // not necessary, we are at an activity ?!
589 
590  // (3) remove remainder of old trip after current stage activity in plan:
591  int pos = WithinDayAgentUtils.getCurrentPlanElementIndex(agent) + 1 ;
592 
593  while ( !planElements.get(pos).equals(trip.getDestinationActivity()) ) {
594  planElements.remove(pos) ;
595  }
596 
597  // (4) insert new trip after current activity:
598  for ( int ijk = 1 ; ijk < newTripElements.size() ; ijk++ ) {
599  planElements.add( pos + ijk, newTripElements.get(ijk) ) ;
600  }
602 
603  }
604  public static boolean insertEmptyTrip( Plan plan, Activity fromActivity, Activity toActivity, String mainMode, PopulationFactory pf ) {
605  List<Leg> list = Collections.singletonList( pf.createLeg( mainMode ) ) ;
606  TripRouter.insertTrip(plan, fromActivity, list, toActivity ) ;
607  return true ;
608  }
609  public final boolean insertEmptyTrip( Plan plan, Activity fromActivity, Activity toActivity, String mainMode ) {
610  return insertEmptyTrip( plan, fromActivity, toActivity, mainMode, this.pf ) ;
611  }
615  public final List<? extends PlanElement> replanFutureTrip( Trip trip, Plan plan, String mainMode ) {
616  double departureTime = timeInterpretation.decideOnActivityEndTimeAlongPlan( trip.getOriginActivity(), plan ).seconds() ;
617  return replanFutureTrip( trip, plan, mainMode, departureTime ) ;
618  }
619 
620  public final List<? extends PlanElement> replanFutureTrip(Trip trip, Plan plan, String routingMode,
621  double departureTime) {
622  return replanFutureTrip(trip, plan, routingMode, departureTime, tripRouter, scenario );
623  }
624 
625  // utility methods (plans splicing):
626  private static void replaceRemainderOfCurrentRoute(Leg currentLeg, List<? extends PlanElement> newTrip, MobsimAgent agent) {
627  Leg newCurrentLeg = (Leg) newTrip.get(0) ;
628  Gbl.assertNotNull(newCurrentLeg);
629 
630  // prune remaining route from current route:
631  NetworkRoute oldNWRoute = (NetworkRoute) currentLeg.getRoute();
632 
633  final Integer currentRouteLinkIdIndex = WithinDayAgentUtils.getCurrentRouteLinkIdIndex(agent);
634 
635  final NetworkRoute newNWRoute = (NetworkRoute)newCurrentLeg.getRoute();
636 
637  final List<Id<Link>> newLinksIds = newNWRoute.getLinkIds().subList(0,newNWRoute.getLinkIds().size()) ;
638  EditRoutes.spliceNewPathIntoOldRoute(currentRouteLinkIdIndex, newNWRoute.getEndLinkId(),
639  oldNWRoute, newLinksIds, agent.getCurrentLinkId()) ;
640 
641 // for (int ii = currentRouteLinkIdIndex; ii<oldNWRoute.getLinkIds().size() ; ii++ ) {
642 // oldNWRoute.getLinkIds().remove(ii) ;
643 // }
644 //
645 // // now add the new route (yyyyyy not sure if it starts with correct link)
646 // oldNWRoute.getLinkIds().addAll( newNWRoute.getLinkIds() ) ;
647 //
648 // // also change the arrival link id:
649 // oldNWRoute.setEndLinkId( newNWRoute.getEndLinkId() ) ;
651  }
652 
653  private List<PlanElement> defaultMergeOldAndNewCurrentPtLeg(Leg currentLeg, List<? extends PlanElement> newTrip,
654  MobsimAgent agent, TransitStopFacility nextStop, TransitPassengerRoute oldPtRoute) {
655  Leg newCurrentLeg = (Leg) newTrip.get(0);
656 
657  List<PlanElement> newPlanElementsAfterMerge = new ArrayList<>();
658 
659  // obviuosly pt routers always return first a walk leg to the transit stop, even if ask for a route from a transit stop
660  // to some place and the router wants to board a bus at that very same transit stop, the router will add a walk leg
661  // from that transit stop location to that very same transit stop.
662  if (newCurrentLeg.getRoute() instanceof TransitPassengerRoute) {
664  }
665 
666  // prune remaining route from current route:
668  oldPtRoute.getStartLinkId(), nextStop.getLinkId(), //
669  oldPtRoute.getAccessStopId(), nextStop.getId(), //
670  oldPtRoute.getLineId(), oldPtRoute.getRouteId()
671  );
672  if (oldPtRoute.getBoardingTime().isDefined()) {
673  route.setBoardingTime(oldPtRoute.getBoardingTime().seconds());
674  }
675  if (oldPtRoute.getTravelTime().isDefined()) {
676  // this is wrong but better than nothing.
677  // TODO: calculate travel time to "next stop" where the agent alights
678  route.setTravelTime(oldPtRoute.getTravelTime().seconds());
679  }
680  currentLeg.setRoute(route);
681  // add pt interaction activity
683  nextStop.getCoord(), nextStop.getLinkId());
684  act.setMaximumDuration(0.0);
685  newPlanElementsAfterMerge.add(act);
686  // an infill leg from pt stop to start of other mode necessary seems to be
687  // automatically produced while routing new mode from pt stop facility, so we don't have to add one
688 
689  for (int ijk = 0; ijk < newTrip.size(); ijk++) {
690  newPlanElementsAfterMerge.add(newPlanElementsAfterMerge.size(), newTrip.get(ijk));
691  }
693  return newPlanElementsAfterMerge;
694  }
695 
697  Id<TransitStopFacility> currentStopId, Id<TransitStopFacility> egressStopId) {
698  boolean afterCurrentStop = false;
699  for (TransitRouteStop stop : scenario.getTransitSchedule().getTransitLines().get(lineId).getRoutes().get(routeId).getStops()) {
700  if ( currentStopId.equals(stop.getStopFacility().getId()) ) {
701  afterCurrentStop = true;
702  }
703  if ( afterCurrentStop && egressStopId.equals(stop.getStopFacility().getId()) ) {
704  return true;
705  }
706  }
707  return false;
708  }
709 
710  // static methods:
716  @Deprecated // prefer the non-static methods
717  public static List<? extends PlanElement> replanFutureTrip(Trip trip, Plan plan, String routingMode,
718  double departureTime, TripRouter tripRouter, Scenario scenario) {
719  log.debug( "entering replanFutureTrip for agentid=" + plan.getPerson().getId() ) ;
720 
721  Person person = plan.getPerson();
722 
725 
726  final List<? extends PlanElement> newTrip = tripRouter.calcRoute(routingMode, fromFacility, toFacility, departureTime, person, trip.getTripAttributes())
727  .stream()
728  .map(p -> {
729  if (p instanceof Activity && StageActivityTypeIdentifier.isStageActivity(((Activity) p).getType())) {
731  } else return p;
732  })
733  .collect(Collectors.toList());
734 
735  TripRouter.insertTrip(plan, trip.getOriginActivity(), newTrip, trip.getDestinationActivity());
736 
737  return newTrip ;
738  }
739 
750  @Deprecated // prefer the non-static methods
751  public static List<? extends PlanElement> relocateFutureTrip(Trip trip, Plan plan, String mainMode,
752  double departureTime, TripRouter tripRouter, Scenario scenario) {
753  return replanFutureTrip(trip, plan, mainMode, departureTime, tripRouter, scenario );
754  }
755 
756  public Trip findTripAfterActivity(Plan plan, Activity activity) {
757  return TripStructureUtils.findTripStartingAtActivity(activity, plan);
758  }
759 
760 }
static Trip findTripAtPlanElementIndex(MobsimAgent agent, int index)
Definition: EditTrips.java:140
synchronized List<? extends PlanElement > calcRoute(final String mainMode, final Facility fromFacility, final Facility toFacility, final double departureTime, final Person person, final Attributes routingAttributes)
static Integer getCurrentRouteLinkIdIndex(MobsimAgent agent)
void replanCurrentTripFromStageActivity(Trip trip, int tripElementsIndex, String mainMode, double now, MobsimAgent agent)
Definition: EditTrips.java:565
TransitStopAgentTracker transitAgentTracker
Definition: EditTrips.java:89
Map< Id< TransitStopFacility >, TransitStopFacility > getFacilities()
static void assertIf(boolean flag)
Definition: Gbl.java:207
static Facility wrapLink(final Link link)
void replanCurrentLegWithNetworkRoute(Activity newAct, String mainMode, Leg currentLeg, double now, MobsimAgent agent, Attributes routingAttributes)
Definition: EditTrips.java:190
static Trip findCurrentTrip(MobsimAgent agent)
Definition: EditTrips.java:122
final void setTravelTime(final double travTime)
static List< PlanElement > insertTrip(final Plan plan, final Activity origin, final List<? extends PlanElement > trip, final Activity destination)
final PopulationFactory pf
Definition: EditTrips.java:86
final List<? extends PlanElement > replanFutureTrip(Trip trip, Plan plan, String routingMode, double departureTime)
Definition: EditTrips.java:620
static Integer getCurrentPlanElementIndex(MobsimAgent agent)
void replanCurrentTripFromLeg(Activity newAct, final PlanElement currentPlanElement, final String routingMode, double now, MobsimAgent agent, Attributes routingAttributes)
Definition: EditTrips.java:173
static PlanElement getCurrentPlanElement(MobsimAgent agent)
void arrangeNextAgentState(MobsimAgent agent)
static final String TRANSIT_ACTIVITY_TYPE
TransitRouteStop getStop(final TransitStopFacility stop)
static List<? extends PlanElement > replanFutureTrip(Trip trip, Plan plan, String routingMode, double departureTime, TripRouter tripRouter, Scenario scenario)
Definition: EditTrips.java:717
final boolean insertEmptyTrip(Plan plan, Activity fromActivity, Activity toActivity, String mainMode)
Definition: EditTrips.java:609
Trip findTripAfterActivity(Plan plan, Activity activity)
Definition: EditTrips.java:756
static void putPersonAttribute(HasPlansAndId<?, ?> person, String key, Object value)
static Trip findTripAtPlanElement(MobsimAgent agent, PlanElement pe)
Definition: EditTrips.java:126
Collection< AgentTracker > getAgentTrackers()
Definition: QSim.java:705
void removeAgentFromStop(final PTPassengerAgent agent, final Id< TransitStopFacility > stopId)
final TimeInterpretation timeInterpretation
Definition: EditTrips.java:91
void replanCurrentLegWithGenericRoute(Activity newAct, String routingMode, Leg currentLeg, double now, MobsimAgent agent)
Definition: EditTrips.java:468
static final boolean isStageActivity(final String activityType)
OptionalTime decideOnActivityEndTimeAlongPlan(Activity activity, Plan plan)
void replanCurrentLegWithTransitRoute(Activity newAct, String routingMode, Leg currentLeg, double now, MobsimAgent agent, Attributes routingAttributes)
Definition: EditTrips.java:222
Id< TransitStopFacility > getEgressStopId()
final List<? extends PlanElement > replanFutureTrip(Trip trip, Plan plan, String mainMode)
Definition: EditTrips.java:615
boolean transitRouteLaterStopsAt(Id< TransitLine > lineId, Id< TransitRoute > routeId, Id< TransitStopFacility > currentStopId, Id< TransitStopFacility > egressStopId)
Definition: EditTrips.java:696
static List< Trip > getTrips(final Plan plan)
List< PlanElement > getPlanElements()
static final String NOT_IMPLEMENTED
Definition: Gbl.java:50
static void assertNotNull(Object obj)
Definition: Gbl.java:212
EventsManager getEventsManager()
Definition: QSim.java:565
static boolean insertEmptyTrip(Plan plan, Activity fromActivity, Activity toActivity, String mainMode, PopulationFactory pf)
Definition: EditTrips.java:604
Map< Id< Link >, ? extends Link > getLinks()
static Activity createActivityFromCoordAndLinkId(String type, Coord coord, Id< Link > linkId)
EditTrips(TripRouter tripRouter, Scenario scenario, InternalInterface internalInterface, TimeInterpretation timeInterpretation)
Definition: EditTrips.java:93
ActivityFacilities getActivityFacilities()
static List<? extends PlanElement > relocateFutureTrip(Trip trip, Plan plan, String mainMode, double departureTime, TripRouter tripRouter, Scenario scenario)
Definition: EditTrips.java:751
static Activity createActivity(Activity act)
List<? extends PlanElement > newTripToNewActivity(Facility currentLocationFacility, Activity newAct, String mainMode, double now, Person person, Attributes routingAttributes)
Definition: EditTrips.java:549
TransitSchedule getTransitSchedule()
boolean equals(Object obj)
Definition: Id.java:139
Map< Id< TransitLine >, TransitLine > getTransitLines()
List< PlanElement > defaultMergeOldAndNewCurrentPtLeg(Leg currentLeg, List<? extends PlanElement > newTrip, MobsimAgent agent, TransitStopFacility nextStop, TransitPassengerRoute oldPtRoute)
Definition: EditTrips.java:653
static void replaceRemainderOfCurrentRoute(Leg currentLeg, List<? extends PlanElement > newTrip, MobsimAgent agent)
Definition: EditTrips.java:626
static Facility toFacility(final Activity toWrap, ActivityFacilities activityFacilities)
final boolean replanCurrentTrip(MobsimAgent agent, double now, String routingMode)
Definition: EditTrips.java:144
static Trip findTripStartingAtActivity(final Activity activity, final Plan plan)
Id< TransitStopFacility > getAccessStopId()
final InternalInterface internalInterface
Definition: EditTrips.java:87