MATSIM
ScenarioImporter.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.apache.logging.log4j.LogManager;
23 import org.apache.logging.log4j.Logger;
24 import org.matsim.api.core.v01.Id;
25 import org.matsim.api.core.v01.IdMap;
26 import org.matsim.api.core.v01.Scenario;
28 import org.matsim.api.core.v01.events.*;
31 import org.matsim.api.core.v01.population.*;
44 import org.matsim.vehicles.Vehicle;
48 
49 import java.util.*;
50 
51 class ScenarioImporter {
52 
53  final private static Logger log = LogManager.getLogger(Hermes.class);
54 
55  private static ScenarioImporter instance;
56 
57  private Thread resetThread = null;
58 
59  // Scenario loaded by matsim;
60  private final Scenario scenario;
61 
62  private final Map<Id<VehicleType>, Integer> vehicleTypeMapping = new HashMap<>();
63  protected int agentPersons;
64  // hermes route numbers for each line/route. Should be used as follows:
65  // route_numbers.get(line id).get(route id) -> hermes-route-number
66  protected IdMap<TransitLine, ArrayMap<Id<TransitRoute>, Integer>> routeNumbers;
67  // matsim stop ids (Id<TransitStopFacility>.index) per route number. Should be used as follows:
68  // int[] stop_ids = route_stops_by_route_no[route_no]
69  // route_stops_by_route_no[route_no][station_index] -> transit_stop_facility.id.index
70  protected int[][] routeStopsByRouteNo;
71  // matsim line id (Id<TransitLine>.index) of a particular hermes route. Should be used as follows:
72  // line_of_route[route_no] -> transit_line.id.index
73  protected int[] lineOfRoute;
74  // matsim route id (Id<TransitRoute>.index) of a particular hermes route number. Should be used as follows:
75  // routeOfRoute[route_no] -> transit_route.id.index
76  protected int[] routeOfRoute;
77  // Array of links that define the network.
78  protected HLink[] hermesLinks;
79 
80  protected Realm realm;
81  private final boolean deterministicPt;
82  // Agents waiting in pt stations. Should be used as follows:
83  // agent_stops.get(curr station id).get(line id) -> queue of agents
84  protected IdMap<TransitStopFacility, IntArrayMap<ArrayDeque<Agent>>> agentStops;
85 
86  private float[] flowCapacityPCEs;
87  private float[] storageCapacityPCEs;
88  // Array of agents that participate in the simulation.
89  // Note: in order to make MATSim Agent ids, some positions in the array might be null.
90  protected Agent[] hermesAgents;
91  protected final EventsManager eventsManager;
92  private final int numberOfThreads;
93  private final List<List<Event>> deterministicPtEvents;
94 
95  private ScenarioImporter(Scenario scenario, EventsManager eventsManager) {
96  numberOfThreads = Math.min(scenario.getConfig().global().getNumberOfThreads(), Runtime.getRuntime().availableProcessors());
97  this.deterministicPt = scenario.getConfig().hermes().isDeterministicPt();
98  if (deterministicPt) {
99  deterministicPtEvents = new ArrayList<>(scenario.getConfig().hermes().getEndTime());
100  for (int i = 0; i < scenario.getConfig().hermes().getEndTime(); i++) {
101  deterministicPtEvents.add(new ArrayList<>(16));
102  }
103  } else {
104  deterministicPtEvents = Collections.EMPTY_LIST;
105  }
106  this.scenario = scenario;
107  this.eventsManager = eventsManager;
108  generateVehicleCategories();
109  generateLinks();
110  generatePT();
111  generateAgents();
112 
113  }
114 
115  private void generateVehicleCategories() {
116  int vehicleTypes = scenario.getVehicles().getVehicleTypes().size();
117  if (vehicleTypes >= HermesConfigGroup.MAX_VEHICLE_PCETYPES) {
118  throw new RuntimeException(
119  "Too many vehicle types defined. A maximum of " + HermesConfigGroup.MAX_VEHICLE_PCETYPES + " is supported.");
120  }
121  flowCapacityPCEs = new float[vehicleTypes];
122  storageCapacityPCEs = new float[vehicleTypes];
123  int i = 0;
124  for (VehicleType t : scenario.getVehicles().getVehicleTypes().values()) {
125  //downscaling of vehicles = Upscaling of PCUs
126  flowCapacityPCEs[i] = (float) (t.getPcuEquivalents() / (t.getFlowEfficiencyFactor() * scenario.getConfig().hermes().getFlowCapacityFactor()));
127  storageCapacityPCEs[i] = (float) (t.getPcuEquivalents() / scenario.getConfig().hermes().getStorageCapacityFactor());
128  vehicleTypeMapping.put(t.getId(), i);
129  i++;
130  }
131 
132  }
133 
134  public static void flush() {
135  instance = null;
136  }
137 
138  public static ScenarioImporter instance(Scenario scenario, EventsManager eventsManager) {
139  // if instance is null or the scenario changed or events manager changed, re-do everything.
140  if (instance == null || !scenario.equals(instance.scenario) || !eventsManager.equals(instance.eventsManager)) {
141  log.info("Hermes rebuilding scenario!");
142  instance = new ScenarioImporter(scenario, eventsManager);
143  }
144  return instance;
145  }
146 
147  public void generate() throws Exception {
148  long time = System.currentTimeMillis();
149 
150  if (resetThread != null) {
151  resetThread.join();
152  }
153 
154  log.info(String.format("Hermes reset took %d ms (%d agents %d links)", System.currentTimeMillis() - time, hermesAgents.length, hermesLinks.length));
155  time = System.currentTimeMillis();
156  generatePlans();
157  log.info(String.format("Hermes generatePlans took %d ms", System.currentTimeMillis() - time));
158  time = System.currentTimeMillis();
159  generateRealms();
160  log.info(String.format("Hermes generateRealms took %d ms", System.currentTimeMillis() - time));
161  }
162 
163  public void reset() {
164  resetThread = new Thread() {
165 
166  @Override
167  public void run() {
168  log.info("resetting hermes...");
169  // reset links
170  for (HLink link : hermesLinks) {
171  if (link != null) {
172  link.reset();
173  }
174  }
175  // reset agent plans and events
176  for (Agent hermes_agent : hermesAgents) {
177  if (hermes_agent != null) {
178  hermes_agent.reset();
179  }
180  }
181  // reset agent_stops
182  for (IntArrayMap<ArrayDeque<Agent>> station_id : agentStops) {
183  for (ArrayDeque<Agent> agents_per_line : station_id.values()) {
184  agents_per_line.clear();
185  }
186  }
187 
188  }
189  };
190 
191  resetThread.start();
192  }
193 
194  private void generateLinks() {
195  Network network = scenario.getNetwork();
196  Collection<? extends org.matsim.api.core.v01.network.Link> matsim_links =
197  network.getLinks().values();
198  hermesLinks = new HLink[Id.getNumberOfIds(org.matsim.api.core.v01.network.Link.class)];
199 
200  for (org.matsim.api.core.v01.network.Link matsim_link : matsim_links) {
201  int length = Math.max(1, (int) Math.round(matsim_link.getLength()));
202  int speed = Math.max(1, (int) Math.round(matsim_link.getFreespeed()));
203  int lanes = (int) Math.round(matsim_link.getNumberOfLanes());
204  int storageCapacity = Math.max(1, (int) (Math.ceil(matsim_link.getLength() / network.getEffectiveCellSize() * lanes)));
205  int link_id = matsim_link.getId().index();
206  final float effectiveflowCapacityPerSec = (float) matsim_link.getFlowCapacityPerSec();
207 
208  if (link_id > HermesConfigGroup.MAX_LINK_ID) {
209  throw new RuntimeException("exceeded maximum number of links");
210  }
211 
212  hermesLinks[link_id] = new HLink(link_id, storageCapacity, length, speed, effectiveflowCapacityPerSec, scenario.getConfig().hermes().getStuckTime());
213  }
214  }
215 
216  private void initRoutesStations() {
217  TransitSchedule ts = this.scenario.getTransitSchedule();
218 
219  int routeCount = 0;
220  for (TransitLine tl : ts.getTransitLines().values()) {
221  routeCount += tl.getRoutes().size();
222  }
223 
224  this.lineOfRoute = new int[routeCount];
225  this.routeOfRoute = new int[routeCount];
226  this.routeStopsByRouteNo = new int[routeCount][];
227 
228  this.routeNumbers = new IdMap<>(TransitLine.class);
229  int routeNo = 0;
230  for (TransitLine tl : ts.getTransitLines().values()) {
231  ArrayMap<Id<TransitRoute>, Integer> routesMap = new ArrayMap<>();
232  this.routeNumbers.put(tl.getId(), routesMap);
233  int lineId = tl.getId().index();
234  for (TransitRoute tr : tl.getRoutes().values()) {
235  routesMap.put(tr.getId(), routeNo);
236  int routeId = tr.getId().index();
237  this.lineOfRoute[routeNo] = lineId;
238  this.routeOfRoute[routeNo] = routeId;
239 
240  List<TransitRouteStop> stops = tr.getStops();
241  int[] tr_stops = new int[stops.size()];
242  for (int i = 0; i < stops.size(); i++) {
243  TransitRouteStop trs = stops.get(i);
244  int sid = trs.getStopFacility().getId().index();
245  tr_stops[i] = sid;
246  }
247  this.routeStopsByRouteNo[routeNo] = tr_stops;
248  routeNo++;
249  }
250  }
251  }
252 
253  private void generatePT() {
254  initRoutesStations();
255 
256  // Initialize agent_stops.
257  this.agentStops = new IdMap<>(TransitStopFacility.class);
258 
259  TransitSchedule ts = this.scenario.getTransitSchedule();
260  for (TransitLine line : ts.getTransitLines().values()) {
261  for (TransitRoute route : line.getRoutes().values()) {
262  List<TransitRouteStop> stops = route.getStops();
263  for (int i = 0, stopsCount = stops.size(); i < stopsCount; i++) {
264  TransitRouteStop routeStop = stops.get(i);
265  TransitStopFacility stopFacility = routeStop.getStopFacility();
266 
267  IntArrayMap<ArrayDeque<Agent>> linesMap = this.agentStops.computeIfAbsent(stopFacility.getId(), k -> new IntArrayMap<>());
268  linesMap.computeIfAbsent(line.getId().index(), k -> new ArrayDeque<>());
269  }
270  }
271  }
272  }
273 
274  private void generateRealms() {
275  realm = new Realm(this, eventsManager);
276 
277  // Put agents in their initial location (link or activity center)
278  for (Agent agent : hermesAgents) {
279  // Some agents might not have plans.
280  if (agent == null || agent.plan.size() == 0) {
281  continue;
282  }
283  long planentry = agent.plan().get(0);
284  int type = Agent.getPlanHeader(planentry);
285  // TODO - I should advance agents in a proper way!
286  switch (type) {
287  case Agent.LinkType:
288  int linkid = Agent.getLinkPlanEntry(planentry);
289  double velocity = Agent.getVelocityPlanEntry(planentry);
290  HLink link = hermesLinks[linkid];
291  agent.linkFinishTime = (int) Math.round(link.length() / Math.min(velocity, link.velocity()));
292  link.push(agent, 0, getStorageCapacityPCE(Agent.getLinkPCEEntry(planentry)));
293  break;
294  case Agent.SleepForType:
295  case Agent.SleepUntilType:
296  int sleep = Agent.getSleepPlanEntry(planentry);
297  realm.delayedAgents().get(Math.min(sleep, scenario.getConfig().hermes().getEndTime() + 1)).add(agent);
298  break;
299  default:
300  LogManager.getLogger(getClass()).error(String.format("ERROR -> unknown plan element type %d", type));
301  }
302  }
303 
304  for (HLink link : this.hermesLinks) {
305  if (link != null) {
306  int nextwakeup = link.nexttime();
307  if (nextwakeup > 0) {
308  realm.delayedLinks().get(nextwakeup).add(link);
309  }
310  }
311  }
312  }
313 
314  private void processPlanActivity(
315  Id<Person> id,
316  PlanArray flatplan,
317  EventArray events,
318  Activity act) {
319  int time = 0;
320  int eventid = 0;
321  Id<org.matsim.api.core.v01.network.Link> linkid;
322  Id<ActivityFacility> facid = act.getFacilityId();
323  String type = act.getType();
324 
325  // This logic comes from how QSim agents do it...
326  if (facid == null) {
327  linkid = act.getLinkId();
328  } else {
329  ActivityFacility facility = scenario.getActivityFacilities().getFacilities().get(facid);
330  if (facility == null || facility.getLinkId() == null) {
331  linkid = act.getLinkId();
332  } else {
333  linkid = facility.getLinkId();
334  }
335  }
336 
337  assert linkid != null;
338 
339  // hack to avoid a actstart as first event (hermes does not have it).
340  if (flatplan.size() != 0) {
341  events.add(new ActivityStartEvent(0, id, linkid, facid, type, act.getCoord()));
342  eventid = events.size() - 1;
343  } else {
344  eventid = 0;
345  }
346 
347  if (act.getEndTime().isDefined()) {
348  time = (int) Math.round(act.getEndTime().seconds());
349  flatplan.add(Agent.prepareSleepUntilEntry(eventid, time));
350  } else if (act.getMaximumDuration().isDefined()) {
351  time = (int) Math.round(act.getMaximumDuration().seconds());
352  flatplan.add(Agent.prepareSleepForEntry(eventid, time));
353  } else {
354  // TODO - better way to handle this?
355  flatplan.add(Agent.prepareSleepForEntry(eventid, 0));
356  }
357  events.add(new ActivityEndEvent(0, id, linkid, facid, type, act.getCoord()));
358  }
359 
360  private void processPlanNetworkRoute(
361  Person person,
362  PlanArray flatplan,
363  EventArray events,
364  Leg leg,
365  NetworkRoute netroute,
366  Agent agent) {
367  var id = person.getId();
368  Id<org.matsim.api.core.v01.network.Link> startLId = netroute.getStartLinkId();
369  Id<org.matsim.api.core.v01.network.Link> endLId = netroute.getEndLinkId();
370  Map<Id<Vehicle>, Vehicle> vehicles = scenario.getVehicles().getVehicles();
371  Vehicle v = vehicles.get(VehicleUtils.getVehicleId(person, leg.getMode()));
372  Id<VehicleType> vtypeid = v == null ? VehicleUtils.createDefaultVehicleType().getId() : v.getType().getId();
373  int pcuCategory = this.vehicleTypeMapping.get(vtypeid);
374  Id<Vehicle> vid = v == null ? Id.createVehicleId("v" + person.getId()) : v.getId();
375  double velocity = v == null ?
376  HermesConfigGroup.MAX_VEHICLE_VELOCITY : v.getType().getMaximumVelocity();
377  int egressId = endLId.index();
378 
379  //initial capacity setting
380  if (agent.getFlowCapacityPCUE() == -1) {
381  agent.setFlowCapacityPCUE(getFlowCapacityPCE(pcuCategory));
382  }
383  if (agent.getStorageCapacityPCUE() == -1) {
384  agent.setStorageCapacityPCUE(getStorageCapacityPCE(pcuCategory));
385  }
386  events.add(new PersonEntersVehicleEvent(0, id, vid));
387  events.add(new VehicleEntersTrafficEvent(0, id, startLId, vid, leg.getMode(), 1));
388  if (netroute.getLinkIds().size() > 1 || !startLId.equals(endLId)) {
389  events.add(new LinkLeaveEvent(0, vid, startLId));
390  }
391  for (Id<org.matsim.api.core.v01.network.Link> linkid : netroute.getLinkIds()) {
392  int linkId = linkid.index();
393  events.add(new LinkEnterEvent(0, vid, linkid));
394  flatplan.add(Agent.prepareLinkEntry(events.size() - 1, linkId, velocity, pcuCategory));
395  events.add(new LinkLeaveEvent(0, vid, linkid));
396  }
397  if (netroute.getLinkIds().size() > 1 || !startLId.equals(endLId)) {
398  events.add(new LinkEnterEvent(0, vid, endLId));
399  flatplan.add(Agent.prepareLinkEntry(events.size() - 1, egressId, velocity, pcuCategory));
400  }
401  events.add(new VehicleLeavesTrafficEvent(0, id, endLId, vid, leg.getMode(), 1));
402  events.add(new PersonLeavesVehicleEvent(0, id, vid));
403  }
404 
405  private void populateStops(int srcStopId, int lineId) {
406  IntArrayMap<ArrayDeque<Agent>> agents = this.agentStops.get(srcStopId);
407  agents.computeIfAbsent(lineId, k -> new ArrayDeque<>());
408  }
409 
410  private void processPlanTransitRoute(
411  Id<Person> id,
412  PlanArray flatplan,
413  EventArray events,
414  TransitPassengerRoute troute) {
415  Id<TransitStopFacility> access = troute.getAccessStopId();
416  Id<TransitStopFacility> egress = troute.getEgressStopId();
417  int lineid = troute.getLineId().index();
418  int accessid = access.index();
419  int egressid = egress.index();
420  int routeNo = this.routeNumbers.get(troute.getLineId()).get(troute.getRouteId());
421 
422  populateStops(accessid, lineid);
423 
424  // this will be replaced dynamically
425  Id<Vehicle> vid = Id.createVehicleId("tr_X");
426  // Add public transport access
427  events.add(new AgentWaitingForPtEvent(0, id, access, egress));
428  flatplan.add(Agent.prepareWaitEntry(events.size() - 1, routeNo, accessid));
429  events.add(new PersonEntersVehicleEvent(0, id, vid));
430  flatplan.add(Agent.prepareAccessEntry(events.size() - 1, routeNo, accessid));
431  events.add(new PersonLeavesVehicleEvent(0, id, vid));
432  flatplan.add(Agent.prepareEgressEntry(events.size() - 1, routeNo, egressid));
433  }
434 
435  private void processPlanElement(
436  Person person,
437  PlanArray flatplan,
438  EventArray events,
439  PlanElement element,
440  Agent agent) {
441  var id = person.getId();
442  if (element instanceof Leg) {
443  Leg leg = (Leg) element;
444  Route route = leg.getRoute();
445  String mode = leg.getMode();
446 
447  if (route == null) {
448  return;
449  }
450 
451  events.add(new PersonDepartureEvent(0, id, route.getStartLinkId(), leg.getMode(), TripStructureUtils.getRoutingMode(leg)));
452  if (route instanceof NetworkRoute) {
453  if (scenario.getConfig().hermes().getMainModes().contains(leg.getMode())) {
454  processPlanNetworkRoute(person, flatplan, events, leg, (NetworkRoute) route, agent);
455  } else {
456  processTeleport(id, flatplan, events, (Leg) element, route, mode);
457  }
458  } else if (route instanceof TransitPassengerRoute) {
459  processPlanTransitRoute(id, flatplan, events, (TransitPassengerRoute) route);
460 
461  } else if (route instanceof GenericRouteImpl) {
462  processTeleport(id, flatplan, events, (Leg) element, route, mode);
463  } else {
464  throw new RuntimeException("Route type not supported by Hermes: " + route.getRouteType() + "\n Person:" + id + "\n Leg" + leg + "\n Leg" + route);
465  }
466 
467  events.add(new PersonArrivalEvent(0, id, route.getEndLinkId(), leg.getMode()));
468 
469  } else if (element instanceof Activity) {
470  processPlanActivity(id, flatplan, events, (Activity) element);
471  } else {
472  throw new RuntimeException("Unknown plan element " + element);
473  }
474  }
475 
476  private void processTeleport(Id<Person> id, PlanArray flatplan, EventArray events, Leg element, Route route, String mode) {
477  double routeTravelTime = route.getTravelTime().orElse(0.0);
478  double legTravelTime = element.getTravelTime().orElse(0.0);
479  int time = Math.max(0, (int) Math.round(Math.max(routeTravelTime, legTravelTime)) - 2);
480  //2 second is deducted as this is the maximum possible loss during interaction activities
481  flatplan.add(Agent.prepareSleepForEntry(events.size() - 1, time));
482  events.add(new TeleportationArrivalEvent(0, id, route.getDistance(), mode));
483  }
484 
485  private void generateAgent(
486  int agentId,
487  int capacity,
488  PlanArray flatplan,
489  EventArray events) {
490 
491  if (events.size() >= HermesConfigGroup.MAX_EVENTS_AGENT) {
492  throw new RuntimeException("exceeded maximum number of agent events");
493  }
494 
495  hermesAgents[agentId] = new Agent(agentId, capacity, flatplan, events);
496  }
497 
498  private double delayHelper(double expected, OptionalTime delay_a, OptionalTime delay_b) {
499  if (delay_a.isDefined()) {
500  return expected + delay_a.seconds();
501  } else if (delay_b.isDefined()) {
502  return expected + delay_b.seconds();
503  } else {
504  return expected;
505  }
506  }
507 
508  private double arrivalOffsetHelper(Departure depart, TransitRouteStop trs) {
509  return delayHelper(depart.getDepartureTime(), trs.getArrivalOffset(), trs.getDepartureOffset());
510  }
511 
512  private double departureOffsetHelper(Departure depart, TransitRouteStop trs) {
513  return delayHelper(depart.getDepartureTime(), trs.getDepartureOffset(), trs.getArrivalOffset());
514  }
515 
516  private static class TransitRouteContext {
517  final Agent agent;
518  final PlanArray flatplan;
519  final EventArray flatevents;
520  final TransitLine tl;
521  final TransitRoute tr;
522  final int routeNo;
523  final Departure depart;
524  final List<TransitRouteStop> trs;
525  final Id<Vehicle> vehId;
526  final double[] averageSpeedBetweenStops;
527  int stopidx = 0;
528  int time;
529 
530  public TransitRouteContext(Agent agent, TransitLine tl, TransitRoute tr, int routeNo, Departure depart, Network network) {
531  this.agent = agent;
532  this.flatplan = agent.plan;
533  this.flatevents = agent.events;
534  this.tl = tl;
535  this.tr = tr;
536  this.routeNo = routeNo;
537  this.depart = depart;
538  this.trs = tr.getStops();
539  this.vehId = depart.getVehicleId();
540  this.averageSpeedBetweenStops = calculateSpeedsBetweenStops(network);
541  int earlyDeparture = this.trs.get(0).getDepartureOffset().seconds() > 0 ? 0 : 3; // start 3 seconds early if we should depart at offset 0.0, otherwise exactly at the specified time
542  this.time = Math.max(0, (int) depart.getDepartureTime() - earlyDeparture);
543  }
544 
545  private double[] calculateSpeedsBetweenStops(Network network) {
546  double[] speeds = new double[this.trs.size()];
547 
548  NetworkRoute route = this.tr.getRoute();
549  List<Link> links = new ArrayList<>();
550  links.add(network.getLinks().get(route.getStartLinkId()));
551  for (Id<Link> linkId : route.getLinkIds()) {
552  links.add(network.getLinks().get(linkId));
553  }
554  links.add(network.getLinks().get(route.getEndLinkId()));
555 
556  double distance = 0;
557  int stopIdx = 0;
558  TransitRouteStop nextStop = this.trs.get(stopIdx);
559  Id<Link> nextStopLinkId = nextStop.getStopFacility().getLinkId();
560  boolean isFirstLink = true;
561 
562  double lastDepartureOffset = 0;
563 
564  for (Link link : links) {
565  if (!isFirstLink) {
566  distance += link.getLength();
567  }
568  isFirstLink = false;
569 
570  while (nextStop != null) {
571  if (link.getId().equals(nextStopLinkId)) {
572  double offset = nextStop.getArrivalOffset().or(nextStop.getDepartureOffset()).orElseThrow((() -> new RuntimeException("Stop has neither arrival nor departure offset")));
573  double travelTime = offset - lastDepartureOffset;
574  double speed = Math.ceil(distance / travelTime);
577  } else if (speed < 1.0) {
578  // make sure vehicle always is at least 1m/s fast to prevent 0 values which result in Infinite values later on
579  speed = 1.0;
580  }
581  speeds[stopIdx] = speed;
582  stopIdx++;
583  distance = 0;
584  lastDepartureOffset = nextStop.getDepartureOffset().or(nextStop.getArrivalOffset()).orElseThrow((() -> new RuntimeException("Stop has neither arrival nor departure offset")));
585 
586  if (stopIdx < this.trs.size()) {
587  nextStop = this.trs.get(stopIdx);
588  nextStopLinkId = nextStop.getStopFacility().getLinkId();
589  } else {
590  nextStop = null;
591  nextStopLinkId = null;
592  break;
593  }
594  } else {
595  break;
596  }
597  }
598  }
599  return speeds;
600  }
601  }
602 
603  private void generateDeterministicVehicleOnLink(TransitRouteContext c, Id<Link> linkId, boolean generateLinkEnterEvent, boolean generateLinkLeaveEvent) {
604  if (generateLinkEnterEvent) {
605  if (c.time < this.deterministicPtEvents.size()) {
606  this.deterministicPtEvents.get(c.time).add(new LinkEnterEvent(c.time, c.vehId, linkId));
607  }
608  }
609 
610  int stopsToHandle = 0;
611  while (true) {
612  int tmpStopIdx = c.stopidx + stopsToHandle;
613  if (tmpStopIdx >= c.trs.size()) {
614  break;
615  }
616  boolean stopOnLink = c.trs.get(tmpStopIdx).getStopFacility().getLinkId().equals(linkId);
617  if (stopOnLink) {
618  stopsToHandle++;
619  } else {
620  break;
621  }
622  }
623  if (stopsToHandle > 0) {
624  for (int i = 0; i < stopsToHandle; i++) {
625  TransitRouteStop routeStop = c.trs.get(c.stopidx);
626  Id<TransitStopFacility> stopId = routeStop.getStopFacility().getId();
627  int stopIdIndex = stopId.index();
628  double arrivalTime = arrivalOffsetHelper(c.depart, routeStop);
629  double departureTime = departureOffsetHelper(c.depart, routeStop);
630 
631  if (arrivalTime == departureTime && arrivalTime >= 2) {
632  arrivalTime -= 2;
633  }
634 
635  c.time++;
636  if (arrivalTime < c.time) {
637  arrivalTime = c.time; // there should be at least 1 second between the last stop and this one
638  }
639  if (departureTime < arrivalTime - 2) {
640  departureTime = arrivalTime + 2;
641  }
642 
643  if (c.stopidx != 0 || c.time < arrivalTime) {
644  c.flatplan.add(Agent.prepareSleepUntilEntry(0, (int) arrivalTime));
645  }
646 
647  c.flatevents.add(new VehicleArrivesAtFacilityEvent(0, c.vehId, stopId, arrivalTime));
648  c.flatplan.add(Agent.prepareStopArrivalEntry(c.flatevents.size() - 1, c.routeNo, stopIdIndex));
649  c.agent.setServeStop(stopIdIndex);
650 
651  // no event associated to stop delay
652  c.flatplan.add(Agent.prepareStopDelayEntry((int) departureTime, c.routeNo, stopIdIndex));
653 
654  c.flatevents.add(new VehicleDepartsAtFacilityEvent(0, c.vehId, stopId, departureTime));
655  c.flatplan.add(Agent.prepareStopDepartureEntry(c.flatevents.size() - 1, c.routeNo, stopIdIndex));
656 
657  c.time = (int) departureTime;
658  c.stopidx++;
659  }
660  }
661 
662  if (generateLinkLeaveEvent) {
663  if (stopsToHandle > 0) {
664  // if we handled a stop, then just assume we leave the link directly after handling the stop.
665  c.time++;
666  } else {
667  // otherwise, calculate the travel time on the link
668  if (generateLinkEnterEvent) {
669  // .. but only if we actually traversed this link, i.e. if we also entered this link
670  Link link = this.scenario.getNetwork().getLinks().get(linkId);
671  double length = link.getLength();
672  if (c.stopidx < c.averageSpeedBetweenStops.length) {
673  double avgSpeed = c.averageSpeedBetweenStops[c.stopidx];
674  c.time += length / avgSpeed;
675  } else {
676  // a link after the last stop
677  c.time += length / link.getFreespeed();
678  }
679  } else {
680  // we did not handle a stop, but also not enter the link. Most likely it's the first link of the route,
681  // but without any stop on it. So just leave the link in the next second.
682  c.time++;
683  }
684  }
685 
686  if (c.time < this.deterministicPtEvents.size()) {
687  this.deterministicPtEvents.get(c.time).add(new LinkLeaveEvent(c.time, c.vehId, linkId));
688  }
689  } else if (stopsToHandle == 0) { // last link, which did not have any stop on it
690  // make sure to adapt the time, so the driver does not exit the vehicle too early
691  Link link = this.scenario.getNetwork().getLinks().get(linkId);
692  c.time += link.getLength() / link.getFreespeed();
693  c.flatplan.add(Agent.prepareSleepUntilEntry(0, c.time+1)); // wait finishing the agent until we've driven along all links
694  }
695  }
696 
697  private void generateDeterministicVehicleTrip(
698  Agent agent,
699  TransitLine tl,
700  TransitRoute tr,
701  Departure depart) {
702 
703  Vehicle v = this.scenario.getTransitVehicles().getVehicles().get(depart.getVehicleId());
704  int routeNo = this.routeNumbers.get(tl.getId()).get(tr.getId());
705 
706  TransitRouteContext context = new TransitRouteContext(agent, tl, tr, routeNo, depart, this.scenario.getNetwork());
707  PlanArray flatplan = agent.plan;
708  EventArray flatevents = agent.events;
709 
710  VehicleType vt = v.getType();
711  NetworkRoute nr = tr.getRoute();
712 
713  Id<Person> driverid = Id.createPersonId("pt_" + v.getId() + "_" + vt.getId());
714  String legmode = TransportMode.pt;
715  String routingmode = TransportMode.pt;
716 
717  // Prepare to leave
718  flatevents.add(new TransitDriverStartsEvent(0, driverid, v.getId(), tl.getId(), tr.getId(), depart.getId()));
719  flatevents.add(new PersonDepartureEvent(0, driverid, nr.getStartLinkId(), legmode, routingmode));
720  flatevents.add(new PersonEntersVehicleEvent(0, driverid, v.getId()));
721 
722  flatevents.add(new VehicleEntersTrafficEvent(context.time, driverid, nr.getStartLinkId(), v.getId(), legmode, 1));
723 
724  // Sleep until the time of departure
725  // the very first flat plan entry does not handle events, so actually add two entries, so the events are correctly handled
726  flatplan.add(Agent.prepareSleepUntilEntry(0, Math.max(0, context.time)));
727  flatplan.add(Agent.prepareSleepUntilEntry(flatevents.size() - 1, context.time + 1));
728 
729  // first link
730  generateDeterministicVehicleOnLink(context, nr.getStartLinkId(), false, true);
731 
732  // links
734  generateDeterministicVehicleOnLink(context, link, true, true);
735  }
736 
737  // last link
738  generateDeterministicVehicleOnLink(context, nr.getEndLinkId(), true, false);
739 
740  flatevents.add(new VehicleLeavesTrafficEvent(0, driverid, nr.getEndLinkId(), v.getId(), legmode, 1));
741  flatevents.add(new PersonLeavesVehicleEvent(0, driverid, v.getId()));
742  flatevents.add(new PersonArrivalEvent(0, driverid, nr.getEndLinkId(), legmode));
743  }
744 
745  private void generateNondeterministicVehicleOnLink(TransitRouteContext c, Id<Link> linkId, boolean generateLinkEnterEvent, boolean generateLinkLeaveEvent, int velocity, int pcuCategory) {
746  if (generateLinkEnterEvent) {
747  c.flatevents.add(new LinkEnterEvent(0, c.vehId, linkId));
748  c.flatplan.add(Agent.prepareLinkEntry(c.flatevents.size() - 1, linkId.index(), velocity, pcuCategory));
749  }
750 
751  while (true) {
752  if (c.stopidx >= c.trs.size()) {
753  break;
754  }
755  TransitRouteStop routeStop = c.trs.get(c.stopidx);
756  boolean stopOnLink = routeStop.getStopFacility().getLinkId().equals(linkId);
757  if (stopOnLink) {
758  Id<TransitStopFacility> stopId = routeStop.getStopFacility().getId();
759  int stopIdIndex = stopId.index();
760  double arrivalTime = arrivalOffsetHelper(c.depart, routeStop);
761  double departureTime = departureOffsetHelper(c.depart, routeStop);
762 
763  c.flatevents.add(new VehicleArrivesAtFacilityEvent(0, c.vehId, stopId, arrivalTime));
764  c.flatplan.add(Agent.prepareStopArrivalEntry(c.flatevents.size() - 1, c.routeNo, stopIdIndex));
765  c.agent.setServeStop(stopIdIndex);
766 
767  // no event associated to stop delay
768  c.flatplan.add(Agent.prepareStopDelayEntry((int) departureTime, c.routeNo, stopIdIndex));
769 
770  c.flatevents.add(new VehicleDepartsAtFacilityEvent(0, c.vehId, stopId, departureTime));
771  c.flatplan.add(Agent.prepareStopDepartureEntry(c.flatevents.size() - 1, c.routeNo, stopIdIndex));
772 
773  c.stopidx++;
774  } else {
775  break;
776  }
777  }
778 
779  if (generateLinkLeaveEvent) {
780  c.flatevents.add(new LinkLeaveEvent(0, c.vehId, linkId));
781  }
782  }
783 
784  private void generateVehicleTrip(
785  Agent agent,
786  TransitLine tl,
787  TransitRoute tr,
788  Departure depart) {
789 
790  int routeNo = this.routeNumbers.get(tl.getId()).get(tr.getId());
791  TransitRouteContext context = new TransitRouteContext(agent, tl, tr, routeNo, depart, this.scenario.getNetwork());
792  PlanArray flatplan = agent.plan;
793  EventArray flatevents = agent.events;
794  Vehicle v = this.scenario.getTransitVehicles().getVehicles().get(depart.getVehicleId());
795  VehicleType vt = v.getType();
796  NetworkRoute nr = tr.getRoute();
797  int pcuCategory = 0;
798  //the PCU category for transit vehicles is never read from plan entry but remains constant over the day
799  int velocity = (int) Math.min(Math.round(v.getType().getMaximumVelocity()), HermesConfigGroup.MAX_VEHICLE_VELOCITY);
800 
801  Id<Person> driverid = Id.createPersonId("pt_" + v.getId() + "_" + vt.getId());
802  String legmode = TransportMode.car;
803  String routingmode = TransportMode.car;
804 
805  // Sleep until the time of departure
806  flatplan.add(Agent.prepareSleepUntilEntry(0, (int) Math.round(depart.getDepartureTime())));
807 
808  // Prepare to leave
809  flatevents.add(new TransitDriverStartsEvent(0, driverid, v.getId(), tl.getId(), tr.getId(), depart.getId()));
810  flatevents.add(new PersonDepartureEvent(0, driverid, nr.getStartLinkId(), legmode, routingmode));
811  flatevents.add(new PersonEntersVehicleEvent(0, driverid, v.getId()));
812  flatevents.add(new VehicleEntersTrafficEvent(0, driverid, nr.getStartLinkId(), v.getId(), legmode, 1));
813 
814  generateNondeterministicVehicleOnLink(context, nr.getStartLinkId(), false, true, velocity, pcuCategory);
815 
817  generateNondeterministicVehicleOnLink(context, link, true, true, velocity, pcuCategory);
818  }
819 
820  generateNondeterministicVehicleOnLink(context, nr.getEndLinkId(), true, false, velocity, pcuCategory);
821 
822  flatevents.add(new VehicleLeavesTrafficEvent(0, driverid, nr.getEndLinkId(), v.getId(), legmode, 1));
823  flatevents.add(new PersonLeavesVehicleEvent(0, driverid, v.getId()));
824  flatevents.add(new PersonArrivalEvent(0, driverid, nr.getEndLinkId(), legmode));
825  }
826 
827  private void generateTransitVehiclePlans() {
828  Map<Id<Vehicle>, Vehicle> vehicles = scenario.getTransitVehicles().getVehicles();
829  scenario.getTransitSchedule().getTransitLines().values().stream().forEach((tl) -> {
830  for (TransitRoute tr : tl.getRoutes().values()) {
831  for (Departure depart : tr.getDepartures().values()) {
832  Vehicle v = vehicles.get(depart.getVehicleId());
833  int hermes_id = hermes_id(v.getId().index(), true);
834  Agent agent = hermesAgents[hermes_id];
835  float storageCapacityPCUE = deterministicPt ? 0.1f : (float) v.getType().getPcuEquivalents();
836  float flowCapacityPCUE = deterministicPt ? 0.1f : (float) (v.getType().getPcuEquivalents() / v.getType().getFlowEfficiencyFactor());
837  // for pt vehicles, storage and flow capacities are never updated
838  hermesAgents[hermes_id].setStorageCapacityPCUE(storageCapacityPCUE);
839  hermesAgents[hermes_id].setFlowCapacityPCUE(flowCapacityPCUE);
840  if (deterministicPt) {
841  generateDeterministicVehicleTrip(agent, tl, tr, depart);
842  } else {
843  generateVehicleTrip(agent, tl, tr, depart);
844  }
845  }
846  }
847  });
848 
849  }
850 
851  private void generatePersonPlans() {
852  Population population = scenario.getPopulation();
853  population.getPersons().values().parallelStream().forEach((person) -> {
854  int hermes_id = hermes_id(person.getId().index(), false);
855  PlanArray plan = hermesAgents[hermes_id].plan();
856  EventArray events = hermesAgents[hermes_id].events();
857  for (PlanElement element : person.getSelectedPlan().getPlanElements()) {
858  processPlanElement(person, plan, events, element, hermesAgents[hermes_id]);
859  }
860  });
861  }
862 
863  private void generateAgents() {
864  Population population = scenario.getPopulation();
865  Map<Id<Vehicle>, Vehicle> vehicles = scenario.getTransitVehicles().getVehicles();
866  agentPersons = Id.getNumberOfIds(Person.class);
867  int nagents = agentPersons + Id.getNumberOfIds(Vehicle.class);
868  hermesAgents = new Agent[nagents];
869 
870  // Generate persons
871  for (Person person : population.getPersons().values()) {
872  int hermes_id = hermes_id(person.getId().index(), false);
873  assert hermesAgents[hermes_id] == null;
874  generateAgent(hermes_id, 0, new PlanArray(), new EventArray());
875  }
876 
877  // Generate vehicles
878  for (Vehicle vehicle : vehicles.values()) {
879  VehicleCapacity vc = vehicle.getType().getCapacity();
880  int capacity = vc.getSeats() + vc.getStandingRoom();
881  int hermes_id = hermes_id(vehicle.getId().index(), true);
882  assert hermesAgents[hermes_id] == null;
883  generateAgent(hermes_id, capacity, new PlanArray(), new EventArray());
884  }
885  }
886 
887  public int matsim_id(int hermes_id, boolean is_vehicle) {
888  if (is_vehicle) {
889  return hermes_id - agentPersons;
890  } else {
891  return hermes_id;
892  }
893  }
894 
895  public int hermes_id(int matsim_id, boolean is_vehicle) {
896  if (is_vehicle) {
897  return matsim_id + agentPersons;
898  } else {
899  return matsim_id;
900  }
901  }
902 
903  private void generatePlans() {
904  generatePersonPlans();
905  generateTransitVehiclePlans();
906  }
907 
908  public float getFlowCapacityPCE(int index) {
909  return flowCapacityPCEs[index];
910  }
911 
912  public float getStorageCapacityPCE(int index) {
913  return storageCapacityPCEs[index];
914  }
915 
916  public List<List<Event>> getDeterministicPtEvents() {
917  return deterministicPtEvents;
918  }
919 
920  public boolean isDeterministicPt() {
921  return deterministicPt;
922  }
923 }
Map< Id< ActivityFacility >, ? extends ActivityFacility > getFacilities()
Map< Id< TransitRoute >, TransitRoute > getRoutes()
static< T > Id< T > get(int index, final Class< T > type)
Definition: Id.java:112
static< T > int getNumberOfIds(final Class< T > type)
Definition: Id.java:122
TransitRouteContext(Agent agent, TransitLine tl, TransitRoute tr, int routeNo, Departure depart, Network network)
static Id< Vehicle > createVehicleId(final long key)
Definition: Id.java:220
Map< Id< VehicleType >, VehicleType > getVehicleTypes()
final double getFlowEfficiencyFactor()
Map< Id< Person >,? extends Person > getPersons()
HermesConfigGroup hermes()
Definition: Config.java:479
Map< Id< Departure >, Departure > getDepartures()
Map< Id< Link >, ? extends Link > getLinks()
abstract TransitStopFacility getStopFacility()
Id< ActivityFacility > getFacilityId()
static Id< Person > createPersonId(final long key)
Definition: Id.java:193
final Id< VehicleType > getId()
Map< Id< Vehicle >, Vehicle > getVehicles()
ActivityFacilities getActivityFacilities()
TransitSchedule getTransitSchedule()
Map< Id< TransitLine >, TransitLine > getTransitLines()
final GlobalConfigGroup global()
Definition: Config.java:395
OptionalTime or(OptionalTime optionalTime)