1 package org.opentrafficsim.road.gtu.generator;
2
3 import java.util.LinkedHashSet;
4 import java.util.PriorityQueue;
5 import java.util.Queue;
6 import java.util.Set;
7
8 import javax.naming.NamingException;
9
10 import org.djunits.value.vdouble.scalar.Speed;
11 import org.djunits.value.vdouble.scalar.Time;
12 import org.opentrafficsim.base.parameters.ParameterException;
13 import org.opentrafficsim.core.distributions.ProbabilityException;
14 import org.opentrafficsim.core.geometry.OTSGeometryException;
15 import org.opentrafficsim.core.gtu.GTUException;
16 import org.opentrafficsim.core.network.NetworkException;
17 import org.opentrafficsim.core.network.Node;
18 import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGTUCharacteristicsGenerator;
19 import org.opentrafficsim.road.gtu.generator.od.GTUCharacteristicsGeneratorOD;
20 import org.opentrafficsim.road.gtu.strategical.od.Category;
21 import org.opentrafficsim.road.network.lane.DirectedLanePosition;
22 import org.opentrafficsim.road.network.lane.LaneDirection;
23
24 import nl.tudelft.simulation.dsol.SimRuntimeException;
25 import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
26 import nl.tudelft.simulation.jstats.streams.StreamInterface;
27 import nl.tudelft.simulation.language.Throw;
28
29 /**
30 * Connects with a lane-based GTU generator to disable it over some time and generate a platoon instead. Platoons are added as:
31 * {@code new Platoons(...).addPlatoon(...).addGtu(...).addGtu(...).addPlatoon(...).addGtu(...).addGtu(...).start();}. Method
32 * {@code addGtu(...)} may only determine a generation time if other info is set by {@code fixInfo(...)}.<br>
33 * <br>
34 * This class bay be used with a {@code LaneBasedGTUCharacteristicsGenerator} or {@code GTUCharacteristicsGeneratorOD}. In the
35 * former case the origin and destination nodes as well as the OD category can be {@code null}.
36 * <p>
37 * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
38 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
39 * <p>
40 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 14 sep. 2018 <br>
41 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
42 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
43 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
44 */
45 public class Platoons
46 {
47
48 /** GTU generator to disable. */
49 private final LaneBasedGTUGenerator generator;
50
51 /** Characteristics generator. */
52 private final LaneBasedGTUCharacteristicsGenerator characteristics;
53
54 /** Characteristics generator OD based. */
55 private final GTUCharacteristicsGeneratorOD characteristicsOD;
56
57 /** Simulator. */
58 private final DEVSSimulatorInterface.TimeDoubleUnit simulator;
59
60 /** Random number stream. */
61 private final StreamInterface stream;
62
63 /** Position to generate the GTU's at. */
64 private final Set<DirectedLanePosition> position;
65
66 /** Queue of GTU information to generate GTU's with. */
67 private final Queue<PlatoonGtu> queue = new PriorityQueue<>();
68
69 /** Start time of current platoon. */
70 private Time startTime;
71
72 /** End time of current platoon. */
73 private Time endTime;
74
75 /** Origin to use on added GTU. */
76 private Node fixedOrigin;
77
78 /** Destination to use on added GTU. */
79 private Node fixedDestination;
80
81 /** Category to use on added GTU. */
82 private Category fixedCategory;
83
84 /** Speed to use on added GTU. */
85 private Speed fixedSpeed;
86
87 /** Whether the Platoons was started, after which nothing may be added. */
88 private boolean started = false;
89
90 /**
91 * Constructor.
92 * @param generator LaneBasedGTUGenerator; GTU generator
93 * @param characteristics LaneBasedGTUCharacteristicsGenerator; characteristics generator
94 * @param simulator DEVSSimulatorInterface.TimeDoubleUnit; simulator
95 * @param position Set<DirectedLanePosition>; position
96 */
97 public Platoons(final LaneBasedGTUGenerator generator, final LaneBasedGTUCharacteristicsGenerator characteristics,
98 final DEVSSimulatorInterface.TimeDoubleUnit simulator, final Set<DirectedLanePosition> position)
99 {
100 this.generator = generator;
101 this.characteristics = characteristics;
102 this.characteristicsOD = null;
103 this.simulator = simulator;
104 this.stream = null;
105 this.position = position;
106 }
107
108 /**
109 * Constructor.
110 * @param generator LaneBasedGTUGenerator; GTU generator
111 * @param characteristics GTUCharacteristicsGeneratorOD; characteristics generator
112 * @param simulator DEVSSimulatorInterface.TimeDoubleUnit; simulator
113 * @param stream StreamInterface; random number stream
114 * @param position Set<DirectedLanePosition>; position
115 */
116 public Platoons(final LaneBasedGTUGenerator generator, final GTUCharacteristicsGeneratorOD characteristics,
117 final DEVSSimulatorInterface.TimeDoubleUnit simulator, final StreamInterface stream, final Set<DirectedLanePosition> position)
118 {
119 this.generator = generator;
120 this.characteristics = null;
121 this.characteristicsOD = characteristics;
122 this.simulator = simulator;
123 this.stream = stream;
124 this.position = position;
125 }
126
127 /**
128 * Add a platoon. The generator is disabled during the provided time frame. Individual GTU's should be added using
129 * {@code addGtu}.
130 * @param start Time; start time
131 * @param end Time; end time
132 * @return Platoons; for method chaining
133 * @throws SimRuntimeException on exception
134 */
135 public Platoons addPlatoon(final Time start, final Time end) throws SimRuntimeException
136 {
137 Throw.when(this.started, IllegalStateException.class, "Cannot add a platoon after the Platoons was started.");
138 Throw.whenNull(start, "Start may not be null.");
139 Throw.whenNull(end, "End may not be null.");
140 Set<LaneDirection> laneDirections = new LinkedHashSet<>();
141 for (DirectedLanePosition pos : this.position)
142 {
143 laneDirections.add(pos.getLaneDirection());
144 }
145 this.generator.disable(start, end, laneDirections);
146 this.startTime = start;
147 this.endTime = end;
148 return this;
149 }
150
151 /**
152 * Fix all info except time for GTU's added hereafter.
153 * @param origin Node; origin
154 * @param destination Node; destination
155 * @param category Category; category
156 * @param speed Speed; generation speed
157 * @return Platoons; for method chaining
158 */
159 public Platoons fixInfo(final Node origin, final Node destination, final Category category, final Speed speed)
160 {
161 this.fixedOrigin = origin;
162 this.fixedDestination = destination;
163 this.fixedCategory = category;
164 this.fixedSpeed = speed;
165 return this;
166 }
167
168 /**
169 * Add GTU to the current platoon. Per platoon, GTU may be given in any order. This method uses info set with
170 * {@code fixInfo}.
171 * @param time Time; time of generation
172 * @return Platoons; for method chaining
173 * @throws IllegalStateException if no fixed info was set using {@code fixInfo}
174 */
175 public Platoons addGtu(final Time time)
176 {
177 Throw.when(
178 this.fixedOrigin == null || this.fixedDestination == null || this.fixedCategory == null
179 || this.fixedSpeed == null,
180 IllegalStateException.class, "When using addGtu(Time), used fixInfo(...) before to set other info.");
181 return addGtu(time, this.fixedOrigin, this.fixedDestination, this.fixedCategory, this.fixedSpeed);
182 }
183
184 /**
185 * Add GTU to the current platoon. Per platoon, GTU may be given in any order.
186 * @param time Time; time of generation
187 * @param origin Node; origin
188 * @param destination Node; destination
189 * @param category Category; category
190 * @param speed Speed; generation speed
191 * @return Platoons; for method chaining
192 * @throws IllegalStateException if no platoon was started or time is outside of the platoon time range
193 */
194 public Platoons addGtu(final Time time, final Node origin, final Node destination, final Category category,
195 final Speed speed)
196 {
197 Throw.when(this.started, IllegalStateException.class, "Cannot add a GTU after the Platoons was started.");
198 Throw.when(this.startTime == null || this.endTime == null, IllegalStateException.class,
199 "First call addPlatoon() before calling addGtu()");
200 Throw.when(time.gt(this.endTime) || time.lt(this.startTime), IllegalArgumentException.class,
201 "Time %s is not between %s and %s", time, this.startTime, this.endTime);
202 this.queue.add(new PlatoonGtu(time, origin, destination, category, speed));
203 return this;
204 }
205
206 /**
207 * Starts the events.
208 * @throws SimRuntimeException if start of first platoon is in the past
209 */
210 public void start() throws SimRuntimeException
211 {
212 this.started = true;
213 if (!this.queue.isEmpty())
214 {
215 this.simulator.scheduleEventAbs(this.queue.peek().getTime(), this, this, "placeGtu",
216 new Object[] { this.queue.poll() });
217 }
218 }
219
220 /**
221 * Places the next platoon GTU and schedules the next one.
222 * @param platoonGtu PlatoonGtu; info of GTU to generate
223 * @throws SimRuntimeException on exception
224 * @throws NamingException on exception
225 * @throws GTUException on exception
226 * @throws NetworkException on exception
227 * @throws OTSGeometryException on exception
228 * @throws ParameterException on exception
229 * @throws ProbabilityException on exception
230 */
231 @SuppressWarnings("unused") // scheduled
232 private void placeGtu(final PlatoonGtu platoonGtu) throws SimRuntimeException, NamingException, GTUException,
233 NetworkException, OTSGeometryException, ProbabilityException, ParameterException
234 {
235 if (this.characteristicsOD == null)
236 {
237 this.generator.placeGtu(this.characteristics.draw(), this.position, platoonGtu.getSpeed());
238 }
239 else
240 {
241 this.generator.placeGtu(this.characteristicsOD.draw(platoonGtu.getOrigin(), platoonGtu.getDestination(),
242 platoonGtu.getCategory(), this.stream), this.position, platoonGtu.getSpeed());
243 }
244 start(); // next GTU
245 }
246
247 /**
248 * Class containing info of a GTU to generate.
249 * <p>
250 * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
251 * <br>
252 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
253 * <p>
254 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 14 sep. 2018 <br>
255 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
256 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
257 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
258 */
259 private class PlatoonGtu implements Comparable<PlatoonGtu>
260 {
261
262 /** Time to generate. */
263 private final Time time;
264
265 /** Origin. */
266 private final Node origin;
267
268 /** Destination. */
269 private final Node destination;
270
271 /** Category. */
272 private final Category category;
273
274 /** Generation speed. */
275 private final Speed speed;
276
277 /**
278 * Constructor.
279 * @param time Time; time to generate
280 * @param origin Node; origin
281 * @param destination Node; destination
282 * @param category Category; category
283 * @param speed Speed; generation speed
284 */
285 PlatoonGtu(final Time time, final Node origin, final Node destination, final Category category, final Speed speed)
286 {
287 this.time = time;
288 this.origin = origin;
289 this.destination = destination;
290 this.category = category;
291 this.speed = speed;
292 }
293
294 /** {@inheritDoc} */
295 @Override
296 public int compareTo(final PlatoonGtu o)
297 {
298 if (o == null)
299 {
300 return 1;
301 }
302 return this.time.compareTo(o.time);
303 }
304
305 /**
306 * @return time.
307 */
308 protected Time getTime()
309 {
310 return this.time;
311 }
312
313 /**
314 * @return origin.
315 */
316 protected Node getOrigin()
317 {
318 return this.origin;
319 }
320
321 /**
322 * @return destination.
323 */
324 protected Node getDestination()
325 {
326 return this.destination;
327 }
328
329 /**
330 * @return category.
331 */
332 protected Category getCategory()
333 {
334 return this.category;
335 }
336
337 /**
338 * @return speed.
339 */
340 protected Speed getSpeed()
341 {
342 return this.speed;
343 }
344
345 }
346 }