View Javadoc
1   package org.opentrafficsim.road.gtu.generator;
2   
3   import java.util.LinkedHashSet;
4   import java.util.PriorityQueue;
5   import java.util.Queue;
6   import java.util.Set;
7   
8   import javax.naming.NamingException;
9   
10  import org.djunits.value.vdouble.scalar.Speed;
11  import org.djunits.value.vdouble.scalar.Time;
12  import org.opentrafficsim.base.parameters.ParameterException;
13  import org.opentrafficsim.core.distributions.ProbabilityException;
14  import org.opentrafficsim.core.geometry.OTSGeometryException;
15  import org.opentrafficsim.core.gtu.GTUException;
16  import org.opentrafficsim.core.network.NetworkException;
17  import org.opentrafficsim.core.network.Node;
18  import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGTUCharacteristicsGenerator;
19  import org.opentrafficsim.road.gtu.generator.od.GTUCharacteristicsGeneratorOD;
20  import org.opentrafficsim.road.gtu.strategical.od.Category;
21  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
22  import org.opentrafficsim.road.network.lane.LaneDirection;
23  
24  import nl.tudelft.simulation.dsol.SimRuntimeException;
25  import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
26  import nl.tudelft.simulation.jstats.streams.StreamInterface;
27  import nl.tudelft.simulation.language.Throw;
28  
29  /**
30   * Connects with a lane-based GTU generator to disable it over some time and generate a platoon instead. Platoons are added as:
31   * {@code new Platoons(...).addPlatoon(...).addGtu(...).addGtu(...).addPlatoon(...).addGtu(...).addGtu(...).start();}. Method
32   * {@code addGtu(...)} may only determine a generation time if other info is set by {@code fixInfo(...)}.<br>
33   * <br>
34   * This class bay be used with a {@code LaneBasedGTUCharacteristicsGenerator} or {@code GTUCharacteristicsGeneratorOD}. In the 
35   * former case the origin and destination nodes as well as the OD category can be {@code null}.
36   * <p>
37   * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
38   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
39   * <p>
40   * @version $Revision$, $LastChangedDate$, by $Author$, initial version 14 sep. 2018 <br>
41   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
42   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
43   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
44   */
45  public class Platoons
46  {
47  
48      /** GTU generator to disable. */
49      private final LaneBasedGTUGenerator generator;
50  
51      /** Characteristics generator. */
52      private final LaneBasedGTUCharacteristicsGenerator characteristics;
53  
54      /** Characteristics generator OD based. */
55      private final GTUCharacteristicsGeneratorOD characteristicsOD;
56  
57      /** Simulator. */
58      private final DEVSSimulatorInterface.TimeDoubleUnit simulator;
59  
60      /** Random number stream. */
61      private final StreamInterface stream;
62  
63      /** Position to generate the GTU's at. */
64      private final Set<DirectedLanePosition> position;
65  
66      /** Queue of GTU information to generate GTU's with. */
67      private final Queue<PlatoonGtu> queue = new PriorityQueue<>();
68  
69      /** Start time of current platoon. */
70      private Time startTime;
71  
72      /** End time of current platoon. */
73      private Time endTime;
74  
75      /** Origin to use on added GTU. */
76      private Node fixedOrigin;
77  
78      /** Destination to use on added GTU. */
79      private Node fixedDestination;
80  
81      /** Category to use on added GTU. */
82      private Category fixedCategory;
83  
84      /** Speed to use on added GTU. */
85      private Speed fixedSpeed;
86  
87      /** Whether the Platoons was started, after which nothing may be added. */
88      private boolean started = false;
89  
90      /**
91       * Constructor.
92       * @param generator LaneBasedGTUGenerator; GTU generator
93       * @param characteristics LaneBasedGTUCharacteristicsGenerator; characteristics generator
94       * @param simulator DEVSSimulatorInterface.TimeDoubleUnit; simulator
95       * @param position Set&lt;DirectedLanePosition&gt;; position
96       */
97      public Platoons(final LaneBasedGTUGenerator generator, final LaneBasedGTUCharacteristicsGenerator characteristics,
98              final DEVSSimulatorInterface.TimeDoubleUnit simulator, final Set<DirectedLanePosition> position)
99      {
100         this.generator = generator;
101         this.characteristics = characteristics;
102         this.characteristicsOD = null;
103         this.simulator = simulator;
104         this.stream = null;
105         this.position = position;
106     }
107 
108     /**
109      * Constructor.
110      * @param generator LaneBasedGTUGenerator; GTU generator
111      * @param characteristics GTUCharacteristicsGeneratorOD; characteristics generator
112      * @param simulator DEVSSimulatorInterface.TimeDoubleUnit; simulator
113      * @param stream StreamInterface; random number stream
114      * @param position Set&lt;DirectedLanePosition&gt;; position
115      */
116     public Platoons(final LaneBasedGTUGenerator generator, final GTUCharacteristicsGeneratorOD characteristics,
117             final DEVSSimulatorInterface.TimeDoubleUnit simulator, final StreamInterface stream, final Set<DirectedLanePosition> position)
118     {
119         this.generator = generator;
120         this.characteristics = null;
121         this.characteristicsOD = characteristics;
122         this.simulator = simulator;
123         this.stream = stream;
124         this.position = position;
125     }
126 
127     /**
128      * Add a platoon. The generator is disabled during the provided time frame. Individual GTU's should be added using
129      * {@code addGtu}.
130      * @param start Time; start time
131      * @param end Time; end time
132      * @return Platoons; for method chaining
133      * @throws SimRuntimeException on exception
134      */
135     public Platoons addPlatoon(final Time start, final Time end) throws SimRuntimeException
136     {
137         Throw.when(this.started, IllegalStateException.class, "Cannot add a platoon after the Platoons was started.");
138         Throw.whenNull(start, "Start may not be null.");
139         Throw.whenNull(end, "End may not be null.");
140         Set<LaneDirection> laneDirections = new LinkedHashSet<>();
141         for (DirectedLanePosition pos : this.position)
142         {
143             laneDirections.add(pos.getLaneDirection());
144         }
145         this.generator.disable(start, end, laneDirections);
146         this.startTime = start;
147         this.endTime = end;
148         return this;
149     }
150 
151     /**
152      * Fix all info except time for GTU's added hereafter.
153      * @param origin Node; origin
154      * @param destination Node; destination
155      * @param category Category; category
156      * @param speed Speed; generation speed
157      * @return Platoons; for method chaining
158      */
159     public Platoons fixInfo(final Node origin, final Node destination, final Category category, final Speed speed)
160     {
161         this.fixedOrigin = origin;
162         this.fixedDestination = destination;
163         this.fixedCategory = category;
164         this.fixedSpeed = speed;
165         return this;
166     }
167 
168     /**
169      * Add GTU to the current platoon. Per platoon, GTU may be given in any order. This method uses info set with
170      * {@code fixInfo}.
171      * @param time Time; time of generation
172      * @return Platoons; for method chaining
173      * @throws IllegalStateException if no fixed info was set using {@code fixInfo}
174      */
175     public Platoons addGtu(final Time time)
176     {
177         Throw.when(
178                 this.fixedOrigin == null || this.fixedDestination == null || this.fixedCategory == null
179                         || this.fixedSpeed == null,
180                 IllegalStateException.class, "When using addGtu(Time), used fixInfo(...) before to set other info.");
181         return addGtu(time, this.fixedOrigin, this.fixedDestination, this.fixedCategory, this.fixedSpeed);
182     }
183 
184     /**
185      * Add GTU to the current platoon. Per platoon, GTU may be given in any order.
186      * @param time Time; time of generation
187      * @param origin Node; origin
188      * @param destination Node; destination
189      * @param category Category; category
190      * @param speed Speed; generation speed
191      * @return Platoons; for method chaining
192      * @throws IllegalStateException if no platoon was started or time is outside of the platoon time range
193      */
194     public Platoons addGtu(final Time time, final Node origin, final Node destination, final Category category,
195             final Speed speed)
196     {
197         Throw.when(this.started, IllegalStateException.class, "Cannot add a GTU after the Platoons was started.");
198         Throw.when(this.startTime == null || this.endTime == null, IllegalStateException.class,
199                 "First call addPlatoon() before calling addGtu()");
200         Throw.when(time.gt(this.endTime) || time.lt(this.startTime), IllegalArgumentException.class,
201                 "Time %s is not between %s and %s", time, this.startTime, this.endTime);
202         this.queue.add(new PlatoonGtu(time, origin, destination, category, speed));
203         return this;
204     }
205 
206     /**
207      * Starts the events.
208      * @throws SimRuntimeException if start of first platoon is in the past
209      */
210     public void start() throws SimRuntimeException
211     {
212         this.started = true;
213         if (!this.queue.isEmpty())
214         {
215             this.simulator.scheduleEventAbs(this.queue.peek().getTime(), this, this, "placeGtu",
216                     new Object[] { this.queue.poll() });
217         }
218     }
219 
220     /**
221      * Places the next platoon GTU and schedules the next one.
222      * @param platoonGtu PlatoonGtu; info of GTU to generate
223      * @throws SimRuntimeException on exception
224      * @throws NamingException on exception
225      * @throws GTUException on exception
226      * @throws NetworkException on exception
227      * @throws OTSGeometryException on exception
228      * @throws ParameterException on exception
229      * @throws ProbabilityException on exception
230      */
231     @SuppressWarnings("unused") // scheduled
232     private void placeGtu(final PlatoonGtu platoonGtu) throws SimRuntimeException, NamingException, GTUException,
233             NetworkException, OTSGeometryException, ProbabilityException, ParameterException
234     {
235         if (this.characteristicsOD == null)
236         {
237             this.generator.placeGtu(this.characteristics.draw(), this.position, platoonGtu.getSpeed());
238         }
239         else
240         {
241             this.generator.placeGtu(this.characteristicsOD.draw(platoonGtu.getOrigin(), platoonGtu.getDestination(),
242                     platoonGtu.getCategory(), this.stream), this.position, platoonGtu.getSpeed());
243         }
244         start(); // next GTU
245     }
246 
247     /**
248      * Class containing info of a GTU to generate.
249      * <p>
250      * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
251      * <br>
252      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
253      * <p>
254      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 14 sep. 2018 <br>
255      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
256      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
257      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
258      */
259     private class PlatoonGtu implements Comparable<PlatoonGtu>
260     {
261 
262         /** Time to generate. */
263         private final Time time;
264 
265         /** Origin. */
266         private final Node origin;
267 
268         /** Destination. */
269         private final Node destination;
270 
271         /** Category. */
272         private final Category category;
273 
274         /** Generation speed. */
275         private final Speed speed;
276 
277         /**
278          * Constructor.
279          * @param time Time; time to generate
280          * @param origin Node; origin
281          * @param destination Node; destination
282          * @param category Category; category
283          * @param speed Speed; generation speed
284          */
285         PlatoonGtu(final Time time, final Node origin, final Node destination, final Category category, final Speed speed)
286         {
287             this.time = time;
288             this.origin = origin;
289             this.destination = destination;
290             this.category = category;
291             this.speed = speed;
292         }
293 
294         /** {@inheritDoc} */
295         @Override
296         public int compareTo(final PlatoonGtu o)
297         {
298             if (o == null)
299             {
300                 return 1;
301             }
302             return this.time.compareTo(o.time);
303         }
304 
305         /**
306          * @return time.
307          */
308         protected Time getTime()
309         {
310             return this.time;
311         }
312 
313         /**
314          * @return origin.
315          */
316         protected Node getOrigin()
317         {
318             return this.origin;
319         }
320 
321         /**
322          * @return destination.
323          */
324         protected Node getDestination()
325         {
326             return this.destination;
327         }
328 
329         /**
330          * @return category.
331          */
332         protected Category getCategory()
333         {
334             return this.category;
335         }
336 
337         /**
338          * @return speed.
339          */
340         protected Speed getSpeed()
341         {
342             return this.speed;
343         }
344 
345     }
346 }