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.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, one-lane road.
52   * <p>
53   * Copyright (c) 2013-2020 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 CircularLaneModel 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<Lane> path = new ArrayList<>();
79  
80      /** The left Lane that contains simulated Cars. */
81      private Lane lane1;
82  
83      /** The right Lane that contains simulated Cars. */
84      private Lane lane2;
85  
86      /** The random number generator used to decide what kind of GTU to generate etc. */
87      private StreamInterface stream = new MersenneTwister(12345);
88  
89      /** Strategical planner generator for cars. */
90      private LaneBasedStrategicalPlannerFactory<LaneBasedStrategicalPlanner> strategicalPlannerGeneratorCars = null;
91  
92      /** Strategical planner generator for trucks. */
93      private LaneBasedStrategicalPlannerFactory<LaneBasedStrategicalPlanner> strategicalPlannerGeneratorTrucks = null;
94  
95      /** Car parameters. */
96      private Parameters parametersCar;
97  
98      /** Truck parameters. */
99      private Parameters parametersTruck;
100 
101     /** The OTSRoadNetwork. */
102     private final OTSRoadNetwork network;
103 
104     /**
105      * @param simulator OTSSimulatorInterface; the simulator for this model
106      */
107     public CircularLaneModel(final OTSSimulatorInterface simulator)
108     {
109         super(simulator);
110         this.network = new OTSRoadNetwork("network", true, simulator);
111         makeInputParameterMap();
112     }
113 
114     /**
115      * Make a map of input parameters for this demo.
116      */
117     public void makeInputParameterMap()
118     {
119         try
120         {
121             InputParameterHelper.makeInputParameterMapCarTruck(this.inputParameterMap, 4.0);
122             InputParameterMap genericMap = (InputParameterMap) this.inputParameterMap.get("generic");
123 
124             genericMap.add(new InputParameterDoubleScalar<LengthUnit, Length>("trackLength", "Track length",
125                     "Track length (circumfence of the track)", Length.instantiateSI(1000.0), Length.instantiateSI(500.0),
126                     Length.instantiateSI(2000.0), true, true, "%.0f", 1.0));
127             genericMap.add(new InputParameterDouble("densityMean", "Mean density (veh / km)",
128                     "mean density of the vehicles (vehicles per kilometer)", 30.0, 5.0, 45.0, true, true, "%.0f", 2.0));
129             genericMap.add(new InputParameterDouble("densityVariability", "Density variability",
130                     "Variability of the denisty: variability * (headway - 20) meters", 0.0, 0.0, 1.0, true, true, "%.00f",
131                     3.0));
132         }
133         catch (InputParameterException exception)
134         {
135             exception.printStackTrace();
136         }
137     }
138 
139     /** {@inheritDoc} */
140     @Override
141     public void constructModel() throws SimRuntimeException
142     {
143         try
144         {
145             this.carProbability = (double) getInputParameter("generic.carProbability");
146             double radius = ((Length) getInputParameter("generic.trackLength")).si / 2 / Math.PI;
147             double headway = 1000.0 / (double) getInputParameter("generic.densityMean");
148             double headwayVariability = (double) getInputParameter("generic.densityVariability");
149 
150             this.parametersCar = InputParameterHelper.getParametersCar(getInputParameterMap());
151             this.parametersTruck = InputParameterHelper.getParametersTruck(getInputParameterMap());
152 
153             this.strategicalPlannerGeneratorCars = new LaneBasedStrategicalRoutePlannerFactory(
154                     new LMRSFactory(new IDMPlusFactory(this.stream), new DefaultLMRSPerceptionFactory()));
155             this.strategicalPlannerGeneratorTrucks = new LaneBasedStrategicalRoutePlannerFactory(
156                     new LMRSFactory(new IDMPlusFactory(this.stream), new DefaultLMRSPerceptionFactory()));
157 
158             LaneType laneType = this.network.getLaneType(LaneType.DEFAULTS.TWO_WAY_LANE);
159             OTSRoadNode start = new OTSRoadNode(this.network, "Start", new OTSPoint3D(radius, 0, 0),
160                     new Direction(90, DirectionUnit.EAST_DEGREE));
161             OTSRoadNode halfway = new OTSRoadNode(this.network, "Halfway", new OTSPoint3D(-radius, 0, 0),
162                     new Direction(270, DirectionUnit.EAST_DEGREE));
163 
164             OTSPoint3D[] coordsHalf1 = new OTSPoint3D[127];
165             for (int i = 0; i < coordsHalf1.length; i++)
166             {
167                 double angle = Math.PI * (1 + i) / (1 + coordsHalf1.length);
168                 coordsHalf1[i] = new OTSPoint3D(radius * Math.cos(angle), radius * Math.sin(angle), 0);
169             }
170             this.lane1 = LaneFactory.makeMultiLane(this.network, "Lane1", start, halfway, coordsHalf1, 1, laneType,
171                     this.speedLimit, this.simulator)[0];
172             this.path.add(this.lane1);
173 
174             OTSPoint3D[] coordsHalf2 = new OTSPoint3D[127];
175             for (int i = 0; i < coordsHalf2.length; i++)
176             {
177                 double angle = Math.PI + Math.PI * (1 + i) / (1 + coordsHalf2.length);
178                 coordsHalf2[i] = new OTSPoint3D(radius * Math.cos(angle), radius * Math.sin(angle), 0);
179             }
180             this.lane2 = LaneFactory.makeMultiLane(this.network, "Lane2", halfway, start, coordsHalf2, 1, laneType,
181                     this.speedLimit, this.simulator)[0];
182             this.path.add(this.lane2);
183 
184             // Put the (not very evenly spaced) cars on track1
185             double trackLength = this.lane1.getLength().getSI();
186             double variability = (headway - 20) * headwayVariability;
187             System.out.println("headway is " + headway + " variability limit is " + variability);
188             Random random = new Random(12345);
189             for (double pos = 0; pos <= trackLength - headway - variability;)
190             {
191                 // Actual headway is uniformly distributed around headway
192                 double actualHeadway = headway + (random.nextDouble() * 2 - 1) * variability;
193                 generateCar(this.lane1, new Length(pos, METER));
194                 pos += actualHeadway;
195             }
196             // Put the (not very evenly spaced) cars on track2
197             trackLength = this.lane2.getLength().getSI();
198             variability = (headway - 20) * headwayVariability;
199             System.out.println("headway is " + headway + " variability limit is " + variability);
200             random = new Random(54321);
201             for (double pos = 0; pos <= trackLength - headway - variability;)
202             {
203                 // Actual headway is uniformly distributed around headway
204                 double actualHeadway = headway + (random.nextDouble() * 2 - 1) * variability;
205                 generateCar(this.lane2, new Length(pos, METER));
206                 pos += actualHeadway;
207             }
208 
209         }
210         catch (Exception exception)
211         {
212             exception.printStackTrace();
213         }
214     }
215 
216     /**
217      * Generate one gtu.
218      * @param initialPosition Length; the initial position of the new cars
219      * @param lane Lane; the lane on which the new cars are placed
220      * @throws GTUException when something goes wrong during construction of the car
221      */
222     protected final void generateCar(final Lane lane, final Length initialPosition) throws GTUException
223     {
224         // GTU itself
225         boolean generateTruck = this.stream.nextDouble() > this.carProbability;
226         Length vehicleLength = new Length(generateTruck ? 15 : 4, METER);
227         LaneBasedIndividualGTU gtu = new LaneBasedIndividualGTU("" + (++this.carsCreated),
228                 this.network.getGtuType(GTUType.DEFAULTS.CAR), vehicleLength, new Length(1.8, METER),
229                 new Speed(200, KM_PER_HOUR), vehicleLength.times(0.5), this.simulator, this.network);
230         gtu.setParameters(generateTruck ? this.parametersTruck : this.parametersCar);
231         gtu.setNoLaneChangeDistance(Length.ZERO);
232         gtu.setMaximumAcceleration(Acceleration.instantiateSI(3.0));
233         gtu.setMaximumDeceleration(Acceleration.instantiateSI(-8.0));
234 
235         // strategical planner
236         LaneBasedStrategicalPlanner strategicalPlanner;
237         Route route = null;
238         if (!generateTruck)
239         {
240             strategicalPlanner = this.strategicalPlannerGeneratorCars.create(gtu, route, null, null);
241         }
242         else
243         {
244             strategicalPlanner = this.strategicalPlannerGeneratorTrucks.create(gtu, route, null, null);
245         }
246 
247         // init
248         Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
249         initialPositions.add(new DirectedLanePosition(lane, initialPosition, GTUDirectionality.DIR_PLUS));
250         Speed initialSpeed = new Speed(0, KM_PER_HOUR);
251         try
252         {
253             gtu.init(strategicalPlanner, initialPositions, initialSpeed);
254         }
255         catch (NetworkException | SimRuntimeException | OTSGeometryException exception)
256         {
257             throw new GTUException(exception);
258         }
259     }
260 
261     /**
262      * @return List&lt;Lane&gt;; the set of lanes for the specified index
263      */
264     public List<Lane> getPath()
265     {
266         return new ArrayList<>(this.path);
267     }
268 
269     /** {@inheritDoc} */
270     @Override
271     public OTSRoadNetwork getNetwork()
272     {
273         return this.network;
274     }
275 
276     /**
277      * @return minimumDistance
278      */
279     public final Length getMinimumDistance()
280     {
281         return this.minimumDistance;
282     }
283 
284     /**
285      * Stop simulation and throw an Error.
286      * @param theSimulator DEVSSimulatorInterface.TimeDoubleUnit; the simulator
287      * @param errorMessage String; the error message
288      */
289     public void stopSimulator(final DEVSSimulatorInterface.TimeDoubleUnit theSimulator, final String errorMessage)
290     {
291         System.out.println("Error: " + errorMessage);
292         try
293         {
294             if (theSimulator.isStartingOrRunning())
295             {
296                 theSimulator.stop();
297             }
298         }
299         catch (SimRuntimeException exception)
300         {
301             exception.printStackTrace();
302         }
303         throw new Error(errorMessage);
304     }
305 
306     /** {@inheritDoc} */
307     @Override
308     public Serializable getSourceId()
309     {
310         return "CircularLaneModel";
311     }
312 
313 }