View Javadoc
1   package org.opentrafficsim.road.gtu.generator;
2   
3   import java.io.Serializable;
4   import java.util.LinkedList;
5   import java.util.Queue;
6   import java.util.Set;
7   
8   import javax.naming.NamingException;
9   
10  import org.djunits.unit.AccelerationUnit;
11  import org.djunits.unit.DurationUnit;
12  import org.djunits.unit.LengthUnit;
13  import org.djunits.value.vdouble.scalar.Acceleration;
14  import org.djunits.value.vdouble.scalar.Duration;
15  import org.djunits.value.vdouble.scalar.Length;
16  import org.djunits.value.vdouble.scalar.Speed;
17  import org.djunits.value.vdouble.scalar.Time;
18  import org.opentrafficsim.core.distributions.Generator;
19  import org.opentrafficsim.core.distributions.ProbabilityException;
20  import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
21  import org.opentrafficsim.core.geometry.OTSGeometryException;
22  import org.opentrafficsim.core.gtu.GTUDirectionality;
23  import org.opentrafficsim.core.gtu.GTUException;
24  import org.opentrafficsim.core.gtu.GTUType;
25  import org.opentrafficsim.core.gtu.RelativePosition;
26  import org.opentrafficsim.core.gtu.animation.GTUColorer;
27  import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterException;
28  import org.opentrafficsim.core.network.NetworkException;
29  import org.opentrafficsim.core.network.OTSNetwork;
30  import org.opentrafficsim.road.gtu.animation.DefaultCarAnimation;
31  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
32  import org.opentrafficsim.road.gtu.lane.LaneBasedGTUCharacteristics;
33  import org.opentrafficsim.road.gtu.lane.LaneBasedGTUCharacteristicsGenerator;
34  import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
35  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
36  import org.opentrafficsim.road.network.lane.Lane;
37  
38  import nl.tudelft.simulation.dsol.SimRuntimeException;
39  
40  /**
41   * Lane based GTU generator. This generator generates lane based GTUs using a LaneBasedTemplateGTUType. The template is used to
42   * generate a set of GTU characteristics at the times implied by the headway generator. These sets are queued until there is
43   * sufficient room to construct a GTU at the specified lane locations. The speed of a construction GTU may be reduced to ensure
44   * it does not run into its immediate leader GTU.
45   * <p>
46   * Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
47   * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
48   * <p>
49   * @version $Revision$, $LastChangedDate$, by $Author$, initial version Mar 8, 2016 <br>
50   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
51   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
52   */
53  public class LaneBasedGTUGenerator implements Serializable
54  {
55      /** */
56      private static final long serialVersionUID = 20160000L;
57  
58      /** FIFO for templates that have not been generated yet due to insufficient room/headway. */
59      private final Queue<LaneBasedGTUCharacteristics> unplacedTemplates = new LinkedList<>();
60  
61      /** Name of the GTU generator. */
62      private final String id;
63  
64      /** Time distribution that determines the interval times between GTUs. */
65      private final Generator<Duration> interarrivelTimeGenerator;
66  
67      /** Generates most properties of the GTUs. */
68      private final LaneBasedGTUCharacteristicsGenerator laneBasedGTUCharacteristicsGenerator;
69  
70      /** End time of this generator. */
71      private final Time endTime;
72  
73      /** Maximum number of GTUs to generate. */
74      private final long maxGTUs;
75  
76      /** Total number of GTUs generated so far. */
77      private long generatedGTUs = 0;
78  
79      /** Retry interval for checking if a GTU can be placed. */
80      Duration reTryInterval = new Duration(0.1, DurationUnit.SI);
81  
82      /** The location and initial direction of the generated GTUs. */
83      final Set<DirectedLanePosition> initialLongitudinalPositions;
84  
85      /** The way that this generator checks if it is safe to construct and place the next lane based GTU. */
86      final RoomChecker roomChecker;
87  
88      /** The GTU colorer that will be linked to each generated GTU. */
89      final GTUColorer gtuColorer;
90  
91      /**
92       * Construct a new lane base GTU generator.
93       * @param id String; name of the new GTU generator
94       * @param interarrivelTimeGenerator Generator&lt;Duration&gt;; generator for the interval times between GTUs
95       * @param maxGTUs long; maximum number of GTUs to generate
96       * @param startTime Time; time at which the first GTU will be generated
97       * @param endTime Time; time after which no more GTUs will be generated
98       * @param gtuColorer GTUColorer; the GTU colorer that will be used by all generated GTUs
99       * @param laneBasedGTUCharacteristicsGenerator LaneBasedGTUCharacteristicsGenerator; generator of the characteristics of
100      *            each GTU
101      * @param initialLongitudinalPositions SET&lt;DirectedLanePosition&gt;; the location and initial direction of all generated
102      *            GTUs
103      * @param network OTSNetwork; the OTS network that owns the generated GTUs
104      * @param roomChecker LaneBasedGTUGenerator.RoomChecker; the way that this generator checks that there is sufficient room to
105      *            place a new GTU
106      * @throws SimRuntimeException when <cite>startTime</cite> lies before the current simulation time
107      * @throws ProbabilityException pe
108      * @throws ParameterException if drawing from the interarrival generator fails
109      */
110     public LaneBasedGTUGenerator(String id, final Generator<Duration> interarrivelTimeGenerator, final long maxGTUs,
111             final Time startTime, final Time endTime, final GTUColorer gtuColorer,
112             final LaneBasedGTUCharacteristicsGenerator laneBasedGTUCharacteristicsGenerator,
113             final Set<DirectedLanePosition> initialLongitudinalPositions, final OTSNetwork network, RoomChecker roomChecker)
114             throws SimRuntimeException, ProbabilityException, ParameterException
115     {
116         this.id = id;
117         this.interarrivelTimeGenerator = interarrivelTimeGenerator;
118         this.laneBasedGTUCharacteristicsGenerator = laneBasedGTUCharacteristicsGenerator;
119         this.endTime = endTime;
120         this.maxGTUs = maxGTUs;
121         this.initialLongitudinalPositions = initialLongitudinalPositions;
122         this.roomChecker = roomChecker;
123         this.gtuColorer = gtuColorer;
124         laneBasedGTUCharacteristicsGenerator.getSimulator().scheduleEventAbs(
125                 startTime.plus(this.interarrivelTimeGenerator.draw()), this, this, "generateCharacteristics", new Object[] {});
126     }
127 
128     /**
129      * Generate the characteristics of the next GTU.
130      * @throws ProbabilityException when something is wrongly defined in the LaneBasedTemplateGTUType
131      * @throws SimRuntimeException when this method fails to re-schedule itself or the call to the method that tries to place a
132      *             GTU on the road
133      * @throws ParameterException in case of a parameter problem
134      * @throws GTUException if strategical planner cannot generate a plan
135      */
136     @SuppressWarnings("unused")
137     private void generateCharacteristics() throws ProbabilityException, SimRuntimeException, ParameterException, GTUException
138     {
139         OTSDEVSSimulatorInterface simulator = this.laneBasedGTUCharacteristicsGenerator.getSimulator();
140         if (this.generatedGTUs >= this.maxGTUs
141                 || this.laneBasedGTUCharacteristicsGenerator.getSimulator().getSimulatorTime().get().ge(this.endTime))
142         {
143             return; // Do not reschedule
144         }
145         synchronized (this.unplacedTemplates)
146         {
147             this.generatedGTUs++;
148             this.unplacedTemplates.add(this.laneBasedGTUCharacteristicsGenerator.draw());
149             if (this.unplacedTemplates.size() == 1)
150             {
151                 simulator.scheduleEventNow(this, this, "tryToPlaceGTU", new Object[] {});
152             }
153         }
154         if (this.generatedGTUs < this.maxGTUs)
155         {
156             simulator.scheduleEventRel(this.interarrivelTimeGenerator.draw(), this, this, "generateCharacteristics",
157                     new Object[] {});
158         }
159     }
160 
161     /** Last reported queue length. */
162     private int lastReportedQueueLength = 0;
163 
164     /**
165      * Check if the queue is non-empty and, if it is, try to place the GTUs in the queue on the road.
166      * @throws SimRuntimeException should never happen
167      * @throws GTUException when something wrong in the definition of the GTU
168      * @throws OTSGeometryException when something is wrong in the definition of the GTU
169      * @throws NetworkException when something is wrong with the initial location of the GTU
170      * @throws NamingException ???
171      * @throws ProbabilityException pe
172      */
173     @SuppressWarnings("unused")
174     private void tryToPlaceGTU() throws SimRuntimeException, GTUException, NamingException, NetworkException,
175             OTSGeometryException, ProbabilityException
176     {
177         // System.out.println("entered tryToPlaceGTU");
178         LaneBasedGTUCharacteristics characteristics;
179         OTSDEVSSimulatorInterface simulator = this.laneBasedGTUCharacteristicsGenerator.getSimulator();
180         synchronized (this.unplacedTemplates)
181         {
182             characteristics = this.unplacedTemplates.peek();
183         }
184         if (null == characteristics)
185         {
186             return; // Do not re-schedule this method
187         }
188         Length shortestHeadway = new Length(Double.MAX_VALUE, LengthUnit.SI);
189         Speed leaderSpeed = null;
190         // TODO ALL? we need to stop for all gtus...
191         GTUType gtuType = characteristics.getGTUType();
192         for (DirectedLanePosition dlp : this.initialLongitudinalPositions)
193         {
194             Lane lane = dlp.getLane();
195             // GOTCHA look for the first GTU with FRONT after the start position (not REAR)
196             LaneBasedGTU leader = lane.getGtuAhead(dlp.getPosition(), dlp.getGtuDirection(), RelativePosition.FRONT,
197                     simulator.getSimulatorTime().getTime());
198             // no leader on current lane, but lane may be short
199             Length headway = Length.ZERO;
200             GTUDirectionality leaderDir = dlp.getGtuDirection();
201             // TODO look beyond splitting lane
202             while (leader == null && (leaderDir.isPlus() && lane.nextLanes(gtuType).size() == 1)
203                     || (leaderDir.isMinus() && lane.prevLanes(gtuType).size() == 1) && headway.si < 300)
204             {
205                 headway = headway.plus(lane.getLength());
206                 if (leaderDir.isPlus())
207                 {
208                     leaderDir = lane.nextLanes(gtuType).values().iterator().next();
209                     lane = lane.nextLanes(gtuType).keySet().iterator().next();
210                 }
211                 else
212                 {
213                     leaderDir = lane.prevLanes(gtuType).values().iterator().next();
214                     lane = lane.prevLanes(gtuType).keySet().iterator().next();
215                 }
216                 leader = lane.getGtuAhead(Length.ZERO, leaderDir, RelativePosition.FRONT,
217                         simulator.getSimulatorTime().getTime());
218             }
219             if (null != leader)
220             {
221                 Length egoPos =
222                         dlp.getGtuDirection().isPlus() ? dlp.getPosition() : dlp.getLane().getLength().minus(dlp.getPosition());
223                 Length leaderPos = leaderDir.isPlus() ? leader.position(lane, leader.getRear())
224                         : lane.getLength().minus(leader.position(lane, leader.getRear()));
225                 headway = headway.plus(leaderPos.minus(egoPos));
226                 // What? Allow accident?
227                 // if (headway.si < 0)
228                 // {
229                 // headway = new Length(Math.abs(headway.si), headway.getUnit());
230                 // }
231                 // TODO this is a hack, what if the reference position is not the middle?
232                 headway = new Length(headway.si - characteristics.getLength().si / 2, LengthUnit.SI);
233                 if (shortestHeadway.gt(headway))
234                 {
235                     shortestHeadway = headway;
236                     leaderSpeed = leader.getSpeed();
237                 }
238             }
239         }
240         if (shortestHeadway.si > 0)
241         {
242             Speed safeSpeed = characteristics.getSpeed();
243             if (null != leaderSpeed)
244             {
245                 safeSpeed = this.roomChecker.canPlace(leaderSpeed, shortestHeadway, characteristics);
246             }
247             if (null != safeSpeed)
248             {
249                 // There is enough room; remove the template from the queue and construct the new GTU
250                 synchronized (this.unplacedTemplates)
251                 {
252                     this.unplacedTemplates.remove();
253                 }
254                 if (safeSpeed.gt(characteristics.getMaximumSpeed()))
255                 {
256                     safeSpeed = characteristics.getMaximumSpeed();
257                 }
258                 String gtuId = null == characteristics.getIdGenerator() ? null : characteristics.getIdGenerator().nextId();
259                 LaneBasedIndividualGTU gtu = new LaneBasedIndividualGTU(gtuId, characteristics.getGTUType(),
260                         characteristics.getLength(), characteristics.getWidth(), characteristics.getMaximumSpeed(), simulator,
261                         characteristics.getNetwork());
262                 gtu.setMaximumAcceleration(new Acceleration(3.0, AccelerationUnit.METER_PER_SECOND_2));
263                 gtu.setMaximumDeceleration(new Acceleration(-8.0, AccelerationUnit.METER_PER_SECOND_2));
264                 gtu.initWithAnimation(characteristics.getStrategicalPlannerFactory().create(gtu, characteristics.getRoute()),
265                         this.initialLongitudinalPositions, safeSpeed, DefaultCarAnimation.class, this.gtuColorer);
266 
267                 // System.out.println("tryToPlace: Constructed GTU on " + this.initialLongitudinalPositions);
268             }
269         }
270         int queueLength = this.unplacedTemplates.size();
271         if (queueLength != this.lastReportedQueueLength)
272         {
273             // System.out.println("Generator " + this.id + ": queue length is " + queueLength + " at time "
274             // + simulator.getSimulatorTime().get());
275             this.lastReportedQueueLength = queueLength;
276         }
277         if (queueLength > 0)
278         {
279             // System.out.println("Re-scheduling tryToPlace, queue length is " + this.unplacedTemplates.size());
280             this.laneBasedGTUCharacteristicsGenerator.getSimulator().scheduleEventRel(this.reTryInterval, this, this,
281                     "tryToPlaceGTU", new Object[] {});
282         }
283     }
284 
285     /** {@inheritDoc} */
286     public String toString()
287     {
288         return "LaneBasedGTUGenerator " + this.id + " on " + this.initialLongitudinalPositions;
289     }
290 
291     /**
292      * @return generatedGTUs.
293      */
294     public long getGeneratedGTUs()
295     {
296         return this.generatedGTUs;
297     }
298 
299     /**
300      * @param generatedGTUs set generatedGTUs.
301      */
302     public void setGeneratedGTUs(long generatedGTUs)
303     {
304         this.generatedGTUs = generatedGTUs;
305     }
306 
307     /**
308      * Retrieve the id of this LaneBasedGTUGenerator.
309      * @return String; the id of this LaneBasedGTUGenerator
310      */
311     public String getId()
312     {
313         return this.id;
314     }
315 
316     /**
317      * Retrieve the end time of this LaneBasedGTUGenerator.
318      * @return Time; the time after which this LaneBasedGTUGenerator will not generate any more GTUs
319      */
320     public Time getEndTime()
321     {
322         return this.endTime;
323     }
324 
325     /**
326      * Retrieve the maximum number of GTUs to generate.
327      * @return long; once this number of GTUS is generated, this LaneBasedGTUGenerator will stop generating any more GTUs
328      */
329     public long getMaxGTUs()
330     {
331         return this.maxGTUs;
332     }
333 
334     /**
335      * Retrieve the GTUColorer that this LaneBasedGTUGenerator assigns to all generated GTUs.
336      * @return GtuColorer; the GTUColorer that this LaneBasedGTUGenerator assigns to all generated GTUs
337      */
338     public GTUColorer getGtuColorer()
339     {
340         return this.gtuColorer;
341     }
342 
343     /**
344      * Interface for class that checks that there is sufficient room for a proposed new GTU and returns the maximum safe speed
345      * for the proposed new GTU.
346      */
347     public interface RoomChecker
348     {
349         /**
350          * Return the maximum safe speed for a new GTU with the specified characteristics. Return null if there is no safe
351          * speed. This method will never be called if the newly proposed GTU overlaps with the leader. Nor will this method be
352          * called if there is no leader.
353          * @param leaderSpeed Speed; speed of the nearest leader
354          * @param headway Length; net distance to the nearest leader (always &gt; 0)
355          * @param laneBasedGTUCharacteristics LaneBasedGTUCharacteristics; characteristics of the proposed new GTU
356          * @return Speed; maximum safe speed, or null if a GTU with the specified characteristics cannot be placed at the
357          *         current time
358          * @throws NetworkException this method may throw a NetworkException if it encounters an error in the network structure
359          */
360         public Speed canPlace(final Speed leaderSpeed, final Length headway,
361                 final LaneBasedGTUCharacteristics laneBasedGTUCharacteristics) throws NetworkException;
362     }
363 
364 }