MATSIM
EarliestLinkExitTimeProvider.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * MobsimDataProvider.java
4  * *
5  * *********************************************************************** *
6  * *
7  * copyright : (C) 2013 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.trafficmonitoring;
22 
23 import java.util.Collections;
24 import java.util.HashSet;
25 import java.util.Map;
26 import java.util.Set;
27 import java.util.concurrent.ConcurrentHashMap;
28 import java.util.concurrent.ConcurrentMap;
29 
30 import jakarta.inject.Inject;
31 import jakarta.inject.Named;
32 
33 import org.apache.logging.log4j.LogManager;
34 import org.apache.logging.log4j.Logger;
35 import org.matsim.api.core.v01.Id;
36 import org.matsim.api.core.v01.Scenario;
58 
68 
69  private static final Logger log = LogManager.getLogger(EarliestLinkExitTimeProvider.class);
70 
71  /*
72  * We have to create an internal TransportModeProvider and delegate the events to it.
73  * Otherwise, race conditions could occur since an it could not be guaranteed that an
74  * external TransportModeProvider has processed all relevant events when this class
75  * handles an event.
76  */
78 
79  private final Scenario scenario;
80  private final Map<String, TravelTime> multiModalTravelTimes;
82 
83  private final ConcurrentMap<Id<Person>, OptionalTime> earliestLinkExitTimes = new ConcurrentHashMap<>();
84  private final ConcurrentMap<OptionalTime, Set<Id<Person>>> earliestLinkExitTimesPerTimeStep = new ConcurrentHashMap<>();
85 
87 
88  public EarliestLinkExitTimeProvider(Scenario scenario, EventsManager eventsManager) {
89  this(scenario, null, eventsManager);
90  log.info("Note: no map containing TravelTime objects for all simulated modes is given. Therefore use free speed " +
91  "car travel time as minimal link travel time for all modes.");
92  }
93 
94  @Inject
95  public EarliestLinkExitTimeProvider(Scenario scenario, @Named("lowerBound") Map<String, TravelTime> multiModalTravelTimes, EventsManager eventsManager) {
96  this.scenario = scenario;
97  eventsManager.addHandler(this);
98  this.multiModalTravelTimes = multiModalTravelTimes;
99  this.transportModeProvider = new TransportModeProvider();
100  this.freeSpeedTravelTime = new FreeSpeedTravelTime();
101  }
102 
104  return this.transportModeProvider;
105  }
106 
108  return this.earliestLinkExitTimes.getOrDefault(agentId, OptionalTime.undefined());
109  }
110 
111  public Map<Id<Person>, OptionalTime> getEarliestLinkExitTimes() {
112  return Collections.unmodifiableMap(this.earliestLinkExitTimes);
113  }
114 
115  public Set<Id<Person>> getEarliestLinkExitTimesPerTimeStep(double time) {
116  Set<Id<Person>> set = this.earliestLinkExitTimesPerTimeStep.get(time);
117  if (set != null) return Collections.unmodifiableSet(set);
118  else return null;
119  }
120 
121  public Map<OptionalTime, Set<Id<Person>>> getEarliestLinkExitTimesPerTimeStep() {
122  return Collections.unmodifiableMap(this.earliestLinkExitTimesPerTimeStep);
123  }
124 
125  @Override
126  public void reset(int iteration) {
127  this.transportModeProvider.reset(iteration);
128 
129  this.earliestLinkExitTimes.clear();
130  this.earliestLinkExitTimesPerTimeStep.clear();
131  }
132 
133  @Override
134  public void handleEvent(PersonArrivalEvent event) {
135  this.transportModeProvider.handleEvent(event);
137  }
138 
139  @Override
140  public void handleEvent(LinkEnterEvent event) {
141  Id<Person> driverId = delegate.getDriverOfVehicle(event.getVehicleId());
142  String transportMode = this.transportModeProvider.getTransportMode(driverId);
143  double now = event.getTime();
144  Link link = this.scenario.getNetwork().getLinks().get(event.getLinkId());
145  Person person = this.scenario.getPopulation().getPersons().get(driverId);
146  double earliestExitTime;
147  if (this.multiModalTravelTimes != null) {
148  if (transportMode == null) {
149  throw new RuntimeException(
150  "Agent " + driverId.toString() + " is currently not performing a leg. Aborting!");
151  } else {
152  TravelTime travelTime = this.multiModalTravelTimes.get(transportMode);
153  if (travelTime == null) {
154  throw new RuntimeException(
155  "No TravelTime object was found for mode " + transportMode + ". Aborting!");
156  }
157 
158  earliestExitTime = Math.floor(now + travelTime.getLinkTravelTime(link, now, person, null));
159  }
160  } else {
161  earliestExitTime = Math.floor(now + this.freeSpeedTravelTime.getLinkTravelTime(link, now, person, null));
162  }
163  this.handleAddEarliestLinkExitTime(driverId, earliestExitTime);
164  }
165 
166  @Override
167  public void handleEvent(LinkLeaveEvent event) {
169  }
170 
171  @Override
172  public void handleEvent(PersonDepartureEvent event) {
173  this.transportModeProvider.handleEvent(event);
174  this.handleAddEarliestLinkExitTime(event.getPersonId(), event.getTime());
175  }
176 
177  @Override
178  public void handleEvent(PersonStuckEvent event) {
179  this.transportModeProvider.handleEvent(event);
181  }
182 
183  private void handleAddEarliestLinkExitTime(Id<Person> agentId, double earliestExitTime) {
184  OptionalTime optionalEarliestExitTime = OptionalTime.defined(earliestExitTime);
185  this.earliestLinkExitTimes.put(agentId, optionalEarliestExitTime);
186  //why the value set is not concurrent while the enclosing map is concurrent??
187  Set<Id<Person>> earliestLinkExitTimesAtTime = this.earliestLinkExitTimesPerTimeStep.computeIfAbsent(
188  optionalEarliestExitTime, k -> new HashSet<>());
189  earliestLinkExitTimesAtTime.add(agentId);
190  }
191 
193  OptionalTime earliestExitTime = this.earliestLinkExitTimes.remove(agentId);
194 
195  if (earliestExitTime != null) {
196  Set<Id<Person>> earliestLinkExitTimesAtTime = this.earliestLinkExitTimesPerTimeStep.get(earliestExitTime);
197  if (earliestLinkExitTimesAtTime != null) {
198  earliestLinkExitTimesAtTime.remove(agentId);
199  if (earliestLinkExitTimesAtTime.isEmpty()) {
200  this.earliestLinkExitTimesPerTimeStep.remove(earliestExitTime);
201  }
202  }
203  }
204  }
205 
206  @Override
208  delegate.handleEvent(event);
209  }
210 
211  @Override
213  delegate.handleEvent(event);
214  }
215 }
Map< Id< Person >,? extends Person > getPersons()
double getLinkTravelTime(Link link, double time, Person person, Vehicle vehicle)
void addHandler(final EventHandler handler)
static OptionalTime defined(double seconds)
Map< Id< Link >, ? extends Link > getLinks()