View Javadoc
1   package org.opentrafficsim.demo;
2   
3   import static org.opentrafficsim.core.gtu.GTUType.CAR;
4   
5   import java.util.ArrayList;
6   import java.util.LinkedHashSet;
7   import java.util.List;
8   import java.util.Random;
9   import java.util.Set;
10  
11  import org.djunits.unit.LengthUnit;
12  import org.djunits.unit.UNITS;
13  import org.djunits.value.vdouble.scalar.Acceleration;
14  import org.djunits.value.vdouble.scalar.Length;
15  import org.djunits.value.vdouble.scalar.Speed;
16  import org.opentrafficsim.base.parameters.Parameters;
17  import org.opentrafficsim.core.dsol.AbstractOTSModel;
18  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
19  import org.opentrafficsim.core.geometry.OTSGeometryException;
20  import org.opentrafficsim.core.geometry.OTSPoint3D;
21  import org.opentrafficsim.core.gtu.GTUDirectionality;
22  import org.opentrafficsim.core.gtu.GTUException;
23  import org.opentrafficsim.core.gtu.GTUType;
24  import org.opentrafficsim.core.network.NetworkException;
25  import org.opentrafficsim.core.network.OTSNetwork;
26  import org.opentrafficsim.core.network.OTSNode;
27  import org.opentrafficsim.core.network.route.Route;
28  import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
29  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusFactory;
30  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.DefaultLMRSPerceptionFactory;
31  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LMRSFactory;
32  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
33  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
34  import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlannerFactory;
35  import org.opentrafficsim.road.network.factory.LaneFactory;
36  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
37  import org.opentrafficsim.road.network.lane.Lane;
38  import org.opentrafficsim.road.network.lane.LaneType;
39  
40  import nl.tudelft.simulation.dsol.SimRuntimeException;
41  import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterDouble;
42  import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterDoubleScalar;
43  import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterException;
44  import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterMap;
45  import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
46  import nl.tudelft.simulation.jstats.streams.MersenneTwister;
47  import nl.tudelft.simulation.jstats.streams.StreamInterface;
48  
49  /**
50   * Simulate traffic on a circular, two-lane road.
51   * <p>
52   * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
53   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
54   * <p>
55   * $LastChangedDate: 2018-11-18 20:49:04 +0100 (Sun, 18 Nov 2018) $, @version $Revision: 4743 $, by $Author: averbraeck $,
56   * initial version 1 nov. 2014 <br>
57   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
58   */
59  public class CircularRoadModel extends AbstractOTSModel implements UNITS
60  {
61      /** */
62      private static final long serialVersionUID = 20141121L;
63  
64      /** Number of cars created. */
65      private int carsCreated = 0;
66  
67      /** The probability that the next generated GTU is a passenger car. */
68      private double carProbability;
69  
70      /** Minimum distance. */
71      private Length minimumDistance = new Length(0, METER);
72  
73      /** The speed limit. */
74      private Speed speedLimit = new Speed(100, KM_PER_HOUR);
75  
76      /** The sequence of Lanes that all vehicles will follow. */
77      private List<List<Lane>> paths = new ArrayList<>();
78  
79      /** The random number generator used to decide what kind of GTU to generate etc. */
80      private StreamInterface stream = new MersenneTwister(12345);
81  
82      /** Strategical planner generator for cars. */
83      private LaneBasedStrategicalPlannerFactory<LaneBasedStrategicalPlanner> strategicalPlannerGeneratorCars = null;
84  
85      /** Strategical planner generator for trucks. */
86      private LaneBasedStrategicalPlannerFactory<LaneBasedStrategicalPlanner> strategicalPlannerGeneratorTrucks = null;
87  
88      /** Car parameters. */
89      private Parameters parametersCar;
90  
91      /** Truck parameters. */
92      private Parameters parametersTruck;
93  
94      /** The OTSNetwork. */
95      private final OTSNetwork network = new OTSNetwork("network");
96  
97      /**
98       * @param simulator OTSSimulatorInterface; the simulator for this model
99       */
100     public CircularRoadModel(final OTSSimulatorInterface simulator)
101     {
102         super(simulator);
103         makeInputParameterMap();
104     }
105 
106     /**
107      * Make a map of input parameters for this demo.
108      */
109     public void makeInputParameterMap()
110     {
111         try
112         {
113             InputParameterHelper.makeInputParameterMapCarTruck(this.inputParameterMap, 1.0);
114 
115             InputParameterMap genericMap = null;
116             if (this.inputParameterMap.getValue().containsKey("generic"))
117             {
118                 genericMap = (InputParameterMap) this.inputParameterMap.get("generic");
119             }
120             else
121             {
122                 genericMap = new InputParameterMap("generic", "Generic", "Generic parameters", 1.0);
123                 this.inputParameterMap.add(genericMap);
124             }
125 
126             genericMap.add(new InputParameterDoubleScalar<LengthUnit, Length>("trackLength", "Track length",
127                     "Track length (circumfence of the track)", Length.createSI(1000.0), Length.createSI(500.0),
128                     Length.createSI(2000.0), true, true, "%.0f", 1.5));
129             genericMap.add(new InputParameterDouble("densityMean", "Mean density (veh / km)",
130                     "mean density of the vehicles (vehicles per kilometer)", 30.0, 5.0, 45.0, true, true, "%.0f", 2.0));
131             genericMap.add(new InputParameterDouble("densityVariability", "Density variability",
132                     "Variability of the denisty: variability * (headway - 20) meters", 0.0, 0.0, 1.0, true, true, "%.00f",
133                     3.0));
134         }
135         catch (InputParameterException exception)
136         {
137             exception.printStackTrace();
138         }
139     }
140 
141     /**
142      * @param index int; the rank number of the path
143      * @return List&lt;Lane&gt;; the set of lanes for the specified index
144      */
145     public List<Lane> getPath(final int index)
146     {
147         return this.paths.get(index);
148     }
149 
150     /** {@inheritDoc} */
151     @Override
152     public void constructModel() throws SimRuntimeException
153     {
154         try
155         {
156             final int laneCount = 2;
157             for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
158             {
159                 this.paths.add(new ArrayList<Lane>());
160             }
161 
162             this.carProbability = (double) getInputParameter("generic.carProbability");
163             double radius = ((Length) getInputParameter("generic.trackLength")).si / 2 / Math.PI;
164             double headway = 1000.0 / (double) getInputParameter("generic.densityMean");
165             double headwayVariability = (double) getInputParameter("generic.densityVariability");
166 
167             this.parametersCar = InputParameterHelper.getParametersCar(getInputParameterMap());
168             this.parametersTruck = InputParameterHelper.getParametersTruck(getInputParameterMap());
169 
170             this.strategicalPlannerGeneratorCars = new LaneBasedStrategicalRoutePlannerFactory(
171                     new LMRSFactory(new IDMPlusFactory(this.stream), new DefaultLMRSPerceptionFactory()));
172             this.strategicalPlannerGeneratorTrucks = new LaneBasedStrategicalRoutePlannerFactory(
173                     new LMRSFactory(new IDMPlusFactory(this.stream), new DefaultLMRSPerceptionFactory()));
174 
175             GTUType gtuType = CAR;
176             LaneType laneType = LaneType.TWO_WAY_LANE;
177             OTSNode start = new OTSNode(this.network, "Start", new OTSPoint3D(radius, 0, 0));
178             OTSNode halfway = new OTSNode(this.network, "Halfway", new OTSPoint3D(-radius, 0, 0));
179 
180             OTSPoint3D[] coordsHalf1 = new OTSPoint3D[127];
181             for (int i = 0; i < coordsHalf1.length; i++)
182             {
183                 double angle = Math.PI * (1 + i) / (1 + coordsHalf1.length);
184                 coordsHalf1[i] = new OTSPoint3D(radius * Math.cos(angle), radius * Math.sin(angle), 0);
185             }
186             Lane[] lanes1 = LaneFactory.makeMultiLane(this.network, "FirstHalf", start, halfway, coordsHalf1, laneCount,
187                     laneType, this.speedLimit, this.simulator);
188             OTSPoint3D[] coordsHalf2 = new OTSPoint3D[127];
189             for (int i = 0; i < coordsHalf2.length; i++)
190             {
191                 double angle = Math.PI + Math.PI * (1 + i) / (1 + coordsHalf2.length);
192                 coordsHalf2[i] = new OTSPoint3D(radius * Math.cos(angle), radius * Math.sin(angle), 0);
193             }
194             Lane[] lanes2 = LaneFactory.makeMultiLane(this.network, "SecondHalf", halfway, start, coordsHalf2, laneCount,
195                     laneType, this.speedLimit, this.simulator);
196             for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
197             {
198                 this.paths.get(laneIndex).add(lanes1[laneIndex]);
199                 this.paths.get(laneIndex).add(lanes2[laneIndex]);
200             }
201             // Put the (not very evenly spaced) cars on the track
202             double variability = (headway - 20) * headwayVariability;
203             System.out.println("headway is " + headway + " variability limit is " + variability);
204             Random random = new Random(12345);
205             for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
206             {
207                 double lane1Length = lanes1[laneIndex].getLength().getSI();
208                 double trackLength = lane1Length + lanes2[laneIndex].getLength().getSI();
209                 for (double pos = 0; pos <= trackLength - headway - variability;)
210                 {
211                     Lane lane = pos >= lane1Length ? lanes2[laneIndex] : lanes1[laneIndex];
212                     // Actual headway is uniformly distributed around headway
213                     double laneRelativePos = pos > lane1Length ? pos - lane1Length : pos;
214                     double actualHeadway = headway + (random.nextDouble() * 2 - 1) * variability;
215                     // System.out.println(lane + ", len=" + lane.getLength() + ", pos=" + laneRelativePos);
216                     generateGTU(new Length(laneRelativePos, METER), lane, gtuType);
217                     pos += actualHeadway;
218                 }
219             }
220 
221         }
222         catch (Exception exception)
223         {
224             exception.printStackTrace();
225         }
226     }
227 
228     /**
229      * Generate one gtu.
230      * @param initialPosition Length; the initial position of the new cars
231      * @param lane Lane; the lane on which the new cars are placed
232      * @param gtuType GTUType; the type of the new cars
233      * @throws SimRuntimeException cannot happen
234      * @throws NetworkException on network inconsistency
235      * @throws GTUException when something goes wrong during construction of the car
236      * @throws OTSGeometryException when the initial position is outside the center line of the lane
237      */
238     protected final void generateGTU(final Length initialPosition, final Lane lane, final GTUType gtuType)
239             throws GTUException, NetworkException, SimRuntimeException, OTSGeometryException
240     {
241         // GTU itself
242         boolean generateTruck = this.stream.nextDouble() > this.carProbability;
243         Length vehicleLength = new Length(generateTruck ? 15 : 4, METER);
244         LaneBasedIndividualGTU gtu =
245                 new LaneBasedIndividualGTU("" + (++this.carsCreated), gtuType, vehicleLength, new Length(1.8, METER),
246                         new Speed(200, KM_PER_HOUR), vehicleLength.multiplyBy(0.5), this.simulator, this.network);
247         gtu.setParameters(generateTruck ? this.parametersTruck : this.parametersCar);
248         gtu.setNoLaneChangeDistance(Length.ZERO);
249         gtu.setMaximumAcceleration(Acceleration.createSI(3.0));
250         gtu.setMaximumDeceleration(Acceleration.createSI(-8.0));
251 
252         // strategical planner
253         LaneBasedStrategicalPlanner strategicalPlanner;
254         Route route = null;
255         if (!generateTruck)
256         {
257             strategicalPlanner = this.strategicalPlannerGeneratorCars.create(gtu, route, null, null);
258         }
259         else
260         {
261             strategicalPlanner = this.strategicalPlannerGeneratorTrucks.create(gtu, route, null, null);
262         }
263 
264         // init
265         Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
266         initialPositions.add(new DirectedLanePosition(lane, initialPosition, GTUDirectionality.DIR_PLUS));
267         Speed initialSpeed = new Speed(0, KM_PER_HOUR);
268         gtu.init(strategicalPlanner, initialPositions, initialSpeed);
269     }
270 
271     /** {@inheritDoc} */
272     @Override
273     public OTSNetwork getNetwork()
274     {
275         return this.network;
276     }
277 
278     /**
279      * @return minimumDistance
280      */
281     public final Length getMinimumDistance()
282     {
283         return this.minimumDistance;
284     }
285 
286     /**
287      * Stop simulation and throw an Error.
288      * @param theSimulator DEVSSimulatorInterface.TimeDoubleUnit; the simulator
289      * @param errorMessage String; the error message
290      */
291     public void stopSimulator(final DEVSSimulatorInterface.TimeDoubleUnit theSimulator, final String errorMessage)
292     {
293         System.out.println("Error: " + errorMessage);
294         try
295         {
296             if (theSimulator.isRunning())
297             {
298                 theSimulator.stop();
299             }
300         }
301         catch (SimRuntimeException exception)
302         {
303             exception.printStackTrace();
304         }
305         throw new Error(errorMessage);
306     }
307 
308 }