MATSIM
ActivityReplanningMap.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * ActivityReplanningMap.java
4  * *
5  * *********************************************************************** *
6  * *
7  * copyright : (C) 2010 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.replanning.identifiers.tools;
22 
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.concurrent.ConcurrentHashMap;
29 
30 import jakarta.inject.Inject;
31 
32 import org.apache.logging.log4j.LogManager;
33 import org.apache.logging.log4j.Logger;
34 import org.matsim.api.core.v01.Id;
49 import org.matsim.core.mobsim.qsim.QSim;
53 
63 
64  private static final Logger log = LogManager.getLogger(ActivityReplanningMap.class);
65 
67 
68  /*
69  * Agents that have started an activity in the current time step. We store the
70  * MobsimAgents and their Ids (which are contained in the activity start
71  * event). By doing so, the lookup Id -> MobsimAgent is performed by the
72  * EventHandler which is parallelized.
73  * However, this will result in few unnecessary lookups for agents who end their
74  * activity in the same time step as they start it.
75  */
76  private final Map<Id<Person>, MobsimAgent> startingAgents; // PersonId
77 
78  /*
79  * Contains activity end times of agents that are currently performing an activity.
80  * This is required in case an agent changes its activity end time. To be able to
81  * remove the agent from the activityPerformingAgents we need to know its original
82  * activity end time.
83  */
84  private final Map<Id<Person>, Double> activityEndTimes; // scheduled activity end times
85 
86  /*
87  * Contains a map for each time bin (a bin equals a time step in the mobility simulation).
88  * The set contains all agents ending their activity in that time bin.
89  */
90  private final Map<Integer, Map<Id<Person>, MobsimAgent>> activityPerformingAgents;
91 
92  // package protected to be accessible for test case
93  /*package*/ double simStartTime;
94  /*package*/ double timeStepSize;
95 
96  @Inject
97  public ActivityReplanningMap(MobsimDataProvider mobsimDataProvider, EventsManager eventsManager) {
98  eventsManager.addHandler(this);
99  log.info("Note that the ActivityReplanningMap has to be registered as an EventHandler and a SimulationListener!");
100 
101  this.mobsimDataProvider = mobsimDataProvider;
102 
103  this.startingAgents = new HashMap<>();
104  this.activityEndTimes = new HashMap<>();
105 
106  this.activityPerformingAgents = new ConcurrentHashMap<>();
107  }
108 
109  /*
110  * When the simulation starts the agents are all performing an activity. We collect
111  * them and check their activity end time.
112  */
113  @Override
115 
116  MobsimTimer mobsimTimer = ((QSim) e.getQueueSimulation()).getSimTimer();
117  this.simStartTime = mobsimTimer.getSimStartTime();
118  this.timeStepSize = mobsimTimer.getSimTimestepSize();
119 
120  this.activityPerformingAgents.clear();
121 
122  for (MobsimAgent mobsimAgent : this.mobsimDataProvider.getAgents().values()) {
123 
124  // get the agent's activity end time and mark it as currently performing an Activity
125  double activityEndTime = mobsimAgent.getActivityEndTime();
126 
127  // add the agent to the collections
128  this.activityEndTimes.put(mobsimAgent.getId(), activityEndTime);
129 
130  int bin = this.getTimeBin(activityEndTime);
131  Map<Id<Person>, MobsimAgent> map = getMapForTimeBin(bin);
132  map.put(mobsimAgent.getId(), mobsimAgent);
133  }
134 
135  }
136 
137  /*
138  * The Activity Start Events are thrown before the Activity Start has been handled
139  * by the Simulation. As a result the Departure Time is not set at that time.
140  * We have to wait until the SimStep has been fully simulated and retrieve
141  * the activity departure times then.
142  */
143  @Override
145 
146  double now = e.getSimulationTime();
147  for (MobsimAgent mobsimAgent : startingAgents.values()) {
148 
149  double departureTime = mobsimAgent.getActivityEndTime();
150 
151  /*
152  * If it is the last scheduled Activity the departureTime is -infinity.
153  * Otherwise we select the agent for a replanning.
154  */
155  if (departureTime >= now) {
156  this.activityEndTimes.put(mobsimAgent.getId(), departureTime);
157  int bin = this.getTimeBin(mobsimAgent.getActivityEndTime());
158  Map<Id<Person>, MobsimAgent> map = getMapForTimeBin(bin);
159  map.put(mobsimAgent.getId(), mobsimAgent);
160  } else {
161  log.warn("Departure time is in the past - ignoring activity!");
162  }
163  }
164  this.startingAgents.clear();
165 
166  /*
167  * Remove current time bin from activityPerformingAgents map. They have been handled
168  * in the current time step.
169  */
170  this.activityPerformingAgents.remove(this.getTimeBin(now));
171  }
172 
173  /*
174  * We collect departures in time bins. Each bin contains all departures of one
175  * time step of the mobility simulation.
176  *
177  * Method is package protected to be accessible for test case.
178  */
179  /*package*/ int getTimeBin(double time) {
180 
181  double timeAfterSimStart = time - simStartTime;
182 
183  /*
184  * Agents who end their first activity before the simulation has started
185  * will depart in the first time step.
186  */
187  if (timeAfterSimStart <= 0.0) return 0;
188 
189  /*
190  * Calculate the bin for the given time. Increase it by one if the result
191  * of the modulo operation is > 0. If it is 0, it is the last time value
192  * which is part of the previous bin.
193  */
194  int bin = (int) (timeAfterSimStart / timeStepSize);
195  if (timeAfterSimStart % timeStepSize != 0.0) bin++;
196 
197  return bin;
198  }
199 
200  private Map<Id<Person>, MobsimAgent> getMapForTimeBin(int bin) {
201  Map<Id<Person>, MobsimAgent> map = this.activityPerformingAgents.get(bin);
202  if (map == null) {
203  map = new HashMap<>();
204  this.activityPerformingAgents.put(bin, map);
205  }
206  return map;
207  }
208 
209  /*
210  * Collect the agents that are starting an Activity in the current time step.
211  * Do the agent lookup here since this can be executed parallel to the mobsim.
212  */
213  @Override
214  public void handleEvent(ActivityStartEvent event) {
215  Id<Person> agentId = event.getPersonId();
216  this.startingAgents.put(agentId, this.mobsimDataProvider.getAgent(agentId));
217  }
218 
219  /*
220  * Nothing to do here?
221  * Agents should be removed from the map if their replanning time has come.
222  */
223  @Override
224  public void handleEvent(ActivityEndEvent event) {
225  Id<Person> agentId = event.getPersonId();
226  this.startingAgents.remove(agentId);
227 
228  Double activityEndTime = this.activityEndTimes.remove(agentId);
229  if (activityEndTime != null) {
230  Map<Id<Person>, MobsimAgent> map;
231  // remove
232  map = this.getMapForTimeBin(this.getTimeBin(activityEndTime));
233  map.remove(agentId);
234  }
235  }
236 
237  /*
238  * Nothing to do here?
239  * Agents should not be removed from the simulation if they are performing an activity.
240  */
241  @Override
242  public void handleEvent(PersonStuckEvent event) {
243  }
244 
245  @Override
246  public void handleEvent(ReplanningEvent event) {
247 
248  // check whether the agent is performing an activity
249  Double activityEndTime = this.activityEndTimes.get(event.getPersonId());
250  if (activityEndTime != null) {
251 
252  // check whether the agent has changed its planned departure time
253  MobsimAgent agent = this.mobsimDataProvider.getAgent(event.getPersonId());
254  if (activityEndTime != agent.getActivityEndTime()) {
255  // Update the agent's activity end time.
256  this.activityEndTimes.put(agent.getId(), agent.getActivityEndTime());
257 
258  // Update the activity performing agents map. To do so, remove old entry and add new one.
259  Map<Id<Person>, MobsimAgent> map;
260  // remove
261  map = this.getMapForTimeBin(this.getTimeBin(activityEndTime));
262  map.remove(agent.getId());
263 
264  // add
265  map = this.getMapForTimeBin(this.getTimeBin(agent.getActivityEndTime()));
266  map.put(agent.getId(), agent);
267  }
268  }
269  }
270 
274  public Set<Id<Person>> getActivityPerformingAgents() {
275  return Collections.unmodifiableSet(this.activityEndTimes.keySet());
276  }
277 
285  public Collection<MobsimAgent> getActivityEndingAgents(double time) {
286  return Collections.unmodifiableCollection(this.getMapForTimeBin(this.getTimeBin(time)).values());
287  }
288 
289  @Override
290  public void reset(int iteration) {
291  this.startingAgents.clear();
292  this.activityEndTimes.clear();
293  }
294 }
final Map< Id< Person >, MobsimAgent > getAgents()
final MobsimAgent getAgent(Id< Person > agentId)
void addHandler(final EventHandler handler)
ActivityReplanningMap(MobsimDataProvider mobsimDataProvider, EventsManager eventsManager)
final Map< Integer, Map< Id< Person >, MobsimAgent > > activityPerformingAgents