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