MATSIM
ActivityEngineDefaultImpl.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * *
4  * *********************************************************************** *
5  * *
6  * copyright : (C) 2008 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;
21 
22 import java.util.Iterator;
23 import java.util.Queue;
24 import java.util.concurrent.PriorityBlockingQueue;
25 
26 import jakarta.inject.Inject;
27 
28 import org.apache.logging.log4j.LogManager;
29 import org.apache.logging.log4j.Logger;
30 import org.matsim.api.core.v01.Id;
37 
38 class ActivityEngineDefaultImpl implements ActivityEngine {
39  private static final Logger log = LogManager.getLogger( ActivityEngineDefaultImpl.class ) ;
40 
41  private final EventsManager eventsManager;
42 
43  @Inject
44  ActivityEngineDefaultImpl( EventsManager eventsManager ) {
45  this.eventsManager = eventsManager;
46  }
47 
48 // public ActivityEngineDefaultImpl( EventsManager eventsManager, AgentCounter agentCounter ) {
49 // this.eventsManager = eventsManager;
50 // }
51 
61  private static class AgentEntry {
63  this.agent = agent;
64  this.activityEndTime = activityEndTime;
65  }
66  private final MobsimAgent agent;
67  private final double activityEndTime;
68  }
69 
70  private InternalInterface internalInterface;
71 
76  private final Queue<AgentEntry> activityEndsList = new PriorityBlockingQueue<>(500, (e0, e1) -> {
77  int cmp = Double.compare(e0.activityEndTime, e1.activityEndTime);
78  if (cmp == 0) {
79  // Both depart at the same time -> let the one with the larger id be first (=smaller)
80  //
81  // yy We are not sure what the above comment line is supposed to say. Presumably, it is supposed
82  // to say that the agent with the larger ID should be "smaller" one in the comparison.
83  // In practice, it seems
84  // that something like "emob_9" is before "emob_8", and something like "emob_10" before "emob_1".
85  // It is unclear why this convention is supposed to be helpful.
86  // kai & dominik, jul'12
87  //
88  return e1.agent.getId().compareTo(e0.agent.getId());
89  }
90  return cmp;
91  });
92 
93  // See handleActivity for the reason for this.
94  private boolean beforeFirstSimStep = true;
95 
96  @Override
97  public void onPrepareSim() {
98  // Nothing to do here
99  }
100 
101  @Override
102  public void doSimStep(double time) {
103  beforeFirstSimStep = false;
104  while (activityEndsList.peek() != null) {
105  if (activityEndsList.peek().activityEndTime <= time) {
106  MobsimAgent agent = activityEndsList.poll().agent;
107  unregisterAgentAtActivityLocation(agent);
108  agent.endActivityAndComputeNextState(time);
109  internalInterface.arrangeNextAgentState(agent);
110  } else {
111  return;
112  }
113  }
114  }
115 
116  @Override
117  public void afterSim() {
118  double now = this.internalInterface.getMobsim().getSimTimer().getTimeOfDay();
119  for (AgentEntry entry : activityEndsList) {
120  if (entry.activityEndTime != Double.POSITIVE_INFINITY) {
121  // since we are at an activity, it is not plausible to assume that the agents know mode or destination
122  // link id. Thus generating the event with ``null'' in the corresponding entries. kai, mar'12
123  eventsManager.processEvent(new PersonStuckEvent(now, entry.agent.getId(), null, null));
124  }
125  }
126  activityEndsList.clear();
127  }
128 
129  @Override
130  public void setInternalInterface(InternalInterface internalInterface) {
131  this.internalInterface = internalInterface;
132  }
133 
134 
145  @Override
146  public boolean handleActivity(MobsimAgent agent) {
147  if (agent.getActivityEndTime() == Double.POSITIVE_INFINITY) {
148  // This is the last planned activity.
149  // So the agent goes to sleep.
150  internalInterface.getMobsim().getAgentCounter().decLiving();
151  } else if (agent.getActivityEndTime() <= internalInterface.getMobsim().getSimTimer().getTimeOfDay() && !beforeFirstSimStep) {
152  // This activity is already over (planned for 0 duration)
153  // So we proceed immediately.
154  agent.endActivityAndComputeNextState(internalInterface.getMobsim().getSimTimer().getTimeOfDay());
155  internalInterface.arrangeNextAgentState(agent) ;
156  } else {
157  // The agent commences an activity on this link.
158  final AgentEntry agentEntry = new AgentEntry(agent, agent.getActivityEndTime());
159  activityEndsList.add(agentEntry);
160  internalInterface.registerAdditionalAgentOnLink(agent);
161  }
162  // Why beforeFirstSimStep matters:
163  // - If this class has never had a doSimStep() when this method is called, this means that this Agent is having its
164  // "overnight", i.e. first Activity.
165  // - This means that this ActivityEngine should not just pass this MobsimAgent along if its activityEndTime has already ended,
166  // but queue it in with other such Agents and let them all leave on doSimStep(), because we expect those Agents to leave
167  // in the order specified by the activityQueue (no matter if it is a good order or not, see comment there). The order in which new Agents enter
168  // the simulation and are passed into this method is a different one, so this matters.
169  // - This is safe (Agents will not miss a second), simply because doSimStep for this time step has not yet happened.
170  // - It also means that e.g. OTFVis will probably display all Agents while they are in their first Activity before you press play.
171  // - On the other hand, agents whose first activity is also their last activity go right to sleep "inside" this engine.
172  return true;
173  }
174 
183  @Override
184  public void rescheduleActivityEnd(final MobsimAgent agent) {
185  if ( agent.getState()!=State.ACTIVITY ) {
186  return ;
187  }
188 
189 
190  double newActivityEndTime = agent.getActivityEndTime();
191  AgentEntry oldEntry = removeAgentFromQueue(agent);
192 
193  // The intention in the following is that an agent that is no longer alive has an activity end time of infinity. The number of
194  // alive agents is only modified when an activity end time is changed between a finite time and infinite. kai, jun'11
195  if (oldEntry == null) {
196  if (newActivityEndTime == Double.POSITIVE_INFINITY) {
197  // agent was de-activated and still should be de-activated - nothing to do here
198  } else {
199  // re-activate the agent
200  activityEndsList.add(new AgentEntry(agent, newActivityEndTime));
201  internalInterface.registerAdditionalAgentOnLink(agent);
202  ((org.matsim.core.mobsim.qsim.AgentCounter) internalInterface.getMobsim().getAgentCounter()).incLiving();
203  }
204  } else if (newActivityEndTime == Double.POSITIVE_INFINITY) {
205  /*
206  * After the re-planning the agent's current activity has changed to its last activity.
207  * Therefore the agent is de-activated. cdobler, oct'11
208  */
209  unregisterAgentAtActivityLocation(agent);
210  internalInterface.getMobsim().getAgentCounter().decLiving();
211  } else {
212  /*
213  * The activity is just rescheduled during the day, so we keep the agent active. cdobler, oct'11
214  */
215  activityEndsList.add(new AgentEntry(agent, newActivityEndTime));
216  }
217  }
218 
219  private AgentEntry removeAgentFromQueue(MobsimAgent agent) {
220  Iterator<AgentEntry> iterator = activityEndsList.iterator();
221  while (iterator.hasNext()) {
222  AgentEntry entry = iterator.next();
223  if (entry.agent == agent) {
224  iterator.remove();
225  return entry;
226  }
227  }
228  return null;
229  }
230 
231  private void unregisterAgentAtActivityLocation(final MobsimAgent agent) {
232  Id<Person> agentId = agent.getId();
233  Id<Link> linkId = agent.getCurrentLinkId();
234  if (linkId != null) { // may be bushwacking
235  internalInterface.unregisterAdditionalAgentOnLink(agentId, linkId);
236  }
237  }
238 
239 }
void arrangeNextAgentState(MobsimAgent agent)
void registerAdditionalAgentOnLink(MobsimAgent agent)
MobsimAgent unregisterAdditionalAgentOnLink(Id< Person > agentId, Id< Link > linkId)
void endActivityAndComputeNextState(final double now)
final double activityEndTime
final MobsimAgent agent
AgentCounter getAgentCounter()
Definition: QSim.java:629