MATSIM
PersonPrepareForSim.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * PersonPrepareForSim.java
4  * *
5  * *********************************************************************** *
6  * *
7  * copyright : (C) 2007 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.core.population.algorithms;
22 
23 import org.apache.logging.log4j.LogManager;
24 import org.apache.logging.log4j.Logger;
25 import org.matsim.api.core.v01.Id;
26 import org.matsim.api.core.v01.Scenario;
45 
46 import java.util.List;
47 import java.util.Optional;
48 import java.util.Set;
49 import java.util.stream.Stream;
50 
63 public final class PersonPrepareForSim extends AbstractPersonAlgorithm {
64 
65  private final PlanAlgorithm router;
66  private final XY2Links xy2links;
68 
69  private static final Logger log = LogManager.getLogger(PersonPrepareForSim.class);
70  private final Scenario scenario;
71 
72  /*
73  * To be used by the controller which creates multiple instances of this class which would
74  * create multiple copies of a car-only-network. Instead, we can create that network once in
75  * the Controller and re-use it for each new instance. cdobler, sep'15
76  */
77  public PersonPrepareForSim(final PlanAlgorithm router, final Scenario scenario, final Network carOnlyNetwork) {
78  super();
79  this.router = router;
80  if (NetworkUtils.isMultimodal(carOnlyNetwork)) {
81  throw new RuntimeException("Expected carOnlyNetwork not to be multi-modal. Aborting!");
82  }
83  this.xy2links = new XY2Links(carOnlyNetwork, scenario.getActivityFacilities());
84  this.activityFacilities = scenario.getActivityFacilities();
85  this.scenario = scenario ;
86  }
87 
88  public PersonPrepareForSim(final PlanAlgorithm router, final Scenario scenario) {
89  super();
90  this.router = router;
91  Network net = scenario.getNetwork();
92  if (NetworkUtils.isMultimodal( scenario.getNetwork() )) {
93  log.info("Network seems to be multimodal. XY2Links will only use car links.");
95  net = NetworkUtils.createNetwork(scenario.getConfig().network());
96  filter.filter(net, Set.of(TransportMode.car));
97  }
98 
99  this.xy2links = new XY2Links(net, scenario.getActivityFacilities());
100  this.activityFacilities = scenario.getActivityFacilities();
101  this.scenario = scenario ;
102  }
103 
104  @Override
105  public void run(final Person person) {
106  // first make sure we have a selected plan
107  Plan selectedPlan = person.getSelectedPlan();
108  if (selectedPlan == null) {
109  // the only way no plan can be selected should be when the person has no plans at all
110  log.warn("Person " + person.getId() + " has no plans!");
111  return;
112  }
113 
114  // yyyyyy need to find out somewhere here if the access/egress legs of the incoming plans
115  // are consistent with the config setting. Otherwise need to re-route all of them. kai, jul'18
116 
117  for (Plan plan : person.getPlans()) {
118  boolean needsXY2Links = false;
119  boolean needsReRoute = false;
120 
121  // for backward compatibility: add routingMode to legs if not present
123 
124  // make sure all the plans have valid act-locations and valid routes
125  planLoop: for (PlanElement pe : plan.getPlanElements()) {
126  switch (pe) {
127  case Activity act -> {
128  boolean needsReComputation = needsReComputation(act);
129  if (needsReComputation) {
130  needsXY2Links = true;
131  needsReRoute = true;
132  break planLoop;
133  }
134  }
135  case Leg leg -> {
136  needsReRoute |= needsReRoute(person, leg);
137  }
138  default -> throw new IllegalStateException("Unexpected PlanElement: " + pe);
139  }
140  }
141  if (needsXY2Links) {
142  this.xy2links.run(plan);
143  }
144  if (needsReRoute) {
145  this.router.run(plan);
146  }
147  }
148 
149  }
150 
151  private boolean needsReRoute(Person person, Leg leg) {
152  if (TripStructureUtils.getRoutingMode(leg) == null) {
153  String errorMessage = "Routing mode not set for leg :" + leg + " of agent id " + person.getId().toString();
154  log.error( errorMessage );
155  throw new RuntimeException( errorMessage );
156  }
157 
158  if (leg.getRoute() == null) {
159  return true;
160  }
161 
162  checkModeConsistent(person, leg);
163 
164  if(!Double.isNaN(leg.getRoute().getDistance())){
165  return false;
166  }
167 
168  adaptRoute(leg);
169 
170  return false;
171  }
172 
173  private void adaptRoute(Leg leg) {
174  if (leg.getRoute() instanceof NetworkRoute){
175  /* So far, 1.0 is always used as relative position on start and end link.
176  * This means that the end link is considered in route distance and the start link not.
177  * tt feb'16
178  */
179  double relativePositionStartLink = scenario.getConfig().global().getRelativePositionOfEntryExitOnLink() ;
180  double relativePositionEndLink = scenario.getConfig().global().getRelativePositionOfEntryExitOnLink() ;
181 // dist = RouteUtils.calcDistance((NetworkRoute) leg.getRoute(), relativePositionStartLink, relativePositionEndLink, this.network);
182  double dist = RouteUtils.calcDistance((NetworkRoute) leg.getRoute(), relativePositionStartLink, relativePositionEndLink, scenario.getNetwork() );
183  leg.getRoute().setDistance(dist);
184  // using the full network for the distance calculation. kai, jul'18
185  } else if (leg.getRoute() instanceof ExperimentalTransitRoute) {
186  // replace deprecated ExperimentalTransitRoute with DefaultTransitPassengerRoute
189  oldRoute.getStartLinkId(),
190  oldRoute.getEndLinkId(),
191  oldRoute.getAccessStopId(),
192  oldRoute.getEgressStopId(),
193  oldRoute.getLineId(),
194  oldRoute.getRouteId());
195  leg.setRoute(newRoute);
196  }
197  }
198 
199  private void checkModeConsistent(Person person, Leg leg) {
201  return;
202  }
203 
204  if(!(leg.getRoute() instanceof NetworkRoute networkRoute)) {
205  return;
206  }
207 
208  Optional<Id<Link>> inconsistentLink = networkRoute.getLinkIds().stream()
209  .filter(linkId -> {
210  Link link = scenario.getNetwork().getLinks().get(linkId);
211  return link == null || !link.getAllowedModes().contains(leg.getMode());
212  })
213  .findFirst();
214 
215  if (inconsistentLink.isPresent()) {
216  String errorMessage = "Route inconsistent with link modes for link: " + inconsistentLink.get() + " Person " + person.getId() + "; Leg '" + leg + "'";
217  log.error(errorMessage + "\n Consider cleaning inconsistent routes by using PopulationUtils.checkRouteModeAndReset()." +
218  "\n If this is intended, set the routing config parameter 'networkRouteConsistencyCheck' to 'disable'.");
219  throw new RuntimeException(errorMessage);
220  }
221  }
222 
223  private boolean needsReComputation(Activity act) {
224  return act.getLinkId() == null // neither activity nor facility has a link
225  &&
226  //this check is necessary here, else, XY2Links will put the link/coord back to activity which is clear violation of facilitiesConfigGroup.removingLinksAndCoordinates =true. Amit July'18
227  (act.getFacilityId() == null
228  || this.activityFacilities.getFacilities().isEmpty()
229  || this.activityFacilities.getFacilities().get(act.getFacilityId()) == null
230  || this.activityFacilities.getFacilities().get(act.getFacilityId()).getLinkId() == null);
231  }
232 
233  private void checkAndAddRoutingMode(Plan plan) {
234  for (Trip trip : TripStructureUtils.getTrips(plan.getPlanElements())) {
235  List<Leg> legs = trip.getLegsOnly();
236  if (!legs.isEmpty()) {
237  String routingMode = TripStructureUtils.getRoutingMode(legs.get(0));
238 
239  for (Leg leg : legs) {
240  // check all legs either have the same routing mode or all have routingMode==null
241  String existingRoutingMode = TripStructureUtils.getRoutingMode(leg);
242  if (existingRoutingMode == null) {
243  if (routingMode == null) {
244  // outdated initial plan without routingMode
245  } else {
246  String errorMessage = "Found a mixed trip, some legs with routingMode and others without. "
247  + "This is inconsistent. Agent id: " + plan.getPerson().getId().toString();
248  log.error(errorMessage);
249  throw new RuntimeException(errorMessage);
250  }
251  } else {
252  if (!routingMode.equals(existingRoutingMode)) {
253  String errorMessage = "Found a trip whose legs have different routingModes. "
254  + "This is inconsistent. Agent id: " + plan.getPerson().getId().toString();
255  log.error(errorMessage);
256  throw new RuntimeException(errorMessage);
257  }
258  }
259  }
260 
261  // add routing mode
262  if (routingMode == null) {
263  if (legs.size() == 1) {
264  // there is only a single leg (e.g. after Trips2Legs and a mode choice replanning module)
265  routingMode = legs.get(0).getMode();
266  if (routingMode.equals(TransportMode.transit_walk)) {
267  String errorMessage = "Found a trip of only one leg of mode transit_walk. "
268  + "This should not happen during simulation since transit_walk was replaced by walk and "
269  + "routingMode. Agent id: " + plan.getPerson().getId().toString();
270  log.error(errorMessage);
271  throw new RuntimeException(errorMessage);
272  }
273  TripStructureUtils.setRoutingMode(legs.get(0), routingMode);
274  } else {
275  String errorMessage = "Found a trip whose legs have no routingMode. "
276  + "This is only allowed for (outdated) input plans, not during simulation (after PrepareForSim). Agent id: "
277  + plan.getPerson().getId().toString();
278  log.error(errorMessage);
279  throw new RuntimeException(errorMessage);
280  }
281  }
282  }
283  }
284  }
285 }
Map< Id< ActivityFacility >, ? extends ActivityFacility > getFacilities()
void setDistance(final double distance)
final NetworkConfigGroup network()
Definition: Config.java:411
static boolean isMultimodal(final Network network)
void filter(final Network subNetwork, final Set< String > extractModes)
NetworkRouteConsistencyCheck getNetworkRouteConsistencyCheck()
PersonPrepareForSim(final PlanAlgorithm router, final Scenario scenario, final Network carOnlyNetwork)
PersonPrepareForSim(final PlanAlgorithm router, final Scenario scenario)
static void setRoutingMode(Leg leg, String mode)
static List< Trip > getTrips(final Plan plan)
List< PlanElement > getPlanElements()
static double calcDistance(final NetworkRoute networkRoute, final double relPosOnDepartureLink, final double relPosOnArrivalLink, final Network network)
RoutingConfigGroup routing()
Definition: Config.java:439
Map< Id< Link >, ? extends Link > getLinks()
Id< ActivityFacility > getFacilityId()
ActivityFacilities getActivityFacilities()
final GlobalConfigGroup global()
Definition: Config.java:395
abstract List<? extends T > getPlans()