20 package org.matsim.core.mobsim.hermes;
22 import org.apache.logging.log4j.LogManager;
23 import org.apache.logging.log4j.Logger;
51 class ScenarioImporter {
53 final private static Logger log = LogManager.getLogger(Hermes.class);
55 private static ScenarioImporter instance;
57 private Thread resetThread = null;
62 private final Map<Id<VehicleType>, Integer> vehicleTypeMapping =
new HashMap<>();
63 protected int agentPersons;
66 protected IdMap<TransitLine, ArrayMap<Id<TransitRoute>, Integer>> routeNumbers;
70 protected int[][] routeStopsByRouteNo;
73 protected int[] lineOfRoute;
76 protected int[] routeOfRoute;
78 protected HLink[] hermesLinks;
80 protected Realm realm;
81 private final boolean deterministicPt;
84 protected IdMap<TransitStopFacility, IntArrayMap<ArrayDeque<Agent>>> agentStops;
86 private float[] flowCapacityPCEs;
87 private float[] storageCapacityPCEs;
90 protected Agent[] hermesAgents;
92 private final int numberOfThreads;
93 private final List<List<Event>> deterministicPtEvents;
98 if (deterministicPt) {
101 deterministicPtEvents.add(
new ArrayList<>(16));
104 deterministicPtEvents = Collections.EMPTY_LIST;
106 this.scenario = scenario;
107 this.eventsManager = eventsManager;
108 generateVehicleCategories();
115 private void generateVehicleCategories() {
117 if (vehicleTypes >= HermesConfigGroup.MAX_VEHICLE_PCETYPES) {
119 "Too many vehicle types defined. A maximum of " + HermesConfigGroup.MAX_VEHICLE_PCETYPES +
" is supported.");
121 flowCapacityPCEs =
new float[vehicleTypes];
122 storageCapacityPCEs =
new float[vehicleTypes];
128 vehicleTypeMapping.put(t.getId(), i);
134 public static void flush() {
140 if (instance == null || !scenario.equals(instance.scenario) || !eventsManager.equals(instance.eventsManager)) {
141 log.info(
"Hermes rebuilding scenario!");
142 instance =
new ScenarioImporter(scenario, eventsManager);
147 public void generate() throws
Exception {
148 long time = System.currentTimeMillis();
150 if (resetThread != null) {
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();
157 log.info(String.format(
"Hermes generatePlans took %d ms", System.currentTimeMillis() - time));
158 time = System.currentTimeMillis();
160 log.info(String.format(
"Hermes generateRealms took %d ms", System.currentTimeMillis() - time));
163 public void reset() {
164 resetThread =
new Thread() {
168 log.info(
"resetting hermes...");
170 for (HLink link : hermesLinks) {
176 for (Agent hermes_agent : hermesAgents) {
177 if (hermes_agent != null) {
178 hermes_agent.reset();
182 for (IntArrayMap<ArrayDeque<Agent>> station_id : agentStops) {
183 for (ArrayDeque<Agent> agents_per_line : station_id.values()) {
184 agents_per_line.clear();
194 private void generateLinks() {
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();
208 if (link_id > HermesConfigGroup.MAX_LINK_ID) {
212 hermesLinks[link_id] =
new HLink(link_id, storageCapacity, length, speed, effectiveflowCapacityPerSec, scenario.
getConfig().
hermes().
getStuckTime());
216 private void initRoutesStations() {
221 routeCount += tl.getRoutes().size();
224 this.lineOfRoute =
new int[routeCount];
225 this.routeOfRoute =
new int[routeCount];
226 this.routeStopsByRouteNo =
new int[routeCount][];
228 this.routeNumbers =
new IdMap<>(
TransitLine.class);
231 ArrayMap<Id<TransitRoute>, Integer> routesMap =
new ArrayMap<>();
232 this.routeNumbers.put(tl.getId(), routesMap);
233 int lineId = tl.getId().index();
235 routesMap.put(tr.getId(), routeNo);
236 int routeId = tr.getId().index();
237 this.lineOfRoute[routeNo] = lineId;
238 this.routeOfRoute[routeNo] = routeId;
240 List<TransitRouteStop> stops = tr.getStops();
241 int[] tr_stops =
new int[stops.size()];
242 for (
int i = 0; i < stops.size(); i++) {
247 this.routeStopsByRouteNo[routeNo] = tr_stops;
253 private void generatePT() {
254 initRoutesStations();
260 for (
TransitLine line : ts.getTransitLines().values()) {
262 List<TransitRouteStop> stops = route.getStops();
263 for (
int i = 0, stopsCount = stops.size(); i < stopsCount; i++) {
267 IntArrayMap<ArrayDeque<Agent>> linesMap = this.agentStops.computeIfAbsent(stopFacility.
getId(), k ->
new IntArrayMap<>());
268 linesMap.computeIfAbsent(line.getId().index(), k ->
new ArrayDeque<>());
274 private void generateRealms() {
275 realm =
new Realm(
this, eventsManager);
278 for (Agent agent : hermesAgents) {
280 if (agent == null || agent.plan.size() == 0) {
283 long planentry = agent.plan().get(0);
284 int type = Agent.getPlanHeader(planentry);
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)));
294 case Agent.SleepForType:
295 case Agent.SleepUntilType:
296 int sleep = Agent.getSleepPlanEntry(planentry);
300 LogManager.getLogger(getClass()).error(String.format(
"ERROR -> unknown plan element type %d", type));
304 for (HLink link : this.hermesLinks) {
306 int nextwakeup = link.nexttime();
307 if (nextwakeup > 0) {
308 realm.delayedLinks().get(nextwakeup).add(link);
314 private void processPlanActivity(
330 if (facility == null || facility.
getLinkId() == null) {
337 assert linkid != null;
340 if (flatplan.size() != 0) {
342 eventid = events.
size() - 1;
349 flatplan.add(Agent.prepareSleepUntilEntry(eventid, time));
352 flatplan.add(Agent.prepareSleepForEntry(eventid, time));
355 flatplan.add(Agent.prepareSleepForEntry(eventid, 0));
360 private void processPlanNetworkRoute(
367 var
id = person.getId();
371 Vehicle v = vehicles.get(VehicleUtils.getVehicleId(person, leg.
getMode()));
373 int pcuCategory = this.vehicleTypeMapping.get(vtypeid);
375 double velocity = v == null ?
377 int egressId = endLId.index();
380 if (agent.getFlowCapacityPCUE() == -1) {
381 agent.setFlowCapacityPCUE(getFlowCapacityPCE(pcuCategory));
383 if (agent.getStorageCapacityPCUE() == -1) {
384 agent.setStorageCapacityPCUE(getStorageCapacityPCE(pcuCategory));
388 if (netroute.
getLinkIds().size() > 1 || !startLId.equals(endLId)) {
392 int linkId = linkid.index();
394 flatplan.add(Agent.prepareLinkEntry(events.
size() - 1, linkId, velocity, pcuCategory));
397 if (netroute.
getLinkIds().size() > 1 || !startLId.equals(endLId)) {
399 flatplan.add(Agent.prepareLinkEntry(events.
size() - 1, egressId, velocity, pcuCategory));
405 private void populateStops(
int srcStopId,
int lineId) {
406 IntArrayMap<ArrayDeque<Agent>> agents = this.agentStops.get(srcStopId);
407 agents.computeIfAbsent(lineId, k ->
new ArrayDeque<>());
410 private void processPlanTransitRoute(
414 TransitPassengerRoute troute) {
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());
422 populateStops(accessid, lineid);
428 flatplan.add(Agent.prepareWaitEntry(events.
size() - 1, routeNo, accessid));
430 flatplan.add(Agent.prepareAccessEntry(events.
size() - 1, routeNo, accessid));
432 flatplan.add(Agent.prepareEgressEntry(events.
size() - 1, routeNo, egressid));
435 private void processPlanElement(
441 var
id = person.getId();
442 if (element instanceof
Leg) {
443 Leg leg = (Leg) element;
454 processPlanNetworkRoute(person, flatplan, events, leg, (NetworkRoute) route, agent);
456 processTeleport(
id, flatplan, events, (Leg) element, route, mode);
458 }
else if (route instanceof TransitPassengerRoute) {
459 processPlanTransitRoute(
id, flatplan, events, (TransitPassengerRoute) route);
461 }
else if (route instanceof GenericRouteImpl) {
462 processTeleport(
id, flatplan, events, (Leg) element, route, mode);
464 throw new RuntimeException(
"Route type not supported by Hermes: " + route.
getRouteType() +
"\n Person:" +
id +
"\n Leg" + leg +
"\n Leg" + route);
469 }
else if (element instanceof
Activity) {
470 processPlanActivity(
id, flatplan, events, (Activity) element);
476 private void processTeleport(
Id<Person> id, PlanArray flatplan,
EventArray events, Leg element,
Route route, String mode) {
479 int time = Math.max(0, (
int) Math.round(Math.max(routeTravelTime, legTravelTime)) - 2);
481 flatplan.add(Agent.prepareSleepForEntry(events.
size() - 1, time));
485 private void generateAgent(
491 if (events.
size() >= HermesConfigGroup.MAX_EVENTS_AGENT) {
495 hermesAgents[agentId] =
new Agent(agentId, capacity, flatplan, events);
500 return expected + delay_a.
seconds();
502 return expected + delay_b.
seconds();
524 final List<TransitRouteStop> trs;
526 final double[] averageSpeedBetweenStops;
532 this.flatplan = agent.plan;
533 this.flatevents = agent.events;
536 this.routeNo = routeNo;
537 this.depart = depart;
541 int earlyDeparture = this.trs.get(0).getDepartureOffset().seconds() > 0 ? 0 : 3;
546 double[] speeds =
new double[this.trs.size()];
548 NetworkRoute route = this.tr.
getRoute();
549 List<Link> links =
new ArrayList<>();
552 links.add(network.
getLinks().get(linkId));
560 boolean isFirstLink =
true;
562 double lastDepartureOffset = 0;
564 for (
Link link : links) {
566 distance += link.getLength();
570 while (nextStop != null) {
571 if (link.getId().equals(nextStopLinkId)) {
573 double travelTime = offset - lastDepartureOffset;
574 double speed = Math.ceil(distance / travelTime);
577 }
else if (speed < 1.0) {
581 speeds[stopIdx] = speed;
586 if (stopIdx < this.trs.size()) {
587 nextStop = this.trs.get(stopIdx);
591 nextStopLinkId = null;
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));
610 int stopsToHandle = 0;
612 int tmpStopIdx = c.stopidx + stopsToHandle;
613 if (tmpStopIdx >= c.trs.size()) {
616 boolean stopOnLink = c.trs.get(tmpStopIdx).getStopFacility().getLinkId().equals(linkId);
623 if (stopsToHandle > 0) {
624 for (
int i = 0; i < stopsToHandle; i++) {
627 int stopIdIndex = stopId.
index();
628 double arrivalTime = arrivalOffsetHelper(c.depart, routeStop);
629 double departureTime = departureOffsetHelper(c.depart, routeStop);
631 if (arrivalTime == departureTime && arrivalTime >= 2) {
636 if (arrivalTime < c.time) {
637 arrivalTime = c.time;
639 if (departureTime < arrivalTime - 2) {
640 departureTime = arrivalTime + 2;
643 if (c.stopidx != 0 || c.time < arrivalTime) {
644 c.flatplan.
add(Agent.prepareSleepUntilEntry(0, (
int) arrivalTime));
648 c.flatplan.
add(Agent.prepareStopArrivalEntry(c.flatevents.
size() - 1, c.routeNo, stopIdIndex));
649 c.agent.setServeStop(stopIdIndex);
652 c.flatplan.
add(Agent.prepareStopDelayEntry((
int) departureTime, c.routeNo, stopIdIndex));
655 c.flatplan.
add(Agent.prepareStopDepartureEntry(c.flatevents.
size() - 1, c.routeNo, stopIdIndex));
657 c.time = (int) departureTime;
662 if (generateLinkLeaveEvent) {
663 if (stopsToHandle > 0) {
668 if (generateLinkEnterEvent) {
672 if (c.stopidx < c.averageSpeedBetweenStops.length) {
673 double avgSpeed = c.averageSpeedBetweenStops[c.stopidx];
674 c.time += length / avgSpeed;
686 if (c.time <
this.deterministicPtEvents.size()) {
687 this.deterministicPtEvents.get(c.time).add(
new LinkLeaveEvent(c.time, c.vehId, linkId));
689 }
else if (stopsToHandle == 0) {
693 c.flatplan.
add(Agent.prepareSleepUntilEntry(0, c.time+1));
697 private void generateDeterministicVehicleTrip(
704 int routeNo = this.routeNumbers.get(tl.
getId()).
get(tr.
getId());
726 flatplan.add(Agent.prepareSleepUntilEntry(0, Math.max(0, context.time)));
727 flatplan.add(Agent.prepareSleepUntilEntry(flatevents.
size() - 1, context.time + 1));
730 generateDeterministicVehicleOnLink(context, nr.
getStartLinkId(),
false,
true);
734 generateDeterministicVehicleOnLink(context, link,
true,
true);
738 generateDeterministicVehicleOnLink(context, nr.
getEndLinkId(),
true,
false);
745 private void generateNondeterministicVehicleOnLink(
TransitRouteContext c,
Id<Link> linkId,
boolean generateLinkEnterEvent,
boolean generateLinkLeaveEvent,
int velocity,
int pcuCategory) {
746 if (generateLinkEnterEvent) {
748 c.flatplan.
add(Agent.prepareLinkEntry(c.flatevents.
size() - 1, linkId.
index(), velocity, pcuCategory));
752 if (c.stopidx >= c.trs.size()) {
759 int stopIdIndex = stopId.
index();
760 double arrivalTime = arrivalOffsetHelper(c.depart, routeStop);
761 double departureTime = departureOffsetHelper(c.depart, routeStop);
764 c.flatplan.
add(Agent.prepareStopArrivalEntry(c.flatevents.
size() - 1, c.routeNo, stopIdIndex));
765 c.agent.setServeStop(stopIdIndex);
768 c.flatplan.
add(Agent.prepareStopDelayEntry((
int) departureTime, c.routeNo, stopIdIndex));
771 c.flatplan.
add(Agent.prepareStopDepartureEntry(c.flatevents.
size() - 1, c.routeNo, stopIdIndex));
779 if (generateLinkLeaveEvent) {
784 private void generateVehicleTrip(
790 int routeNo = this.routeNumbers.get(tl.
getId()).
get(tr.
getId());
806 flatplan.add(Agent.prepareSleepUntilEntry(0, (
int) Math.round(depart.
getDepartureTime())));
814 generateNondeterministicVehicleOnLink(context, nr.
getStartLinkId(),
false,
true, velocity, pcuCategory);
817 generateNondeterministicVehicleOnLink(context, link,
true,
true, velocity, pcuCategory);
820 generateNondeterministicVehicleOnLink(context, nr.
getEndLinkId(),
true,
false, velocity, pcuCategory);
827 private void generateTransitVehiclePlans() {
833 int hermes_id = hermes_id(v.
getId().index(),
true);
834 Agent agent = hermesAgents[hermes_id];
838 hermesAgents[hermes_id].setStorageCapacityPCUE(storageCapacityPCUE);
839 hermesAgents[hermes_id].setFlowCapacityPCUE(flowCapacityPCUE);
840 if (deterministicPt) {
841 generateDeterministicVehicleTrip(agent, tl, tr, depart);
843 generateVehicleTrip(agent, tl, tr, depart);
851 private void generatePersonPlans() {
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();
858 processPlanElement(person, plan, events, element, hermesAgents[hermes_id]);
863 private void generateAgents() {
868 hermesAgents =
new Agent[nagents];
872 int hermes_id = hermes_id(person.getId().index(),
false);
873 assert hermesAgents[hermes_id] == null;
878 for (
Vehicle vehicle : vehicles.values()) {
881 int hermes_id = hermes_id(vehicle.getId().index(),
true);
882 assert hermesAgents[hermes_id] == null;
887 public int matsim_id(
int hermes_id,
boolean is_vehicle) {
889 return hermes_id - agentPersons;
895 public int hermes_id(
int matsim_id,
boolean is_vehicle) {
897 return matsim_id + agentPersons;
903 private void generatePlans() {
904 generatePersonPlans();
905 generateTransitVehiclePlans();
908 public float getFlowCapacityPCE(
int index) {
909 return flowCapacityPCEs[index];
912 public float getStorageCapacityPCE(
int index) {
913 return storageCapacityPCEs[index];
916 public List<List<Event>> getDeterministicPtEvents() {
917 return deterministicPtEvents;
920 public boolean isDeterministicPt() {
921 return deterministicPt;
OptionalTime getEndTime()
double orElse(double other)
Map< Id< ActivityFacility >, ? extends ActivityFacility > getFacilities()
Map< Id< TransitRoute >, TransitRoute > getRoutes()
static< T > Id< T > get(int index, final Class< T > type)
static< T > int getNumberOfIds(final Class< T > type)
Id< Link > getStartLinkId()
OptionalTime getMaximumDuration()
TransitRouteContext(Agent agent, TransitLine tl, TransitRoute tr, int routeNo, Departure depart, Network network)
static Id< Vehicle > createVehicleId(final long key)
Vehicles getTransitVehicles()
Id< Vehicle > getVehicleId()
double getDepartureTime()
static final int MAX_VEHICLE_VELOCITY
Map< Id< VehicleType >, VehicleType > getVehicleTypes()
final double getMaximumVelocity()
final double getFlowEfficiencyFactor()
final double getPcuEquivalents()
Map< Id< Person >,? extends Person > getPersons()
Set< String > getMainModes()
Integer getStandingRoom()
double getFlowCapacityFactor()
List< Id< Link > > getLinkIds()
abstract OptionalTime getArrivalOffset()
HermesConfigGroup hermes()
List< TransitRouteStop > getStops()
OptionalTime getTravelTime()
Population getPopulation()
Map< Id< Departure >, Departure > getDepartures()
boolean isDeterministicPt()
Map< Id< Link >, ? extends Link > getLinks()
abstract TransitStopFacility getStopFacility()
OptionalTime getTravelTime()
double getEffectiveCellSize()
Id< ActivityFacility > getFacilityId()
static Id< Person > createPersonId(final long key)
final Id< VehicleType > getId()
Map< Id< Vehicle >, Vehicle > getVehicles()
ActivityFacilities getActivityFacilities()
TransitSchedule getTransitSchedule()
Id< Link > getEndLinkId()
Map< Id< TransitLine >, TransitLine > getTransitLines()
double getStorageCapacityFactor()
abstract OptionalTime getDepartureOffset()
final GlobalConfigGroup global()
abstract T getSelectedPlan()
double [] calculateSpeedsBetweenStops(Network network)
OptionalTime or(OptionalTime optionalTime)