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