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