MATSIM
PrepareForSimImpl.java
Go to the documentation of this file.
1 
2 /* *********************************************************************** *
3  * project: org.matsim.*
4  * PrepareForSimImpl.java
5  * *
6  * *********************************************************************** *
7  * *
8  * copyright : (C) 2019 by the members listed in the COPYING, *
9  * LICENSE and WARRANTY file. *
10  * email : info at matsim dot org *
11  * *
12  * *********************************************************************** *
13  * *
14  * This program is free software; you can redistribute it and/or modify *
15  * it under the terms of the GNU General Public License as published by *
16  * the Free Software Foundation; either version 2 of the License, or *
17  * (at your option) any later version. *
18  * See also COPYING, LICENSE and WARRANTY file *
19  * *
20  * *********************************************************************** */
21 
22 package org.matsim.core.controler;
23 
24 
25 import jakarta.inject.Inject;
26 import jakarta.inject.Provider;
27 import org.apache.logging.log4j.LogManager;
28 import org.apache.logging.log4j.Logger;
29 import org.matsim.api.core.v01.Id;
30 import org.matsim.api.core.v01.Scenario;
37 import org.matsim.core.config.groups.*;
39 import org.matsim.core.gbl.Gbl;
54 import org.matsim.vehicles.Vehicle;
57 
58 import javax.annotation.Nullable;
59 import java.util.*;
60 
62 
63 public final class PrepareForSimImpl implements PrepareForSim, PrepareForMobsim {
64  // I think it is ok to have this public final. Since one may want to use it as a delegate. kai, may'18
65  // but how should that work with a non-public constructor? kai, jun'18
66  // Well, I guess it can be injected as well?!
67  // bind( PrepareForSimImpl.class ) ;
68  // bind( PrepareForSim.class ).to( MyPrepareForSimImpl.class ) ;
69 
70  private static Logger log = LogManager.getLogger(PrepareForSim.class);
71 
73  private final Scenario scenario;
74  private final Network network;
75  private final Population population;
77  private final Provider<TripRouter> tripRouterProvider;
83 
87  @Nullable
88  @Inject
89  private Set<PersonPrepareForSimAlgorithm> prepareForSimAlgorithms;
90 
95  @Inject
96  PrepareForSimImpl(GlobalConfigGroup globalConfigGroup, Scenario scenario, Network network,
97  Population population, ActivityFacilities activityFacilities, Provider<TripRouter> tripRouterProvider,
98  QSimConfigGroup qSimConfigGroup, FacilitiesConfigGroup facilitiesConfigGroup,
99  PlansConfigGroup plansConfigGroup,
100  MainModeIdentifier backwardCompatibilityMainModeIdentifier,
101  TimeInterpretation timeInterpretation) {
102  this.globalConfigGroup = globalConfigGroup;
103  this.scenario = scenario;
104  this.network = network;
105  this.population = population;
106  this.activityFacilities = activityFacilities;
107  this.tripRouterProvider = tripRouterProvider;
108  this.qSimConfigGroup = qSimConfigGroup;
109  this.facilitiesConfigGroup = facilitiesConfigGroup;
110  this.plansConfigGroup = plansConfigGroup;
111  this.backwardCompatibilityMainModeIdentifier = backwardCompatibilityMainModeIdentifier;
112  this.timeInterpretation = timeInterpretation;
113  }
114 
115 
116  @Override
117  public void run() {
118  /*
119  * Create single-mode network here and hand it over to PersonPrepareForSim. Otherwise, each instance would create its
120  * own single-mode network. However, this assumes that the main mode is car - which PersonPrepareForSim also does. Should
121  * be probably adapted in a way that other main modes are possible as well. cdobler, oct'15.
122  */
123  final Network carOnlyNetwork;
124  if (NetworkUtils.isMultimodal(network)) {
125  log.info("Network seems to be multimodal. Create car-only network which is handed over to PersonPrepareForSim.");
127  carOnlyNetwork = NetworkUtils.createNetwork(scenario.getConfig().network());
128  HashSet<String> modes = new HashSet<>();
129  modes.add(TransportMode.car);
130  filter.filter(carOnlyNetwork, modes);
131  } else {
132  carOnlyNetwork = network;
133  }
134 
135  //matsim-724
136  switch(this.facilitiesConfigGroup.getFacilitiesSource()){
137  case none:
138 // Gbl.assertIf( this.activityFacilities.getFacilities().isEmpty() );
139  // I have at least one use case where people use the facilities as some kind
140  // of database for stuff, but don't run the activities off them. I have thus
141  // disabled the above check. yy We need to think about what we want to
142  // do in such cases; might want to auto-generate our facilities as below
143  // and _add_ them to the existing facilities. kai, feb'18
144  break;
145  case fromFile:
146  case setInScenario:
147  Gbl.assertIf(! this.activityFacilities.getFacilities().isEmpty() );
148  break;
149  case onePerActivityLinkInPlansFile:
150  /* fall-through */ // switch is inside "FacilitiesFromPopulation" method!
151  case onePerActivityLocationInPlansFile:
152 // FacilitiesFromPopulation facilitiesFromPopulation = new FacilitiesFromPopulation(activityFacilities, facilitiesConfigGroup);
153  FacilitiesFromPopulation facilitiesFromPopulation = new FacilitiesFromPopulation(scenario);
154 
155 // facilitiesFromPopulation.setAssignLinksToFacilitiesIfMissing(true, network);
156  // (yy not sure if the false setting makes sense at all. kai, jul'18)
157 
158 // facilitiesFromPopulation.assignOpeningTimes(facilitiesConfigGroup.isAssigningOpeningTime(), scenario.getConfig().planCalcScore());
159  facilitiesFromPopulation.run(population);
160  // Note that location choice, when switched on, should now either use the facilities generated here,
161  // or come with explicit pre-existing facilities. kai, jul'18
162  break;
163  default:
164  throw new RuntimeException("Facilities source '"+this.facilitiesConfigGroup.getFacilitiesSource()+"' is not implemented.");
165  }
166 
167  // get links for facilities
168  // using car only network to get the links for facilities. Amit July'18
169  XY2LinksForFacilities.run(carOnlyNetwork, this.activityFacilities);
170 
171  // yyyy from a behavioral perspective, the vehicle must be somehow linked to
172  // the person (maybe via the household). kai, feb'18
173  // each agent receives a vehicle for each main mode now. janek, aug'19
175 
177 
178  // Can be null if instantiated via constructor, which should only happen in tests
179  if (prepareForSimAlgorithms != null) {
180  // This does not nake use of multi-threading because it can not be assumed that these instances are thread-safe
181  // thread-safety could be ensured with Providers, but they can not be used automatically in conjunction with set binders.
182  for (PersonPrepareForSimAlgorithm algo : prepareForSimAlgorithms) {
183  for (Person person : population.getPersons().values()) {
184  algo.run(person);
185  }
186  }
187  }
188 
189  // make sure all routes are calculated.
190  // the above creation of vehicles per agent has to be run before executing the initial routing here. janek, aug'19
191  // At least xy2links is needed here, i.e. earlier than PrepareForMobsimImpl. It could, however, presumably be separated out
192  // (i.e. we introduce a separate PersonPrepareForMobsim). kai, jul'18
193  ParallelPersonAlgorithmUtils.run(population, globalConfigGroup.getNumberOfThreads(),
194  () -> new PersonPrepareForSim(new PlanRouter(tripRouterProvider.get(), activityFacilities, timeInterpretation), scenario,
195  carOnlyNetwork)
196  );
197 
198  if (scenario instanceof Lockable) {
199  ((Lockable)scenario).setLocked();
200  // see comment in ScenarioImpl. kai, sep'14
201  }
202 
203  if (population instanceof Lockable) {
204  ((Lockable) population).setLocked();
205  }
206 
207  if ( network instanceof Lockable ) {
208  ((Lockable) network).setLocked();
209  }
210 
211  if (activityFacilities instanceof Lockable) {
212  ((Lockable) activityFacilities).setLocked();
213  }
214 
215  // (yyyy means that if someone replaces prepareForSim and does not add the above lines, the containers are not locked. kai, nov'16)
216  }
217 
218  // only warn once that legacy vehicle id is used
219  private static boolean hasWarned = false;
220 
222 
223  final Map<String, VehicleType> modeVehicleTypes = getVehicleTypesForAllNetworkAndMainModes();
224 
225  for (Person person : scenario.getPopulation().getPersons().values()) {
226 
227 
228  Map<String, Id<Vehicle>> modeToVehicle = new HashMap<>();
229 
230  // optional attribute, that can be null
231  Map<String, Id<VehicleType>> modeTypes = VehicleUtils.getVehicleTypes(person);
232 
233  for (Map.Entry<String, VehicleType> modeType : modeVehicleTypes.entrySet()) {
234 
235  String mode = modeType.getKey();
236 
237  Id<Vehicle> vehicleId = createVehicleId(person, mode);
238 
239  // get the type
240  VehicleType type = modeType.getValue();
241 
242  // Use the person attribute to map to a more specific vehicle type
243  if (modeTypes != null && modeTypes.containsKey(mode)) {
244  Id<VehicleType> typeId = modeTypes.get(mode);
245  type = scenario.getVehicles().getVehicleTypes().get(typeId);
246  if (type == null) {
247  throw new IllegalStateException("Vehicle type " + typeId + " specified for person " + person.getId() + ", but not found in scenario.");
248  }
249  }
250 
251  createAndAddVehicleIfNecessary(vehicleId, type);
252 
253  // write mode-string to vehicle-id into a map
254  modeToVehicle.put(mode, vehicleId);
255  }
256 
257  VehicleUtils.insertVehicleIdsIntoAttributes(person, modeToVehicle);
258  }
259  }
260 
261  private Id<Vehicle> createVehicleId(Person person, String modeType) {
262 
263  if (qSimConfigGroup.getUsePersonIdForMissingVehicleId() && TransportMode.car.equals(modeType)) {
264  if (!hasWarned) {
265  log.warn("'usePersonIdForMissingVehicleId' is deprecated. It will be removed soon.");
266  hasWarned = true;
267  }
268 
269  return Id.createVehicleId(person.getId());
270  }
271 
272  return VehicleUtils.createVehicleId(person, modeType);
273  }
274 
275  private Map<String, VehicleType> getVehicleTypesForAllNetworkAndMainModes() {
276 
277  Map<String, VehicleType> modeVehicleTypes = new HashMap<>();
278 
279  if (qSimConfigGroup.getVehiclesSource().equals(QSimConfigGroup.VehiclesSource.fromVehiclesData)) {
280  // in this case the user has to do everything on their own and we can short circuit here.
281  return modeVehicleTypes;
282  }
283 
284  Set<String> modes = new HashSet<>(qSimConfigGroup.getMainModes());
285  modes.addAll(scenario.getConfig().routing().getNetworkModes());
286 
287  for (String mode : modes) {
288  VehicleType type;
289  switch (qSimConfigGroup.getVehiclesSource()) {
290  case defaultVehicle:
292  if (!scenario.getVehicles().getVehicleTypes().containsKey(type.getId())){
293  scenario.getVehicles().addVehicleType( type );
294  }
295  break;
296  case modeVehicleTypesFromVehiclesData:
297  type = scenario.getVehicles().getVehicleTypes().get(Id.create(mode, VehicleType.class));
298  if ( type==null ) {
299  log.fatal( "Could not find requested vehicle type =" + mode + ". With config setting " + modeVehicleTypesFromVehiclesData.toString() + ", you need");
300  log.fatal( "to add, for each mode that performs network routing and/or is used as network/main mode in the qsim, a vehicle type for that mode." );
301  throw new RuntimeException("Could not find requested vehicle type = " + mode + ". See above.");
302  }
303  break;
304  default:
305  throw new RuntimeException(qSimConfigGroup.getVehiclesSource().toString() + " is not implemented yet.");
306  }
307  Gbl.assertNotNull(type);
308  modeVehicleTypes.put(mode, type);
309  }
310  return modeVehicleTypes;
311  }
312 
313  private void createAndAddVehicleIfNecessary(Id<Vehicle> vehicleId, VehicleType vehicleType) {
314 
315  if (!scenario.getVehicles().getVehicles().containsKey(vehicleId)) {
316 
317  switch (qSimConfigGroup.getVehiclesSource()) {
318  case defaultVehicle:
319  case modeVehicleTypesFromVehiclesData:
320  Vehicle vehicle = scenario.getVehicles().getFactory().createVehicle(vehicleId, vehicleType);
321  scenario.getVehicles().addVehicle(vehicle);
322  break;
323  default:
324  throw new RuntimeException("Expecting a vehicle id which is missing in the vehicles database: " + vehicleId);
325  }
326  }
327  }
328 
330 
337  for (Person person : population.getPersons().values()) {
338  for (Plan plan : person.getPlans()) {
339  for (Trip trip : TripStructureUtils.getTrips(plan.getPlanElements())) {
340  List<Leg> legs = trip.getLegsOnly();
341  if (legs.size() >= 1) {
342  String routingMode = TripStructureUtils.getRoutingMode(legs.get(0));
343 
344  for (Leg leg : legs) {
345  // 1. check all legs either have the same routing mode or all have routingMode==null
346  if (TripStructureUtils.getRoutingMode(leg) == null) {
347  if (routingMode != null) {
348  String errorMessage = "Found a mixed trip having some legs with routingMode set and others without. "
349  + "This is inconsistent. Agent id: " + person.getId().toString()
350  + "\nTrip: " + trip.getTripElements().toString();
351  log.error(errorMessage);
352  throw new RuntimeException(errorMessage);
353  }
354 
355  } else {
356  if (routingMode.equals(TripStructureUtils.getRoutingMode(leg))) {
357  TripStructureUtils.setRoutingMode(leg, routingMode);
358  } else {
359  String errorMessage = "Found a trip whose legs have different routingModes. "
360  + "This is inconsistent. Agent id: " + person.getId().toString()
361  + "\nTrip: " + trip.getTripElements().toString();
362  log.error(errorMessage);
363  throw new RuntimeException(errorMessage);
364  }
365  }
366  }
367 
368  // add routing mode
369  if (routingMode == null) {
370  if (legs.size() == 1) {
371  // there is only a single leg (e.g. after Trips2Legs and a mode choice replanning
372  // module)
373 
374  String oldMainMode = replaceOutdatedFallbackModesAndReturnOldMainMode(legs.get(0), null);
375  if (oldMainMode != null) {
376  routingMode = oldMainMode;
377  TripStructureUtils.setRoutingMode(legs.get(0), routingMode);
378  } else {
379  // leg has a real mode (not an outdated fallback mode)
380  routingMode = legs.get(0).getMode();
381  TripStructureUtils.setRoutingMode(legs.get(0), routingMode);
382  }
383  } else {
385  for (Leg leg : legs) {
386  replaceOutdatedAccessEgressWalkModes(leg, routingMode);
387  }
389  person, trip);
390  } else {
391  String errorMessage = "Found a trip with multiple legs and no routingMode. "
392  + "Person id " + person.getId().toString()
393  + "\nTrip: " + trip.getTripElements().toString()
394  + "\nTerminating. Take care to inject an adequate MainModeIdentifier and set config switch "
395  + "plansConfigGroup.setHandlingOfPlansWithoutRoutingMode("
397  log.error(errorMessage);
398  throw new RuntimeException(errorMessage);
399  }
400  }
401  }
402 
403  for (Leg leg : legs) {
404  // check before replaceOutdatedAccessEgressHelperModes
405  if (leg.getMode().equals(TransportMode.walk) && leg.getRoute() instanceof NetworkRoute) {
406  log.error(
407  "Found a walk leg with a NetworkRoute. This is the only allowed use case of having "
408  + "non_network_walk as an access/egress mode. PrepareForSimImpl replaces "
409  + "non_network_walk with walk, because access/egress to modes other than walk should "
410  + "use the walk Router. If this causes any problem please report to gleich or kai -nov'19");
411  }
412  }
413 
414  for (Leg leg : legs) {
415  replaceOutdatedAccessEgressWalkModes(leg, routingMode);
416  replaceOutdatedNonNetworkWalk(leg, routingMode);
418  }
419  }
420  }
421  }
422  }
423  }
424 
426  String routingMode;
427  if (insistingOnPlansWithoutRoutingModeLogWarnNotShownYet) {
428  log.warn(
429  "Insisting on using backward compatibility MainModeIdentifier instead of setting routingMode directly.");
430  insistingOnPlansWithoutRoutingModeLogWarnNotShownYet = false;
431  }
432  if (backwardCompatibilityMainModeIdentifier == null) {
433  log.error(
434  "Found a trip without routingMode, but there is no MainModeIdentifier set up for PrepareForSim, so cannot infer the routing mode from a MainModeIdentifier. Trip: "
435  + trip.getTripElements());
436  throw new RuntimeException("no MainModeIdentifier set up for PrepareForSim");
437  }
438  routingMode = backwardCompatibilityMainModeIdentifier.identifyMainMode(trip.getTripElements());
439  if (routingMode != null) {
440  for (Leg leg : trip.getLegsOnly()) {
441  TripStructureUtils.setRoutingMode(leg, routingMode);
442  }
443  } else {
444  String errorMessage = "Found a trip whose legs had no routingMode. "
445  + "The backwardCompatibilityMainModeIdentifier could not identify the mode. " + "Agent id: "
446  + person.getId().toString() + "\nTrip: " + trip.getTripElements().toString();
447  log.error(errorMessage);
448  throw new RuntimeException(errorMessage);
449  }
450  return routingMode;
451  }
452 
453  private void replaceOutdatedAccessEgressWalkModes(Leg leg, String routingMode) {
454  // access_walk and egress_walk were replaced by non_network_walk
455  if (leg.getMode().equals("access_walk") || leg.getMode().equals("egress_walk")) {
457  TripStructureUtils.setRoutingMode(leg, routingMode);
458  }
459  }
460 
461  // non_network_walk as access/egress to modes other than walk on the network was replaced by walk. -
462  // kn/gl-nov'19
463  private void replaceOutdatedNonNetworkWalk(Leg leg, String routingMode) {
464  if (leg.getMode().equals(TransportMode.non_network_walk)) {
466  TripStructureUtils.setRoutingMode(leg, routingMode);
467  }
468  }
469 
477  private String replaceOutdatedFallbackModesAndReturnOldMainMode(Leg leg, String routingMode) {
478  // transit_walk was replaced by walk (formerly fallback and access/egress/transfer to pt mode)
479  if (leg.getMode().equals(TransportMode.transit_walk)) {
481  TripStructureUtils.setRoutingMode(leg, routingMode);
482  return TransportMode.pt;
483  }
484 
485  // replace drt_walk etc. (formerly fallback and access/egress to drt modes)
486  if (leg.getMode().endsWith("_walk") && !leg.getMode().equals(TransportMode.non_network_walk)) {
487  String oldMainMode = leg.getMode().substring(0, leg.getMode().length() - 5);
489  TripStructureUtils.setRoutingMode(leg, routingMode);
490  return oldMainMode;
491  }
492 
493  // replace drt_fallback etc. (formerly fallback for drt modes)
494  if (leg.getMode().endsWith("_fallback")) {
495  String oldMainMode = leg.getMode().substring(0, leg.getMode().length() - 9);
497  TripStructureUtils.setRoutingMode(leg, routingMode);
498  return oldMainMode;
499  }
500 
501  return null;
502  }
503 }
final FacilitiesConfigGroup facilitiesConfigGroup
Map< Id< ActivityFacility >, ? extends ActivityFacility > getFacilities()
static< T > Id< T > get(int index, final Class< T > type)
Definition: Id.java:112
String replaceOutdatedFallbackModesAndReturnOldMainMode(Leg leg, String routingMode)
static void assertIf(boolean flag)
Definition: Gbl.java:207
static Id< Vehicle > createVehicleId(final long key)
Definition: Id.java:220
final NetworkConfigGroup network()
Definition: Config.java:411
static boolean isMultimodal(final Network network)
VehiclesFactory getFactory()
void filter(final Network subNetwork, final Set< String > extractModes)
Map< Id< VehicleType >, VehicleType > getVehicleTypes()
static Map< String, Id< VehicleType > > getVehicleTypes(Person person)
String identifyMainMode(List<? extends PlanElement > tripElements)
void addVehicleType(final VehicleType type)
Map< Id< Person >,? extends Person > getPersons()
static< T > Id< T > create(final long key, final Class< T > type)
Definition: Id.java:68
static void setRoutingMode(Leg leg, String mode)
final Provider< TripRouter > tripRouterProvider
void addVehicle(final Vehicle v)
final MainModeIdentifier backwardCompatibilityMainModeIdentifier
final HandlingOfPlansWithoutRoutingMode getHandlingOfPlansWithoutRoutingMode()
static List< Trip > getTrips(final Plan plan)
static VehicleType createDefaultVehicleType()
static void run(final Population population, final int numberOfThreads, final PersonAlgorithm algorithm)
static void assertNotNull(Object obj)
Definition: Gbl.java:212
RoutingConfigGroup routing()
Definition: Config.java:439
void replaceOutdatedNonNetworkWalk(Leg leg, String routingMode)
void createAndAddVehicleIfNecessary(Id< Vehicle > vehicleId, VehicleType vehicleType)
Vehicle createVehicle(Id< Vehicle > id, VehicleType type)
final Id< VehicleType > getId()
static Id< Vehicle > createVehicleId(Person person, String mode)
Map< Id< Vehicle >, Vehicle > getVehicles()
Set< PersonPrepareForSimAlgorithm > prepareForSimAlgorithms
Id< Vehicle > createVehicleId(Person person, String modeType)
Map< String, VehicleType > getVehicleTypesForAllNetworkAndMainModes()
String getAndAddRoutingModeFromBackwardCompatibilityMainModeIdentifier(Person person, Trip trip)
static void insertVehicleIdsIntoAttributes(Person person, Map< String, Id< Vehicle >> modeToVehicle)
void replaceOutdatedAccessEgressWalkModes(Leg leg, String routingMode)