1 package org.opentrafficsim.road.gtu.generator;
2
3 import java.io.Serializable;
4 import java.rmi.RemoteException;
5 import java.util.Collections;
6 import java.util.LinkedHashMap;
7 import java.util.LinkedHashSet;
8 import java.util.LinkedList;
9 import java.util.Map;
10 import java.util.Queue;
11 import java.util.Set;
12 import java.util.SortedSet;
13 import java.util.TreeSet;
14
15 import javax.media.j3d.Bounds;
16 import javax.naming.NamingException;
17
18 import org.djunits.unit.DurationUnit;
19 import org.djunits.value.vdouble.scalar.Duration;
20 import org.djunits.value.vdouble.scalar.Length;
21 import org.djunits.value.vdouble.scalar.Speed;
22 import org.djunits.value.vdouble.scalar.Time;
23 import org.opentrafficsim.base.Identifiable;
24 import org.opentrafficsim.base.TimeStampedObject;
25 import org.opentrafficsim.base.parameters.ParameterException;
26 import org.opentrafficsim.core.distributions.Generator;
27 import org.opentrafficsim.core.distributions.ProbabilityException;
28 import org.opentrafficsim.core.geometry.OTSGeometryException;
29 import org.opentrafficsim.core.gtu.GTUDirectionality;
30 import org.opentrafficsim.core.gtu.GTUException;
31 import org.opentrafficsim.core.gtu.GTUType;
32 import org.opentrafficsim.core.gtu.RelativePosition;
33 import org.opentrafficsim.core.gtu.animation.GTUColorer;
34 import org.opentrafficsim.core.idgenerator.IdGenerator;
35 import org.opentrafficsim.core.network.NetworkException;
36 import org.opentrafficsim.core.network.OTSNetwork;
37 import org.opentrafficsim.road.gtu.animation.DefaultCarAnimation;
38 import org.opentrafficsim.road.gtu.generator.GeneratorPositions.GeneratorLanePosition;
39 import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGTUCharacteristics;
40 import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGTUCharacteristicsGenerator;
41 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
42 import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
43 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTU;
44 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTUReal;
45 import org.opentrafficsim.road.network.lane.CrossSectionLink;
46 import org.opentrafficsim.road.network.lane.DirectedLanePosition;
47 import org.opentrafficsim.road.network.lane.Lane;
48 import org.opentrafficsim.road.network.lane.LaneDirection;
49
50 import nl.tudelft.simulation.dsol.SimRuntimeException;
51 import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
52 import nl.tudelft.simulation.language.Throw;
53 import nl.tudelft.simulation.language.d3.DirectedPoint;
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 public class LaneBasedGTUGenerator implements Serializable, Identifiable, GTUGenerator
69 {
70
71 private static final long serialVersionUID = 20160000L;
72
73
74 private final Map<CrossSectionLink, Map<GeneratorLanePosition, Queue<TimeStampedObject<LaneBasedGTUCharacteristics>>>> unplacedTemplates =
75 new LinkedHashMap<>();
76
77
78 private final String id;
79
80
81 private final Generator<Duration> interarrivelTimeGenerator;
82
83
84 private final LaneBasedGTUCharacteristicsGenerator laneBasedGTUCharacteristicsGenerator;
85
86
87 private long generatedGTUs = 0;
88
89
90 private Duration reTryInterval = new Duration(0.1, DurationUnit.SI);
91
92
93 private final GeneratorPositions generatorPositions;
94
95
96 private final OTSNetwork network;
97
98
99 private final DEVSSimulatorInterface.TimeDoubleUnit simulator;
100
101
102 private final RoomChecker roomChecker;
103
104
105 private final GTUColorer gtuColorer;
106
107
108 private final IdGenerator idGenerator;
109
110
111 private Length noLaneChangeDistance = null;
112
113
114 private Set<LaneDirection> disabled = new LinkedHashSet<>();
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133 public LaneBasedGTUGenerator(final String id, final Generator<Duration> interarrivelTimeGenerator,
134 final GTUColorer gtuColorer, final LaneBasedGTUCharacteristicsGenerator laneBasedGTUCharacteristicsGenerator,
135 final GeneratorPositions generatorPositions, final OTSNetwork network,
136 final DEVSSimulatorInterface.TimeDoubleUnit simulator, final RoomChecker roomChecker, final IdGenerator idGenerator)
137 throws SimRuntimeException, ProbabilityException, ParameterException
138 {
139 this.id = id;
140 this.interarrivelTimeGenerator = interarrivelTimeGenerator;
141 this.laneBasedGTUCharacteristicsGenerator = laneBasedGTUCharacteristicsGenerator;
142 this.generatorPositions = generatorPositions;
143 this.network = network;
144 this.simulator = simulator;
145 this.roomChecker = roomChecker;
146 this.gtuColorer = gtuColorer;
147 this.idGenerator = idGenerator;
148 Duration headway = this.interarrivelTimeGenerator.draw();
149 if (headway != null)
150 {
151 simulator.scheduleEventRel(headway, this, this, "generateCharacteristics", new Object[] {});
152 }
153 }
154
155
156
157
158
159 public void setNoLaneChangeDistance(final Length noLaneChangeDistance)
160 {
161 this.noLaneChangeDistance = noLaneChangeDistance;
162 }
163
164
165
166
167
168
169
170
171
172 @SuppressWarnings("unused")
173 private void generateCharacteristics() throws ProbabilityException, SimRuntimeException, ParameterException, GTUException
174 {
175 synchronized (this.unplacedTemplates)
176 {
177 this.generatedGTUs++;
178 LaneBasedGTUCharacteristics characteristics = this.laneBasedGTUCharacteristicsGenerator.draw();
179 GTUType gtuType = characteristics.getGTUType();
180
181 Map<CrossSectionLink, Map<Integer, Integer>> unplaced = new LinkedHashMap<>();
182 for (CrossSectionLink link : this.unplacedTemplates.keySet())
183 {
184 Map<Integer, Integer> linkMap = new LinkedHashMap<>();
185 Map<GeneratorLanePosition, Queue<TimeStampedObject<LaneBasedGTUCharacteristics>>> linkTemplates =
186 this.unplacedTemplates.get(link);
187 for (GeneratorLanePosition lanePosition : linkTemplates.keySet())
188 {
189 linkMap.put(lanePosition.getLaneNumber(), linkTemplates.get(lanePosition).size());
190 }
191 unplaced.put(link, linkMap);
192 }
193
194 Speed desiredSpeed = characteristics.getStrategicalPlannerFactory().peekDesiredSpeed(gtuType,
195 this.generatorPositions.speedLimit(gtuType), characteristics.getMaximumSpeed());
196 GeneratorLanePosition lanePosition =
197 this.generatorPositions.draw(gtuType, unplaced, desiredSpeed, characteristics.getRoute());
198
199 if (!this.unplacedTemplates.containsKey(lanePosition.getLink()))
200 {
201 this.unplacedTemplates.put(lanePosition.getLink(), new LinkedHashMap<>());
202 }
203 Map<GeneratorLanePosition, Queue<TimeStampedObject<LaneBasedGTUCharacteristics>>> linkMap =
204 this.unplacedTemplates.get(lanePosition.getLink());
205 if (!linkMap.containsKey(lanePosition))
206 {
207 linkMap.put(lanePosition, new LinkedList<>());
208 }
209 Queue<TimeStampedObject<LaneBasedGTUCharacteristics>> queue = linkMap.get(lanePosition);
210 queue.add(new TimeStampedObject<LaneBasedGTUCharacteristics>(characteristics, this.simulator.getSimulatorTime()));
211 if (queue.size() == 1)
212 {
213 this.simulator.scheduleEventNow(this, this, "tryToPlaceGTU", new Object[] { lanePosition });
214 }
215 }
216 Duration headway = this.interarrivelTimeGenerator.draw();
217 if (headway != null)
218 {
219 this.simulator.scheduleEventRel(headway, this, this, "generateCharacteristics", new Object[] {});
220 }
221 }
222
223
224
225
226
227
228
229
230
231
232
233 @SuppressWarnings("unused")
234 private void tryToPlaceGTU(final GeneratorLanePosition position) throws SimRuntimeException, GTUException, NamingException,
235 NetworkException, OTSGeometryException, ProbabilityException
236 {
237 TimeStampedObject<LaneBasedGTUCharacteristics> timedCharacteristics;
238 Queue<TimeStampedObject<LaneBasedGTUCharacteristics>> queue =
239 this.unplacedTemplates.get(position.getLink()).get(position);
240
241
242 Set<LaneDirection> lanes = new LinkedHashSet<>();
243 for (DirectedLanePosition pos : position.getPosition())
244 {
245 lanes.add(pos.getLaneDirection());
246 }
247 if (!Collections.disjoint(this.disabled, lanes))
248 {
249 queue.remove();
250 return;
251 }
252
253 synchronized (queue)
254 {
255 timedCharacteristics = queue.peek();
256 }
257 if (null == timedCharacteristics)
258 {
259 return;
260 }
261
262 LaneBasedGTUCharacteristics characteristics = timedCharacteristics.getObject();
263 SortedSet<HeadwayGTU> leaders = new TreeSet<>();
264 for (DirectedLanePosition dirPos : position.getPosition())
265 {
266 getFirstLeaders(dirPos.getLaneDirection(), dirPos.getPosition().neg().minus(characteristics.getFront()),
267 dirPos.getPosition(), leaders);
268 }
269 Duration since = this.simulator.getSimulatorTime().minus(timedCharacteristics.getTimestamp());
270 Placement placement = this.roomChecker.canPlace(leaders, characteristics, since, position.getPosition());
271 if (placement.canPlace())
272 {
273
274 synchronized (queue)
275 {
276 queue.remove();
277 }
278 placeGtu(characteristics, placement.getPosition(), placement.getSpeed());
279 if (queue.size() > 0)
280 {
281 this.simulator.scheduleEventNow(this, this, "tryToPlaceGTU", new Object[] { position });
282 }
283 }
284 else if (queue.size() > 0)
285 {
286 this.simulator.scheduleEventRel(this.reTryInterval, this, this, "tryToPlaceGTU", new Object[] { position });
287 }
288 }
289
290
291
292
293
294
295
296
297
298
299
300 final void placeGtu(final LaneBasedGTUCharacteristics characteristics, final Set<DirectedLanePosition> position,
301 final Speed speed) throws NamingException, GTUException, NetworkException, SimRuntimeException, OTSGeometryException
302 {
303 String gtuId = this.idGenerator.nextId();
304 LaneBasedIndividualGTU gtu = new LaneBasedIndividualGTU(gtuId, characteristics.getGTUType(),
305 characteristics.getLength(), characteristics.getWidth(), characteristics.getMaximumSpeed(),
306 characteristics.getFront(), this.simulator, this.network);
307 gtu.setMaximumAcceleration(characteristics.getMaximumAcceleration());
308 gtu.setMaximumDeceleration(characteristics.getMaximumDeceleration());
309 gtu.setVehicleModel(characteristics.getVehicleModel());
310 gtu.setNoLaneChangeDistance(this.noLaneChangeDistance);
311 gtu.initWithAnimation(
312 characteristics.getStrategicalPlannerFactory().create(gtu, characteristics.getRoute(),
313 characteristics.getOrigin(), characteristics.getDestination()),
314 position, speed, DefaultCarAnimation.class, this.gtuColorer);
315 }
316
317
318
319
320
321
322
323
324
325 private void getFirstLeaders(final LaneDirection lane, final Length startDistance, final Length beyond,
326 final Set<HeadwayGTU> set) throws GTUException
327 {
328 LaneBasedGTU next = lane.getLane().getGtuAhead(beyond, lane.getDirection(), RelativePosition.FRONT,
329 this.simulator.getSimulatorTime());
330 if (next != null)
331 {
332 Length headway;
333 if (lane.getDirection().isPlus())
334 {
335 headway = startDistance.plus(next.position(lane.getLane(), next.getRear()));
336 }
337 else
338 {
339 headway = startDistance.plus(lane.getLane().getLength().minus(next.position(lane.getLane(), next.getRear())));
340 }
341 if (headway.si < 300)
342 {
343 set.add(new HeadwayGTUReal(next, headway, true));
344 }
345 return;
346 }
347 Map<Lane, GTUDirectionality> downstreamLanes = lane.getLane().downstreamLanes(lane.getDirection(), GTUType.VEHICLE);
348 for (Lane downstreamLane : downstreamLanes.keySet())
349 {
350 Length startDistanceDownstream = startDistance.plus(lane.getLane().getLength());
351 if (startDistanceDownstream.si > 300)
352 {
353 return;
354 }
355 GTUDirectionality dir = downstreamLanes.get(downstreamLane);
356 Length beyondDownstream = dir.isPlus() ? Length.ZERO : downstreamLane.getLength();
357 getFirstLeaders(new LaneDirection(downstreamLane, dir), startDistanceDownstream, beyondDownstream, set);
358 }
359 }
360
361
362 @Override
363 public final String toString()
364 {
365 return "LaneBasedGTUGenerator " + this.id + " on " + this.generatorPositions;
366 }
367
368
369
370
371 public final long getGeneratedGTUs()
372 {
373 return this.generatedGTUs;
374 }
375
376
377
378
379 public final void setGeneratedGTUs(final long generatedGTUs)
380 {
381 this.generatedGTUs = generatedGTUs;
382 }
383
384
385
386
387
388 @Override
389 public final String getId()
390 {
391 return this.id;
392 }
393
394
395
396
397
398 public final GTUColorer getGtuColorer()
399 {
400 return this.gtuColorer;
401 }
402
403
404
405
406
407
408
409
410
411 public void disable(final Time start, final Time end, final Set<LaneDirection> laneDirections) throws SimRuntimeException
412 {
413 Throw.when(end.lt(start), SimRuntimeException.class, "End time %s is before start time %s.", end, start);
414 this.simulator.scheduleEventAbs(start, this, this, "disable", new Object[] { laneDirections });
415 this.simulator.scheduleEventAbs(end, this, this, "enable", new Object[0]);
416 }
417
418
419
420
421
422 @SuppressWarnings("unused")
423 private void disable(final Set<LaneDirection> laneDirections)
424 {
425 this.disabled = laneDirections;
426 }
427
428
429
430
431 @SuppressWarnings("unused")
432 private void enable()
433 {
434 this.disabled = new LinkedHashSet<>();
435 }
436
437
438
439
440
441 public interface RoomChecker
442 {
443
444
445
446
447
448
449
450
451
452
453
454
455
456 Placement canPlace(SortedSet<HeadwayGTU> leaders, LaneBasedGTUCharacteristics characteristics, Duration since,
457 Set<DirectedLanePosition> initialPosition) throws NetworkException, GTUException;
458 }
459
460
461
462
463
464
465
466
467
468
469
470
471
472 public static final class Placement
473 {
474
475
476 public static final Placement NO = new Placement();
477
478
479 private final Speed speed;
480
481
482 private final Set<DirectedLanePosition> position;
483
484
485
486
487 private Placement()
488 {
489 this.speed = null;
490 this.position = null;
491 }
492
493
494
495
496
497
498 public Placement(final Speed speed, final Set<DirectedLanePosition> position)
499 {
500 Throw.whenNull(speed, "Speed may not be null. Use Placement.NO if the GTU cannot be placed.");
501 Throw.whenNull(position, "Position may not be null. Use Placement.NO if the GTU cannot be placed.");
502 this.speed = speed;
503 this.position = position;
504 }
505
506
507
508
509
510 public boolean canPlace()
511 {
512 return this.speed != null && this.position != null;
513 }
514
515
516
517
518
519 public Speed getSpeed()
520 {
521 return this.speed;
522 }
523
524
525
526
527
528 public Set<DirectedLanePosition> getPosition()
529 {
530 return this.position;
531 }
532
533
534 @Override
535 public String toString()
536 {
537 return "Placement [speed=" + this.speed + ", position=" + this.position + "]";
538 }
539
540 }
541
542
543 @Override
544 public DirectedPoint getLocation() throws RemoteException
545 {
546 return this.generatorPositions.getLocation();
547 }
548
549
550 @Override
551 public Bounds getBounds() throws RemoteException
552 {
553 return this.generatorPositions.getBounds();
554 }
555
556
557
558
559
560 public Map<DirectedPoint, Integer> getQueueLengths()
561 {
562 Map<DirectedPoint, Integer> result = new LinkedHashMap<>();
563 for (CrossSectionLink link : this.unplacedTemplates.keySet())
564 {
565 for (GeneratorLanePosition lanePosition : this.unplacedTemplates.get(link).keySet())
566 {
567 result.put(lanePosition.getPosition().iterator().next().getLocation(),
568 this.unplacedTemplates.get(link).get(lanePosition).size());
569 }
570 }
571 for (GeneratorLanePosition lanePosition : this.generatorPositions.getAllPositions())
572 {
573 DirectedPoint p = lanePosition.getPosition().iterator().next().getLocation();
574 if (!result.containsKey(p))
575 {
576 result.put(p, 0);
577 }
578 }
579 return result;
580 }
581
582 }