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