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, final DEVSSimulatorInterface.TimeDoubleUnit simulator,
136 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,
211 this.simulator.getSimulatorTime()));
212 if (queue.size() == 1)
213 {
214 this.simulator.scheduleEventNow(this, this, "tryToPlaceGTU", new Object[] { lanePosition });
215 }
216 }
217 Duration headway = this.interarrivelTimeGenerator.draw();
218 if (headway != null)
219 {
220 this.simulator.scheduleEventRel(headway, this, this, "generateCharacteristics", new Object[] {});
221 }
222 }
223
224
225
226
227
228
229
230
231
232
233
234 @SuppressWarnings("unused")
235 private void tryToPlaceGTU(final GeneratorLanePosition position) throws SimRuntimeException, GTUException, NamingException,
236 NetworkException, OTSGeometryException, ProbabilityException
237 {
238 TimeStampedObject<LaneBasedGTUCharacteristics> timedCharacteristics;
239 Queue<TimeStampedObject<LaneBasedGTUCharacteristics>> queue =
240 this.unplacedTemplates.get(position.getLink()).get(position);
241
242
243 Set<LaneDirection> lanes = new LinkedHashSet<>();
244 for (DirectedLanePosition pos : position.getPosition())
245 {
246 lanes.add(pos.getLaneDirection());
247 }
248 if (!Collections.disjoint(this.disabled, lanes))
249 {
250 queue.remove();
251 return;
252 }
253
254 synchronized (queue)
255 {
256 timedCharacteristics = queue.peek();
257 }
258 if (null == timedCharacteristics)
259 {
260 return;
261 }
262
263 LaneBasedGTUCharacteristics characteristics = timedCharacteristics.getObject();
264 SortedSet<HeadwayGTU> leaders = new TreeSet<>();
265 for (DirectedLanePosition dirPos : position.getPosition())
266 {
267
268 getFirstLeaders(dirPos.getLaneDirection(),
269 dirPos.getPosition().neg().minus(characteristics.getLength().divideBy(2.0)), dirPos.getPosition(), leaders);
270 }
271 Duration since = this.simulator.getSimulatorTime().minus(timedCharacteristics.getTimestamp());
272 Placement placement = this.roomChecker.canPlace(leaders, characteristics, since, position.getPosition());
273 if (placement.canPlace())
274 {
275
276 synchronized (queue)
277 {
278 queue.remove();
279 }
280 placeGtu(characteristics, placement.getPosition(), placement.getSpeed());
281 if (queue.size() > 0)
282 {
283 this.simulator.scheduleEventNow(this, this, "tryToPlaceGTU", new Object[] { position });
284 }
285 }
286 else if (queue.size() > 0)
287 {
288 this.simulator.scheduleEventRel(this.reTryInterval, this, this, "tryToPlaceGTU", new Object[] { position });
289 }
290 }
291
292
293
294
295
296
297
298
299
300
301
302 final void placeGtu(final LaneBasedGTUCharacteristics characteristics, final Set<DirectedLanePosition> position,
303 final Speed speed) throws NamingException, GTUException, NetworkException, SimRuntimeException, OTSGeometryException
304 {
305 String gtuId = this.idGenerator.nextId();
306 LaneBasedIndividualGTU gtu = new LaneBasedIndividualGTU(gtuId, characteristics.getGTUType(),
307 characteristics.getLength(), characteristics.getWidth(), characteristics.getMaximumSpeed(),
308 characteristics.getFront(), this.simulator, this.network);
309 gtu.setMaximumAcceleration(characteristics.getMaximumAcceleration());
310 gtu.setMaximumDeceleration(characteristics.getMaximumDeceleration());
311 gtu.setVehicleModel(characteristics.getVehicleModel());
312 gtu.setNoLaneChangeDistance(this.noLaneChangeDistance);
313 gtu.initWithAnimation(
314 characteristics.getStrategicalPlannerFactory().create(gtu, characteristics.getRoute(),
315 characteristics.getOrigin(), characteristics.getDestination()),
316 position, speed, DefaultCarAnimation.class, this.gtuColorer);
317 }
318
319
320
321
322
323
324
325
326
327 private void getFirstLeaders(final LaneDirection lane, final Length startDistance, final Length beyond,
328 final Set<HeadwayGTU> set) throws GTUException
329 {
330 LaneBasedGTU next = lane.getLane().getGtuAhead(beyond, lane.getDirection(), RelativePosition.FRONT,
331 this.simulator.getSimulatorTime());
332 if (next != null)
333 {
334 Length headway;
335 if (lane.getDirection().isPlus())
336 {
337 headway = startDistance.plus(next.position(lane.getLane(), next.getRear()));
338 }
339 else
340 {
341 headway = startDistance.plus(lane.getLane().getLength().minus(next.position(lane.getLane(), next.getRear())));
342 }
343 if (headway.si < 300)
344 {
345 set.add(new HeadwayGTUReal(next, headway, true));
346 }
347 return;
348 }
349 Map<Lane, GTUDirectionality> downstreamLanes = lane.getLane().downstreamLanes(lane.getDirection(), GTUType.VEHICLE);
350 for (Lane downstreamLane : downstreamLanes.keySet())
351 {
352 Length startDistanceDownstream = startDistance.plus(lane.getLane().getLength());
353 if (startDistanceDownstream.si > 300)
354 {
355 return;
356 }
357 GTUDirectionality dir = downstreamLanes.get(downstreamLane);
358 Length beyondDownstream = dir.isPlus() ? Length.ZERO : downstreamLane.getLength();
359 getFirstLeaders(new LaneDirection(downstreamLane, dir), startDistanceDownstream, beyondDownstream, set);
360 }
361 }
362
363
364 @Override
365 public final String toString()
366 {
367 return "LaneBasedGTUGenerator " + this.id + " on " + this.generatorPositions;
368 }
369
370
371
372
373 public final long getGeneratedGTUs()
374 {
375 return this.generatedGTUs;
376 }
377
378
379
380
381 public final void setGeneratedGTUs(final long generatedGTUs)
382 {
383 this.generatedGTUs = generatedGTUs;
384 }
385
386
387
388
389
390 @Override
391 public final String getId()
392 {
393 return this.id;
394 }
395
396
397
398
399
400 public final GTUColorer getGtuColorer()
401 {
402 return this.gtuColorer;
403 }
404
405
406
407
408
409
410
411
412
413 public void disable(final Time start, final Time end, final Set<LaneDirection> laneDirections) throws SimRuntimeException
414 {
415 Throw.when(end.lt(start), SimRuntimeException.class, "End time %s is before start time %s.", end, start);
416 this.simulator.scheduleEventAbs(start, this, this, "disable", new Object[] { laneDirections });
417 this.simulator.scheduleEventAbs(end, this, this, "enable", new Object[0]);
418 }
419
420
421
422
423
424 @SuppressWarnings("unused")
425 private void disable(final Set<LaneDirection> laneDirections)
426 {
427 this.disabled = laneDirections;
428 }
429
430
431
432
433 @SuppressWarnings("unused")
434 private void enable()
435 {
436 this.disabled = new LinkedHashSet<>();
437 }
438
439
440
441
442
443 public interface RoomChecker
444 {
445
446
447
448
449
450
451
452
453
454
455
456
457
458 Placement canPlace(SortedSet<HeadwayGTU> leaders, LaneBasedGTUCharacteristics characteristics, Duration since,
459 Set<DirectedLanePosition> initialPosition) throws NetworkException, GTUException;
460 }
461
462
463
464
465
466
467
468
469
470
471
472
473
474 public static final class Placement
475 {
476
477
478 public static final Placement NO = new Placement();
479
480
481 private final Speed speed;
482
483
484 private final Set<DirectedLanePosition> position;
485
486
487
488
489 private Placement()
490 {
491 this.speed = null;
492 this.position = null;
493 }
494
495
496
497
498
499
500 public Placement(final Speed speed, final Set<DirectedLanePosition> position)
501 {
502 Throw.whenNull(speed, "Speed may not be null. Use Placement.NO if the GTU cannot be placed.");
503 Throw.whenNull(position, "Position may not be null. Use Placement.NO if the GTU cannot be placed.");
504 this.speed = speed;
505 this.position = position;
506 }
507
508
509
510
511
512 public boolean canPlace()
513 {
514 return this.speed != null && this.position != null;
515 }
516
517
518
519
520
521 public Speed getSpeed()
522 {
523 return this.speed;
524 }
525
526
527
528
529
530 public Set<DirectedLanePosition> getPosition()
531 {
532 return this.position;
533 }
534
535
536 @Override
537 public String toString()
538 {
539 return "Placement [speed=" + this.speed + ", position=" + this.position + "]";
540 }
541
542 }
543
544
545 @Override
546 public DirectedPoint getLocation() throws RemoteException
547 {
548 return this.generatorPositions.getLocation();
549 }
550
551
552 @Override
553 public Bounds getBounds() throws RemoteException
554 {
555 return this.generatorPositions.getBounds();
556 }
557
558
559
560
561
562 public Map<DirectedPoint, Integer> getQueueLengths()
563 {
564 Map<DirectedPoint, Integer> result = new LinkedHashMap<>();
565 for (CrossSectionLink link : this.unplacedTemplates.keySet())
566 {
567 for (GeneratorLanePosition lanePosition : this.unplacedTemplates.get(link).keySet())
568 {
569 result.put(lanePosition.getPosition().iterator().next().getLocation(),
570 this.unplacedTemplates.get(link).get(lanePosition).size());
571 }
572 }
573 for (GeneratorLanePosition lanePosition : this.generatorPositions.getAllPositions())
574 {
575 DirectedPoint p = lanePosition.getPosition().iterator().next().getLocation();
576 if (!result.containsKey(p))
577 {
578 result.put(p, 0);
579 }
580 }
581 return result;
582 }
583
584 }