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