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 }