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