1   package org.opentrafficsim.road.gtu.generator;
2   
3   import java.io.Serializable;
4   import java.util.ArrayList;
5   import java.util.LinkedHashSet;
6   import java.util.List;
7   import java.util.Set;
8   
9   import org.djunits.unit.DurationUnit;
10  import org.djunits.unit.LengthUnit;
11  import org.djunits.unit.SpeedUnit;
12  import org.djunits.value.vdouble.scalar.Duration;
13  import org.djunits.value.vdouble.scalar.Length;
14  import org.djunits.value.vdouble.scalar.Speed;
15  import org.djunits.value.vdouble.scalar.Time;
16  import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
17  import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
18  import org.opentrafficsim.core.gtu.GTUDirectionality;
19  import org.opentrafficsim.core.gtu.GTUException;
20  import org.opentrafficsim.core.gtu.GTUType;
21  import org.opentrafficsim.core.gtu.RelativePosition;
22  import org.opentrafficsim.core.gtu.animation.GTUColorer;
23  import org.opentrafficsim.core.network.NetworkException;
24  import org.opentrafficsim.core.network.OTSNetwork;
25  import org.opentrafficsim.core.network.route.RouteGenerator;
26  import org.opentrafficsim.core.units.distributions.ContinuousDistDoubleScalar;
27  import org.opentrafficsim.road.gtu.animation.DefaultCarAnimation;
28  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
29  import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
30  import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU.LaneBasedIndividualCarBuilder;
31  import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
32  import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayDistance;
33  import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTUSimple;
34  import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
35  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusOld;
36  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
37  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
38  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
39  import org.opentrafficsim.road.network.lane.Lane;
40  
41  import nl.tudelft.simulation.dsol.SimRuntimeException;
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  public abstract class AbstractGTUGenerator implements Serializable
59  {
60      
61      private static final long serialVersionUID = 20150202L;
62  
63      
64      private final String name;
65  
66      
67      private final GTUType gtuType;
68  
69      
70      private final Class<?> gtuClass;
71  
72      
73      private final ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> initialSpeedDist;
74  
75      
76      private final ContinuousDistDoubleScalar.Rel<Duration, DurationUnit> interarrivelTimeDist;
77  
78      
79      private long generatedGTUs = 0;
80  
81      
82      private final long maxGTUs;
83  
84      
85      private final Time startTime;
86  
87      
88      private final Time endTime;
89  
90      
91      private final Lane lane;
92  
93      
94      private final Length position;
95  
96      
97      private final GTUDirectionality direction;
98  
99      
100     private final GTUColorer gtuColorer;
101 
102     
103     private final LaneBasedStrategicalPlannerFactory<? extends LaneBasedStrategicalPlanner> strategicalPlannerFactory;
104 
105     
106     private final RouteGenerator routeGenerator;
107 
108     
109     private final OTSNetwork network;
110 
111     
112     private List<LaneBasedIndividualCarBuilder> carBuilderList = new ArrayList<>();
113 
114     
115     @SuppressWarnings("checkstyle:visibilitymodifier")
116     protected long numberGTUs = 0;
117 
118     
119 
120 
121 
122 
123 
124 
125 
126 
127 
128 
129 
130 
131 
132 
133 
134 
135 
136 
137     @SuppressWarnings("checkstyle:parameternumber")
138     public AbstractGTUGenerator(final String name, final OTSDEVSSimulatorInterface simulator, final GTUType gtuType,
139             final Class<?> gtuClass, final ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> initialSpeedDist,
140             final ContinuousDistDoubleScalar.Rel<Duration, DurationUnit> interarrivelTimeDist, final long maxGTUs,
141             final Time startTime, final Time endTime, final Lane lane, final Length position, final GTUDirectionality direction,
142             final GTUColorer gtuColorer,
143             final LaneBasedStrategicalPlannerFactory<? extends LaneBasedStrategicalPlanner> strategicalPlannerFactory,
144             final RouteGenerator routeGenerator, final OTSNetwork network) throws SimRuntimeException
145     {
146         super();
147         this.name = name;
148         this.gtuType = gtuType;
149         this.gtuClass = gtuClass;
150         this.initialSpeedDist = initialSpeedDist;
151         this.interarrivelTimeDist = interarrivelTimeDist;
152         this.maxGTUs = maxGTUs;
153         this.startTime = startTime;
154         this.endTime = endTime;
155         this.lane = lane;
156         this.position = position;
157         this.direction = direction;
158         this.gtuColorer = gtuColorer;
159         this.strategicalPlannerFactory = strategicalPlannerFactory;
160         this.routeGenerator = routeGenerator;
161         this.network = network;
162 
163         simulator.scheduleEventAbs(startTime, this, this, "generate", null);
164     }
165 
166     
167 
168 
169 
170     protected final void generate() throws Exception
171     {
172         
173         if (getSimulator().getSimulatorTime().getTime().gt(this.endTime))
174         {
175             return;
176         }
177 
178         
179         if (this.generatedGTUs >= this.maxGTUs)
180         {
181             return;
182         }
183 
184         
185         this.numberGTUs++;
186         String id = this.name + ":" + this.numberGTUs;
187 
188         
189         if (LaneBasedIndividualGTU.class.isAssignableFrom(getGtuClass()))
190         {
191             LaneBasedIndividualCarBuilder carBuilder = new LaneBasedIndividualCarBuilder();
192             carBuilder.setId(id);
193             carBuilder.setGtuType(getGtuType());
194             Length carLength = getLengthDist().draw();
195             carBuilder.setLength(carLength);
196             carBuilder.setWidth(getWidthDist().draw());
197             carBuilder.setMaximumSpeed(getMaximumSpeedDist().draw());
198             carBuilder.setInitialSpeed(getInitialSpeedDist().draw());
199             carBuilder.setSimulator(getSimulator());
200             Set<DirectedLanePosition> initialLongitudinalPositions = new LinkedHashSet<>(1);
201             initialLongitudinalPositions.add(new DirectedLanePosition(this.lane, this.position, this.direction));
202             carBuilder.setInitialLongitudinalPositions(initialLongitudinalPositions);
203             carBuilder.setAnimationClass(DefaultCarAnimation.class);
204             carBuilder.setGtuColorer(this.gtuColorer);
205             carBuilder.setNetwork(this.network);
206             this.generatedGTUs++;
207 
208             if (enoughSpace(carBuilder))
209             {
210                 carBuilder.build(this.strategicalPlannerFactory, this.routeGenerator.draw());
211             }
212             else
213             {
214                 
215                 this.carBuilderList.add(carBuilder);
216                 
217                 if (this.carBuilderList.size() == 1)
218                 {
219                     
220                     getSimulator().scheduleEventRel(new Duration(0.1, DurationUnit.SECOND), this, this, "checkCarBuilderList",
221                             null);
222                 }
223             }
224         }
225         else
226         {
227             throw new GTUException("GTU class " + getGtuClass().getName() + ": cannot instantiate, no builder.");
228         }
229 
230         
231         OTSSimTimeDouble nextTime = getSimulator().getSimulatorTime().plus(this.interarrivelTimeDist.draw());
232         if (nextTime.get().le(this.endTime))
233         {
234             getSimulator().scheduleEventAbs(nextTime, this, this, "generate", null);
235         }
236     }
237 
238     
239 
240 
241 
242 
243 
244 
245 
246     protected final boolean enoughSpace(final LaneBasedIndividualCarBuilder carBuilder) throws NetworkException, GTUException
247     {
248         DirectedLanePosition directedLanePosition = carBuilder.getInitialLongitudinalPositions().iterator().next();
249         Lane generatorLane = directedLanePosition.getLane();
250         double genPosSI = directedLanePosition.getPosition().getSI();
251         
252         
253         double lengthSI = generatorLane.getLength().getSI();
254         double frontNew = (genPosSI + carBuilder.getLength().getSI()) / lengthSI;
255         double rearNew = genPosSI / lengthSI;
256 
257         
258         for (LaneBasedGTU gtu : generatorLane.getGtuList())
259         {
260             double frontGTU = gtu.fractionalPosition(generatorLane, gtu.getFront());
261             double rearGTU = gtu.fractionalPosition(generatorLane, gtu.getRear());
262             if ((frontNew >= rearGTU && frontNew <= frontGTU) || (rearNew >= rearGTU && rearNew <= frontGTU)
263                     || (frontGTU >= rearNew && frontGTU <= frontNew) || (rearGTU >= rearNew && rearGTU <= frontNew))
264             {
265                 
266                 return false;
267             }
268         }
269 
270         
271         GTUFollowingModelOld followingModel = new IDMPlusOld();
272         
273 
274         Headway headway = headway(new Length(250.0, LengthUnit.METER), generatorLane);
275         Length minimumHeadway = new Length(0.0, LengthUnit.METER);
276         if (headway.getObjectType().isGtu())
277         {
278             minimumHeadway = followingModel.minimumHeadway(carBuilder.getInitialSpeed(), headway.getSpeed(),
279                     new Length(1.0, LengthUnit.CENTIMETER), new Length(250.0, LengthUnit.METER),
280                     generatorLane.getSpeedLimit(carBuilder.getGtuType()), carBuilder.getMaximumSpeed());
281             
282             double acc = followingModel.computeAcceleration(carBuilder.getInitialSpeed(), carBuilder.getMaximumSpeed(),
283                     headway.getSpeed(), headway.getDistance(), carBuilder.getMaximumSpeed()).getSI();
284             if (acc < 0)
285             {
286                 
287                 
288                 
289                 return false;
290             }
291         }
292 
293         
294         
295         return headway.getDistance().ge(minimumHeadway);
296     }
297 
298     
299 
300 
301 
302 
303 
304 
305 
306 
307 
308 
309 
310     private Headway headwayRecursiveForwardSI(final Lane theLane, final double lanePositionSI, final double cumDistanceSI,
311             final double maxDistanceSI, final Time when) throws GTUException
312     {
313         
314         LaneBasedGTU otherGTU = theLane.getGtuAhead(new Length(lanePositionSI, LengthUnit.METER), GTUDirectionality.DIR_PLUS,
315                 RelativePosition.REAR, when);
316         if (otherGTU != null)
317         {
318             double distanceM = cumDistanceSI + otherGTU.position(theLane, otherGTU.getRear(), when).getSI() - lanePositionSI;
319             if (distanceM > 0 && distanceM <= maxDistanceSI)
320             {
321                 return new HeadwayGTUSimple(otherGTU.getId(), otherGTU.getGTUType(), new Length(distanceM, LengthUnit.SI),
322                         otherGTU.getLength(), otherGTU.getSpeed(), null);
323             }
324             return new HeadwayDistance(Double.MAX_VALUE);
325         }
326 
327         
328         if (cumDistanceSI + theLane.getLength().getSI() - lanePositionSI < maxDistanceSI)
329         {
330             
331             if (theLane.nextLanes(this.gtuType).size() > 0)
332             {
333                 Headway foundMaxGTUDistanceSI = new HeadwayDistance(Double.MAX_VALUE);
334                 for (Lane nextLane : theLane.nextLanes(this.gtuType).keySet())
335                 {
336                     
337                     
338                     
339                     
340                     {
341                         double traveledDistanceSI = cumDistanceSI + theLane.getLength().getSI() - lanePositionSI;
342                         Headway closest = headwayRecursiveForwardSI(nextLane, 0.0, traveledDistanceSI, maxDistanceSI, when);
343                         if (closest.getDistance().si < maxDistanceSI
344                                 && closest.getDistance().si < foundMaxGTUDistanceSI.getDistance().si)
345                         {
346                             foundMaxGTUDistanceSI = closest;
347                         }
348                     }
349                 }
350                 return foundMaxGTUDistanceSI;
351             }
352         }
353 
354         
355         return new HeadwayDistance(Double.MAX_VALUE);
356     }
357 
358     
359 
360 
361 
362 
363 
364 
365 
366 
367 
368 
369 
370     private Headway headwayRecursiveBackwardSI(final Lane theLane, final double lanePositionSI, final double cumDistanceSI,
371             final double maxDistanceSI, final Time when) throws GTUException
372     {
373         
374         LaneBasedGTU otherGTU = theLane.getGtuBehind(new Length(lanePositionSI, LengthUnit.METER), GTUDirectionality.DIR_PLUS,
375                 RelativePosition.FRONT, when);
376         if (otherGTU != null)
377         {
378             double distanceM = cumDistanceSI + otherGTU.position(theLane, otherGTU.getFront(), when).getSI() - lanePositionSI;
379             if (distanceM > 0 && distanceM <= maxDistanceSI)
380             {
381                 return new HeadwayGTUSimple(otherGTU.getId(), otherGTU.getGTUType(), new Length(distanceM, LengthUnit.SI),
382                         otherGTU.getLength(), otherGTU.getSpeed(), null);
383             }
384             return new HeadwayDistance(Double.MAX_VALUE);
385         }
386 
387         
388         if (cumDistanceSI + theLane.getLength().getSI() - lanePositionSI < maxDistanceSI)
389         {
390             
391             if (theLane.prevLanes(this.gtuType).size() > 0)
392             {
393                 Headway foundMaxGTUDistanceSI = new HeadwayDistance(Double.MAX_VALUE);
394                 for (Lane prevLane : theLane.prevLanes(this.gtuType).keySet())
395                 {
396                     
397                     
398                     
399                     
400                     {
401                         double traveledDistanceSI = cumDistanceSI + theLane.getLength().getSI() - lanePositionSI;
402                         Headway closest = headwayRecursiveBackwardSI(prevLane, 0.0, traveledDistanceSI, maxDistanceSI, when);
403                         if (closest.getDistance().si < maxDistanceSI
404                                 && closest.getDistance().si < foundMaxGTUDistanceSI.getDistance().si)
405                         {
406                             foundMaxGTUDistanceSI = closest;
407                         }
408                     }
409                 }
410                 return foundMaxGTUDistanceSI;
411             }
412         }
413 
414         
415         return new HeadwayDistance(Double.MAX_VALUE);
416     }
417 
418     
419 
420 
421 
422 
423 
424 
425 
426     private Headway headwayGTUSIForward(final double maxDistanceSI, final Lane generatorLane) throws GTUException
427     {
428         Time when = getSimulator().getSimulatorTime().getTime();
429         Headway foundMaxGTUDistanceSI = new HeadwayDistance(Double.MAX_VALUE);
430         
431         Headway closest;
432         if (this.direction.equals(GTUDirectionality.DIR_PLUS))
433         {
434             closest = headwayRecursiveForwardSI(this.lane, 0.0, 0.0, maxDistanceSI, when);
435         }
436         else
437         {
438             closest = headwayRecursiveBackwardSI(this.lane, generatorLane.getLength().getSI(), 0.0, maxDistanceSI, when);
439         }
440         if (closest.getDistance().si < maxDistanceSI && closest.getDistance().si < foundMaxGTUDistanceSI.getDistance().si)
441         {
442             foundMaxGTUDistanceSI = closest;
443         }
444         return foundMaxGTUDistanceSI;
445     }
446 
447     
448 
449 
450 
451 
452 
453 
454     public final Headway headway(final Length maxDistance, final Lane generatorLane) throws GTUException
455     {
456         return headwayGTUSIForward(maxDistance.getSI(), generatorLane);
457     }
458 
459     
460 
461 
462 
463     protected final void checkCarBuilderList() throws Exception
464     {
465         if (!this.carBuilderList.isEmpty())
466         {
467             LaneBasedIndividualCarBuilder carBuilder = this.carBuilderList.get(0);
468             if (enoughSpace(carBuilder))
469             {
470                 this.carBuilderList.remove(0);
471                 carBuilder.build(this.strategicalPlannerFactory, this.routeGenerator.draw());
472             }
473         }
474 
475         
476         if (!this.carBuilderList.isEmpty())
477         {
478             getSimulator().scheduleEventRel(new Duration(0.1, DurationUnit.SECOND), this, this, "checkCarBuilderList", null);
479         }
480     }
481 
482     
483     public abstract OTSDEVSSimulatorInterface getSimulator();
484 
485     
486     public abstract ContinuousDistDoubleScalar.Rel<Length, LengthUnit> getLengthDist();
487 
488     
489     public abstract ContinuousDistDoubleScalar.Rel<Length, LengthUnit> getWidthDist();
490 
491     
492     public abstract ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> getMaximumSpeedDist();
493 
494     
495 
496 
497     public final String getName()
498     {
499         return this.name;
500     }
501 
502     
503 
504 
505     public final GTUType getGtuType()
506     {
507         return this.gtuType;
508     }
509 
510     
511 
512 
513     public final Class<?> getGtuClass()
514     {
515         return this.gtuClass;
516     }
517 
518     
519 
520 
521     public final ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> getInitialSpeedDist()
522     {
523         return this.initialSpeedDist;
524     }
525 
526     
527 
528 
529     public final ContinuousDistDoubleScalar.Rel<Duration, DurationUnit> getInterarrivelTimeDist()
530     {
531         return this.interarrivelTimeDist;
532     }
533 
534     
535 
536 
537     public final long getMaxGTUs()
538     {
539         return this.maxGTUs;
540     }
541 
542     
543 
544 
545     public final Time getStartTime()
546     {
547         return this.startTime;
548     }
549 
550     
551 
552 
553     public final Time getEndTime()
554     {
555         return this.endTime;
556     }
557 
558     
559 
560 
561     public final GTUColorer getGtuColorer()
562     {
563         return this.gtuColorer;
564     }
565 
566     
567 
568 
569     public final LaneBasedStrategicalPlannerFactory<? extends LaneBasedStrategicalPlanner> getStrategicalPlannerFactory()
570     {
571         return this.strategicalPlannerFactory;
572     }
573 
574 }