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