MATSIM
PopulationAgentSource.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * *
4  * *********************************************************************** *
5  * *
6  * copyright : (C) 2009 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.agents;
21 
22 import org.apache.logging.log4j.LogManager;
23 import org.apache.logging.log4j.Logger;
24 import org.matsim.api.core.v01.Id;
26 import org.matsim.api.core.v01.population.*;
27 import org.matsim.core.config.Config;
29 import org.matsim.core.gbl.Gbl;
32 import org.matsim.core.mobsim.qsim.QSim;
38 import org.matsim.vehicles.Vehicle;
40 
41 import jakarta.inject.Inject;
42 import java.util.Collection;
43 import java.util.HashMap;
44 import java.util.Map;
45 
46 public final class PopulationAgentSource implements AgentSource {
47  private static final Logger log = LogManager.getLogger( PopulationAgentSource.class );
48 
49  private final Population population;
50  private final AgentFactory agentFactory;
52  private final QSim qsim;
53  private final Collection<String> mainModes;
54  private Map<Id<Vehicle>,Id<Link>> seenVehicleIds = new HashMap<>() ;
55  private int warnCnt = 0;
56 
57  @Inject
58  PopulationAgentSource( Population population, AgentFactory agentFactory, QVehicleFactory qVehicleFactory, QSim qsim ) {
59  this.population = population;
60  this.agentFactory = agentFactory;
61  this.qVehicleFactory = qVehicleFactory;
62  this.qsim = qsim;
63  this.mainModes = qsim.getScenario().getConfig().qsim().getMainModes();
64  }
65 
66  @Override
67  public void insertAgentsIntoMobsim() {
68  for (Person p : population.getPersons().values()) {
69  MobsimAgent agent = this.agentFactory.createMobsimAgentFromPerson(p);
70  qsim.insertAgentIntoMobsim(agent);
71  }
72  for (Person p : population.getPersons().values()) {
73  insertVehicles(p);
74  }
75  }
76  private static int cnt = 5 ;
77  private void insertVehicles(Person person) {
78  // this is called in every iteration. So if a route without a vehicle id is found (e.g. after mode choice),
79  // then the id is generated here. kai/amit, may'18
80 
81  Map<String,Id<Vehicle>> seenModes = new HashMap<>();
82  for ( Leg leg : TripStructureUtils.getLegs(person.getSelectedPlan()) ) {
83 
84  // only simulated modes get vehicles:
85  if ( !this.mainModes.contains(leg.getMode()) ) {
86  continue ;
87  }
88 
89  // determine the vehicle ID
90  NetworkRoute route = (NetworkRoute) leg.getRoute();
91  Id<Vehicle> vehicleId = null ;
92  if (route != null) {
93  vehicleId = route.getVehicleId();
94  }
95  if (vehicleId == null) {
96  vehicleId = VehicleUtils.getVehicleId(person, leg.getMode());
97  if(route!=null) {
98  route.setVehicleId( vehicleId );
99  }
100  }
101 
102  // determine the vehicle (not the same as just its ID):
103 
104  final QSimConfigGroup.VehiclesSource vehiclesSource = qsim.getScenario().getConfig().qsim().getVehiclesSource();
105 
106  if ( vehiclesSource!= QSimConfigGroup.VehiclesSource.fromVehiclesData ){
107  // without this condition, it is surely wrong when the vehicles come from the vehicles data ... because a second vehicle for
108  // the same mode is not placed. kai, nov'19
109 
110  // yyyy I am not sure if at this point vehicleId actually can be null ... because the above VehicleUtils.getVehicleId(...,
111  // mode) already should contain a map of all the vehicles per person. ??? kai, nov'19
112 
113  // we have seen the mode before in the plan:
114  if( seenModes.keySet().contains( leg.getMode() ) ){
115  if( vehicleId == null && route != null ){
116  vehicleId = seenModes.get( leg.getMode() );
117  route.setVehicleId( vehicleId );
118  // yyyy what is the meaning of route==null? kai, jun'18
119 
120  if ( cnt > 0 ) {
121  log.warn( "encountered vehicleId=null where I am not sure how and why this should happen ..." );
122  cnt-- ;
123  if ( cnt==0 ) {
124  log.warn( Gbl.FUTURE_SUPPRESSED );
125  }
126  }
127  }
128  continue;
129  }
130  }
131 
132  // if we are here, we haven't seen the mode before in this plan
133 
134  // now memorizing mode and its vehicle ID:
135  seenModes.put(leg.getMode(),vehicleId);
136 
137  // find the vehicle from the vehicles container. It should be there, see automatic vehicle creation in PrepareForSim.
138  Vehicle vehicle = qsim.getScenario().getVehicles().getVehicles().get(vehicleId);
139  if ( vehicle==null ) {
140  String msg = "Could not get the requested vehicle with ID=" + vehicleId + " from the vehicles container. " ;
141  switch ( vehiclesSource ) {
142  case defaultVehicle:
143  case modeVehicleTypesFromVehiclesData:
144  msg += "You are using the config switch qsim.vehiclesSource=" + vehiclesSource.name() + "; this should have worked so " +
145  "please report under matsim.org/faq ." ;
146  break;
147  case fromVehiclesData:
148  msg += "You are using the config switch qsim.vehiclesSource=" + vehiclesSource.name() + "; with that setting, you have to" +
149  " provide all needed vehicles yourself." ;
150  break;
151  default:
152  throw new RuntimeException( Gbl.NOT_IMPLEMENTED ) ;
153  }
154  throw new RuntimeException( msg ) ;
155  }
156 
157  // find the link ID of where to place the vehicle:
158  Id<Link> vehicleLinkId = findVehicleLink(person, vehicle);
159 
160  // Checking if the vehicle has been seen before:
161  Id<Link> result = this.seenVehicleIds.get( vehicleId ) ;
162  if ( result != null ) {
163  if (warnCnt <= 5) {
164  log.info("have seen vehicle with id " + vehicleId + " before; not placing it again.");
165  }
166  if (warnCnt == 5) {
167  log.warn(Gbl.FUTURE_SUPPRESSED);
168  }
169  warnCnt++;
170  if ( result != vehicleLinkId ) {
171  throw new RuntimeException("vehicle placement error: vehicleId=" + vehicleId +
172  "; previous placement link=" + vehicleLinkId + "; current placement link=" + result ) ;
173  }
174  // yyyyyy The above condition is too strict; it should be possible that one person drives
175  // a car to some place, and some other person picks it up there. However, this
176  // method here is sorted by persons, not departure times, and so we don't know
177  // which plan needs the vehicle first. (Looks to me that it should actually be possible
178  // to resolve this.)
179 
180  } else {
181  this.seenVehicleIds.put( vehicleId, vehicleLinkId ) ;
182 // qsim.createAndParkVehicleOnLink(vehicle, vehicleLinkId);
183  qsim.addParkedVehicle( this.qVehicleFactory.createQVehicle( vehicle ) , vehicleLinkId );
184  }
185  }
186  }
187 
193  private Id<Link> findVehicleLink(Person person, Vehicle vehicle) {
194  /*
195  * Manual case: the initial link id of the vehicle is saved as an attribute
196  */
197  Id<Link> initialLinkId = VehicleUtils.getInitialLinkId(vehicle);
198  if (initialLinkId != null) {
199  return initialLinkId;
200  }
201 
202  /* Cases that come to mind:
203  * (1) multiple persons share car located at home, but possibly brought to different place by someone else.
204  * This is treated by the following algo.
205  * (2) person starts day with non-car leg and has car parked somewhere else. This is NOT treated by the following algo.
206  * It could be treated by placing the vehicle at the beginning of the first link where it is needed, but this would not
207  * be compatible with variant (1).
208  * Also see comment in insertVehicles.
209  */
210  for (PlanElement planElement : person.getSelectedPlan().getPlanElements()) {
211  if (planElement instanceof Activity) {
212  Activity activity = (Activity) planElement;
213  ActivityFacilities facilities = this.qsim.getScenario().getActivityFacilities() ;
214  Config config = this.qsim.getScenario().getConfig() ;
215  final Id<Link> activityLinkId = PopulationUtils.computeLinkIdFromActivity(activity, facilities, config ) ;
216  if (activityLinkId != null) {
217  return activityLinkId;
218  }
219  } else if (planElement instanceof Leg) {
220  Leg leg = (Leg) planElement;
221  if (leg.getRoute().getStartLinkId() != null) {
222  return leg.getRoute().getStartLinkId();
223  }
224  }
225  }
226  throw new RuntimeException("Don't know where to put a vehicle for this agent.");
227  }
228 
229 }
static< T > Id< T > get(int index, final Class< T > type)
Definition: Id.java:112
static Id< Link > getInitialLinkId(Vehicle vehicle)
static final String FUTURE_SUPPRESSED
Definition: Gbl.java:44
Map< Id< Person >,? extends Person > getPersons()
static Id< Link > computeLinkIdFromActivity(Activity act, ActivityFacilities facs, Config config)
void insertAgentIntoMobsim(final MobsimAgent agent)
Definition: QSim.java:430
static Id< Vehicle > getVehicleId(Person person, String mode)
abstract void setVehicleId(final Id< Vehicle > vehicleId)
QSimConfigGroup qsim()
Definition: Config.java:447
static final String NOT_IMPLEMENTED
Definition: Gbl.java:50
MobsimAgent createMobsimAgentFromPerson(final Person p)
Id< Link > findVehicleLink(Person person, Vehicle vehicle)
Map< Id< Vehicle >, Vehicle > getVehicles()
ActivityFacilities getActivityFacilities()
static List< Leg > getLegs(final Plan plan)
void addParkedVehicle(MobsimVehicle veh, Id< Link > startLinkId)
Definition: QSim.java:305