MATSIM
Agent.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * *
4  * *********************************************************************** *
5  * *
6  * copyright : (C) 2014 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.hermes;
21 
22 import org.matsim.api.core.v01.Id;
25 
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Collections;
29 import java.util.List;
30 
31 class Agent {
32 
33  public static class PlanArray {
34  long[] array;
35  int size;
36 
37  public PlanArray() {
38  this.array = new long[32];
39  }
40 
41  public void add(long element) {
42  if (size == array.length) {
43  array = Arrays.copyOf(array, array.length * 2);
44  }
45  array[size++] = element;
46  }
47 
48  public int size() {
49  return size;
50  }
51  public long get(int index) {
52  return array[index];
53  }
54 
55  public void clear() {
56  for (int i = 0; i < size; i++) {
57  array[i] = 0;
58  }
59  size = 0;
60  }
61  }
62 
63  // Types of plan headers.
64  // agent sleeps for some time.
65  public static final int SleepForType = 0;
66  // agent sleeps until a specific time of the day
67  public static final int SleepUntilType = 1;
68  // agent goes through some link
69  public static final int LinkType = 2;
70  // non-vehicle agent enters a vehicle agent
71  public static final int AccessType = 3;
72  // non-vehicle agent leaves a vehicle agent
73  public static final int EgressType = 4;
74  // vehicle agent arrives at a PT stop
75  public static final int StopArriveType = 5;
76  // vehicle agent leaves at a PT stop
77  public static final int StopDepartType = 6;
78  // non-vehicle agent waits for vehicle agent at PT stop
79  public static final int WaitType = 7;
80  // vehicle agent waits at the PT stop until it can leave the stop
81  public static final int StopDelayType = 8;
82 
83  // Id of the link (index for World.agents).
84  protected final int id;
85 
86  // Array of plan elements. A plan element has the following structure:
87  // <4 bit header><60 bit payload>
88  // Possible headers (binary format) and corresponding payload:
89  // <0000> SleepForType | 4 bits unused | 16 bit event id | 8 bits unused | 32 bit sleep for a number of second
90  // <0001> SleepUntilType | 4 bits unused | 16 bit event id | 8 bits unused | 32 bit speep until a specific time
91  // <0010> LinkType | 4 bits PCEcategory | 16 bit event id | 32 bit link id | 8 bit velocity
92  // <0111> WaitType | 4 bits unused | 16 bit event id | 8 bits unused | 16 bit route id | 16 station id
93  // <0011> AccessType | 4 bits unused | 16 bit event id | 8 bits unused | 16 bit route id | 16 station id
94  // <0100> EgressType | 4 bits unused | 16 bit event id | 8 bits unused | 16 bit route id | 16 station id
95  // <0101> StopArriveType | 4 bits unused | 16 bit event id | 8 bits unused | 16 bit route id | 16 station id
96  // <1000> StopDelayType | 20 departure sec | 8 bits unused | 16 bit route id | 16 station id
97  // <0110> StopDepartType | 4 bits unused | 16 bit event id | 8 bits unused | 16 bit route id | 16 station id
98  protected final PlanArray plan; // TODO - use a byte buffer instead of a long[]...
99 
100  protected final EventArray events;
101 
102  // Current position in plan. Using this index in the plan will yield what
103  // the agent is doing currently. Note that we trigger the corresponding
104  // events when the plan entry is activated.
105  protected int planIndex;
106 
107  protected int eventsIndex;
108 
109  // Timestamp of when the agent will be ready to exit link.
110  protected int linkFinishTime;
111 
112  // Number of passengers that this agent can take (zero for personal vehicles)
113  private int capacity;
114 
115  // Number of passengers that are currently being transported.
116  private int passengersInside;
117 
118  private float storageCapacityPCUE = -1;
119  private float flowCapacityPCUE = -1;
120 
121  // Map of passengers per destination stop on this vehicle.
122  private UpcomingStops passengersByStop;
123 
124  private final static List<Agent> NO_PASSENGERS = Collections.emptyList();
125 
126  public Agent(int id, int capacity, PlanArray plan, EventArray events) {
127  this.id = id;
128  this.plan = plan;
129  this.events = events;
130  this.capacity = capacity;
131  if (capacity == 0) {
132  this.passengersByStop = null;
133  } else {
134  this.passengersByStop = new UpcomingStops();
135  }
136  }
137 
138  public static long preparePlanEventEntry(long type, long element) {
139  long planEntry = (type << 60) | element;
141  validatePlanEntry(planEntry);
142  }
143  return planEntry;
144  }
145 
146  public int id() {
147  return this.id;
148  }
149 
150  public int linkFinishTime() {
151  return this.linkFinishTime;
152  }
153 
154  public int planIndex() {
155  return this.planIndex;
156  }
157 
158  public PlanArray plan() {
159  return this.plan;
160  }
161 
162  public EventArray events() {
163  return this.events;
164  }
165 
166  public long currPlan() {
167  return this.plan.get(planIndex);
168  }
169 
170  public long prevPlan() {
171  return this.plan.get(planIndex - 1);
172  }
173 
174  public long nextPlan() {
175  return this.plan.get(planIndex + 1);
176  }
177 
178  public boolean finished() {
179  return planIndex >= (plan.size() - 1);
180  }
181 
182  public float getFlowCapacityPCUE() {
183  return flowCapacityPCUE;
184  }
185 
186  public void setFlowCapacityPCUE(float flowCapacityPCUE) {
187  this.flowCapacityPCUE = flowCapacityPCUE;
188  }
189 
190  public float getStorageCapacityPCUE() {
191  return storageCapacityPCUE;
192  }
193 
194  public void setStorageCapacityPCUE(float storageCapacityPCUE) {
195  this.storageCapacityPCUE = storageCapacityPCUE;
196  }
197 
198  /*
199  * Number of passengers that this agent can take (zero for personal vehicles)
200  */
201  public int getCapacity() {
202  return this.capacity;
203  }
204 
205  public boolean isTransitVehicle() {
206  return this.passengersByStop != null;
207  }
208 
209  public List<Agent> egress(int stopid) {
210  List<Agent> ret = passengersByStop.remove(stopid);
211  if (ret == null) {
212  return NO_PASSENGERS;
213  }
214  passengersInside -= ret.size();
215  return ret;
216  }
217 
218  public void setServeStop(int stopId) {
219  this.passengersByStop.addStop(stopId);
220  }
221 
222  public boolean willServeStop(int stopId) {
223  return passengersByStop.hasUpcoming(stopId);
224  }
225 
226  public boolean access(int stopid, Agent agent) {
227  if (passengersInside == capacity) {
228  return false;
229  } else {
230  passengersByStop.add(stopid, agent);
231  passengersInside++;
232  return true;
233  }
234  }
235 
236  public int getNextStopPlanEntry() {
237  // TODO - install assert checking if the next entry is an egress?
238  // +2 is used to peek where the agent wants to leave the vehicle.
239  // +1 is the access plan element which was not yet consumed.
240  return getStopPlanEntry(plan.get(planIndex + 2));
241  }
242 
243  public static int getPlanHeader (long plan) { return (int)((plan >> 60) & 0x000000000000000FL); }
244  public static int getPlanEvent (long plan) { return (int)((plan >> 40) & 0x000000000000FFFFL); }
245  public static int getDeparture (long plan) { return (int)((plan >> 40) & 0x00000000000FFFFFL); }
246  public static int getLinkPlanEntry (long plan) { return (int) ((plan >> 8) & 0x00000000FFFFFFFFL); }
247  public static int getLinkPCEEntry (long plan) {
248  return (int) ((plan >> 56) & 0x000000000000000FL);
249  }
250  public static double getVelocityPlanEntry (long plan) { return decodeVelocityFromLinkEntry((int) (plan & 0x00000000000000FFL)); }
251  public static int getRoutePlanEntry (long plan) { return (int)((plan >> 16) & 0x000000000000FFFFL); }
252  public static int getStopPlanEntry (long plan) { return (int)( plan & 0x000000000000FFFFL); }
253  public static int getSleepPlanEntry (long plan) { return (int)( plan & 0x00000000FFFFFFFFL); }
254 
255  private static void validatePlanEntry(long planEntry) {
256  int event = Agent.getPlanEvent(planEntry);
257  int type = Agent.getPlanHeader(planEntry);
258  switch (type) {
259  case Agent.LinkType:
260  case Agent.SleepForType:
261  case Agent.SleepUntilType:
262  case Agent.AccessType:
263  case Agent.StopArriveType:
264  case Agent.StopDelayType:
265  case Agent.StopDepartType:
266  case Agent.EgressType:
267  case Agent.WaitType:
268  break; // TODO - add more verification for each field!
269  default:
270  throw new RuntimeException("planEntry does not validate " + planEntry);
271  }
272  }
273 
274  public static long preparePlanEventEntry(long type, long eventid, long element) {
275  if (eventid > HermesConfigGroup.MAX_EVENTS_AGENT) {
276  throw new RuntimeException(String.format("eventid above limit: %d", eventid));
277  }
278  return preparePlanEventEntry(type, (eventid << 40) | element);
279  }
280 
281  private static long prepareLinkEntryElement(long linkid, double velocity, long pcecategory) {
282  if (linkid > HermesConfigGroup.MAX_LINK_ID) {
283  throw new RuntimeException("exceeded maximum number of links");
284  }
285  int encodedVelocity = prepareVelocityForLinkEntry(velocity);
286 
287  return (pcecategory << 56) | (linkid << 8) | encodedVelocity;
288  }
289 
290  public static int prepareVelocityForLinkEntry(double velocity) {
291  // Checking for velocities that are too high.
292  velocity = Math.min(velocity, HermesConfigGroup.MAX_VEHICLE_VELOCITY);
293  // Checking for velocities that are too low.
294  velocity = velocity < 0 ? HermesConfigGroup.MAX_VEHICLE_VELOCITY : velocity;
295  // Encode velocity to 8-bit unsigned integer
296  if (velocity < 10) {
297  // Speeds 0.0 - 9.9 -> 0 - 99
298  velocity = velocity * 10;
299  } else {
300  // Speeds 10 - 165 -> 100 - 255
301  velocity = velocity + 90;
302  }
303  return (int) Math.round(velocity);
304  }
305 
306  public static double decodeVelocityFromLinkEntry(int encodedVelocity) {
307  double velocity;
308  if (encodedVelocity < 100) {
309  // 0 - 99 -> 0.0 - 9.9 m/s
310  velocity = ((double) encodedVelocity) / 10.0;
311  } else {
312  // 100 - 255 -> 10 - 165 m/s
313  velocity = ((double) encodedVelocity) - 90;
314  }
315  return velocity;
316  }
317 
318 
319  public static long prepareStopDelay(long type, long departure, long element) {
320  return preparePlanEventEntry(type, (departure << 40) | element);
321  }
322 
323  private static long prepareRouteStopEntry(long routeid, long stopid) {
324  if (stopid > HermesConfigGroup.MAX_STOP_ROUTE_ID) {
325  throw new RuntimeException(String.format("stopid above limit: %d", stopid));
326  }
327  if (routeid > HermesConfigGroup.MAX_STOP_ROUTE_ID) {
328  throw new RuntimeException(String.format("routeid above limit: %d", routeid));
329  }
330  return (routeid << 16) | stopid;
331  }
332 
333  public void reset() {
334  plan.clear();
335  events.clear();
336  planIndex = 0;
337  eventsIndex = 0;
338  linkFinishTime = 0;
339  if (this.passengersByStop != null) {
340  passengersInside = 0;
341  this.passengersByStop.clear();
342  }
343  }
344 
345  public static long prepareLinkEntry(int eventid, int linkid, double velocity, int pcecategory) {
346  long l = preparePlanEventEntry(LinkType, eventid, prepareLinkEntryElement(linkid, velocity, pcecategory));
347  return l;
348  }
349 
350  public static long prepareSleepForEntry(int eventid, int element) {
351  return preparePlanEventEntry(SleepForType, eventid, element);
352  }
353 
354  public static long prepareSleepUntilEntry(int eventid, int element) {
355  return preparePlanEventEntry(SleepUntilType, eventid, element);
356  }
357 
358  public static long prepareAccessEntry(int eventid, int routeid, int stopid) {
359  return preparePlanEventEntry(AccessType, eventid, prepareRouteStopEntry(routeid, stopid));
360  }
361 
362  public static long prepareEgressEntry(int eventid, int routeid, int stopid) {
363  return preparePlanEventEntry(EgressType, eventid, prepareRouteStopEntry(routeid, stopid));
364  }
365 
366  public static long prepareWaitEntry(int eventid, int routeid, int stopid) {
367  return preparePlanEventEntry(WaitType, eventid, prepareRouteStopEntry(routeid, stopid));
368  }
369 
370  public static long prepareStopArrivalEntry(int eventid, int routeid, int stopid) {
371  return preparePlanEventEntry(StopArriveType, eventid, prepareRouteStopEntry(routeid, stopid));
372  }
373 
374  public static long prepareStopDelayEntry(int departure, int routeid, int stopid) {
375  return prepareStopDelay(StopDelayType, departure, prepareRouteStopEntry(routeid, stopid));
376  }
377 
378  public static long prepareStopDepartureEntry(int eventid, int routeid, int stopid) {
379  return preparePlanEventEntry(StopDepartType, eventid, prepareRouteStopEntry(routeid, stopid));
380  }
381 
382  public static String toString(long planEntry) {
383  int type = Agent.getPlanHeader(planEntry);
384  switch (type) {
385  case Agent.LinkType:
386  return String.format("type=link; event=%d; link=%d; vel=%d",
387  getPlanEvent(planEntry), getLinkPlanEntry(planEntry), getVelocityPlanEntry(planEntry));
388  case Agent.SleepForType:
389  return String.format("type=sleepfor; event=%d; sleep=%d",
390  getPlanEvent(planEntry), getSleepPlanEntry(planEntry));
391  case Agent.SleepUntilType:
392  return String.format("type=sleepuntil; event=%d; sleep=%d",
393  getPlanEvent(planEntry), getSleepPlanEntry(planEntry));
394  case Agent.AccessType:
395  return String.format("type=access; event=%d; route=%d stopid=%d",
396  getPlanEvent(planEntry), getRoutePlanEntry(planEntry), getStopPlanEntry(planEntry));
397  case Agent.StopArriveType:
398  return String.format("type=stoparrive; event=%d; route=%d stopid=%d",
399  getPlanEvent(planEntry), getRoutePlanEntry(planEntry), getStopPlanEntry(planEntry));
400  case Agent.StopDelayType:
401  return String.format("type=stopdelay; departure=%d; route=%d stopid=%d",
402  getDeparture(planEntry), getRoutePlanEntry(planEntry), getStopPlanEntry(planEntry));
403  case Agent.StopDepartType:
404  return String.format("type=stopdepart; event=%d; route=%d stopid=%d",
405  getPlanEvent(planEntry), getRoutePlanEntry(planEntry), getStopPlanEntry(planEntry));
406  case Agent.EgressType:
407  return String.format("type=egress; event=%d; route=%d stopid=%d",
408  getPlanEvent(planEntry), getRoutePlanEntry(planEntry), getStopPlanEntry(planEntry));
409  case Agent.WaitType:
410  return String.format("type=wait; event=%d; route=%d stopid=%d",
411  getPlanEvent(planEntry), getRoutePlanEntry(planEntry), getStopPlanEntry(planEntry));
412  default:
413  return String.format("unknown plan type %d", type);
414  }
415 
416  }
417 
418  private static class UpcomingStops {
419  int[] stopIds = new int[10];
420  List<Agent>[] passengers = new ArrayList[10];
421  int size = 0;
422  int currentStopIdx = -1;
423 
424  public void clear() {
425  Arrays.fill(this.stopIds, -1);
426  Arrays.fill(this.passengers, null);
427  this.size = 0;
428  this.currentStopIdx = -1;
429  }
430 
431  public void addStop(int stopId) {
432  if (this.size == this.stopIds.length) {
433  this.stopIds = Arrays.copyOf(this.stopIds, this.stopIds.length * 2);
434  }
435  this.stopIds[this.size] = stopId;
436 
437  if (this.size == this.passengers.length) {
438  this.passengers = Arrays.copyOf(this.passengers, this.passengers.length * 2);
439  }
440  this.passengers[this.size] = new ArrayList<>();
441 
442  this.size++;
443  }
444 
445  public void add(int stopId, Agent agent) {
446  for (int i = this.currentStopIdx + 1; i < this.size; i++) {
447  if (this.stopIds[i] == stopId) {
448  this.passengers[i].add(agent);
449  return;
450  }
451  }
452  throw new RuntimeException("Could not find upcoming stop " + Id.get(stopId, TransitStopFacility.class) + " along this route.");
453  }
454 
455  public boolean hasUpcoming(int stopId) {
456  for (int i = this.currentStopIdx + 1; i < this.size; i++) {
457  if (this.stopIds[i] == stopId) {
458  return true;
459  }
460  }
461  return false;
462  }
463 
464  public List<Agent> remove(int stopId) {
465  for (int i = this.currentStopIdx + 1; i < this.size; i++) {
466  if (this.stopIds[i] == stopId) {
467  this.currentStopIdx = i;
468  return this.passengers[this.currentStopIdx];
469  }
470  }
471  throw new RuntimeException("Could not find upcoming stop " + Id.get(stopId, TransitStopFacility.class) + " along this route.");
472  }
473  }
474 
475 }
static< T > Id< T > get(int index, final Class< T > type)
Definition: Id.java:112
void add(int stopId, Agent agent)
Definition: Agent.java:445