View Javadoc
1   package org.opentrafficsim.web.test;
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.djutils.draw.point.Point2d;
17  import org.opentrafficsim.base.parameters.Parameters;
18  import org.opentrafficsim.core.definitions.DefaultsNl;
19  import org.opentrafficsim.core.dsol.AbstractOtsModel;
20  import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
21  import org.opentrafficsim.core.geometry.OtsGeometryException;
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.Node;
26  import org.opentrafficsim.core.network.route.Route;
27  import org.opentrafficsim.road.definitions.DefaultsRoadNl;
28  import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
29  import org.opentrafficsim.road.gtu.lane.tactical.following.IdmPlusFactory;
30  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.DefaultLmrsPerceptionFactory;
31  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LmrsFactory;
32  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
33  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
34  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalRoutePlannerFactory;
35  import org.opentrafficsim.road.network.RoadNetwork;
36  import org.opentrafficsim.road.network.factory.LaneFactory;
37  import org.opentrafficsim.road.network.lane.Lane;
38  import org.opentrafficsim.road.network.lane.LanePosition;
39  import org.opentrafficsim.road.network.lane.LaneType;
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.jstats.streams.MersenneTwister;
47  import nl.tudelft.simulation.jstats.streams.StreamInterface;
48  
49  /**
50   * Simulate traffic on a circular, two-lane road.
51   * <p>
52   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
53   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
54   * </p>
55   * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
56   */
57  public class CircularRoadModel 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<List<Lane>> paths = new ArrayList<>();
76  
77      /** The random number generator used to decide what kind of GTU to generate etc. */
78      private StreamInterface stream = new MersenneTwister(12345);
79  
80      /** Strategical planner generator for cars. */
81      private LaneBasedStrategicalPlannerFactory<?> strategicalPlannerGeneratorCars = null;
82  
83      /** Strategical planner generator for trucks. */
84      private LaneBasedStrategicalPlannerFactory<?> strategicalPlannerGeneratorTrucks = null;
85  
86      /** Car parameters. */
87      private Parameters parametersCar;
88  
89      /** Truck parameters. */
90      private Parameters parametersTruck;
91  
92      /** The RoadNetwork. */
93      private final RoadNetwork network;
94  
95      /**
96       * @param simulator OtsSimulatorInterface; the simulator for this model
97       */
98      public CircularRoadModel(final OtsSimulatorInterface simulator)
99      {
100         super(simulator);
101         this.network = new RoadNetwork("network", simulator);
102         makeInputParameterMap();
103     }
104 
105     /**
106      * Make a map of input parameters for this demo.
107      */
108     public void makeInputParameterMap()
109     {
110         try
111         {
112             InputParameterHelper.makeInputParameterMapCarTruck(this.inputParameterMap, 1.0);
113 
114             InputParameterMap genericMap = null;
115             if (this.inputParameterMap.getValue().containsKey("generic"))
116             {
117                 genericMap = (InputParameterMap) this.inputParameterMap.get("generic");
118             }
119             else
120             {
121                 genericMap = new InputParameterMap("generic", "Generic", "Generic parameters", 1.0);
122                 this.inputParameterMap.add(genericMap);
123             }
124 
125             genericMap.add(new InputParameterDoubleScalar<LengthUnit, Length>("trackLength", "Track length",
126                     "Track length (circumfence of the track)", Length.instantiateSI(1000.0), Length.instantiateSI(500.0),
127                     Length.instantiateSI(2000.0), true, true, "%.0f", 1.5));
128             genericMap.add(new InputParameterDouble("densityMean", "Mean density (veh / km)",
129                     "mean density of the vehicles (vehicles per kilometer)", 30.0, 5.0, 45.0, true, true, "%.0f", 2.0));
130             genericMap.add(new InputParameterDouble("densityVariability", "Density variability",
131                     "Variability of the denisty: variability * (headway - 20) meters", 0.0, 0.0, 1.0, true, true, "%.00f",
132                     3.0));
133         }
134         catch (InputParameterException exception)
135         {
136             exception.printStackTrace();
137         }
138     }
139 
140     /**
141      * @param index int; the rank number of the path
142      * @return List&lt;Lane&gt;; the set of lanes for the specified index
143      */
144     public List<Lane> getPath(final int index)
145     {
146         return this.paths.get(index);
147     }
148 
149     /** {@inheritDoc} */
150     @Override
151     public void constructModel() throws SimRuntimeException
152     {
153         System.out.println("MODEL CONSTRUCTED");
154         try
155         {
156             final int laneCount = 2;
157             for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
158             {
159                 this.paths.add(new ArrayList<Lane>());
160             }
161 
162             this.carProbability = (double) getInputParameter("generic.carProbability");
163             double radius = ((Length) getInputParameter("generic.trackLength")).si / 2 / Math.PI;
164             double headway = 1000.0 / (double) getInputParameter("generic.densityMean");
165             double headwayVariability = (double) getInputParameter("generic.densityVariability");
166 
167             this.parametersCar = InputParameterHelper.getParametersCar(getInputParameterMap());
168             this.parametersTruck = InputParameterHelper.getParametersTruck(getInputParameterMap());
169 
170             this.strategicalPlannerGeneratorCars = new LaneBasedStrategicalRoutePlannerFactory(
171                     new LmrsFactory(new IdmPlusFactory(this.stream), new DefaultLmrsPerceptionFactory()));
172             this.strategicalPlannerGeneratorTrucks = new LaneBasedStrategicalRoutePlannerFactory(
173                     new LmrsFactory(new IdmPlusFactory(this.stream), new DefaultLmrsPerceptionFactory()));
174 
175             GtuType gtuType = DefaultsNl.CAR;
176             LaneType laneType = DefaultsRoadNl.TWO_WAY_LANE;
177             Node start = new Node(this.network, "Start", new Point2d(radius, 0), new Direction(90, DirectionUnit.EAST_DEGREE));
178             Node halfway =
179                     new Node(this.network, "Halfway", new Point2d(-radius, 0), new Direction(-90, DirectionUnit.EAST_DEGREE));
180 
181             Point2d[] coordsHalf1 = new Point2d[127];
182             for (int i = 0; i < coordsHalf1.length; i++)
183             {
184                 double angle = Math.PI * (1 + i) / (1 + coordsHalf1.length);
185                 coordsHalf1[i] = new Point2d(radius * Math.cos(angle), radius * Math.sin(angle));
186             }
187             Lane[] lanes1 = LaneFactory.makeMultiLane(this.network, "FirstHalf", start, halfway, coordsHalf1, laneCount,
188                     laneType, this.speedLimit, this.simulator, DefaultsNl.VEHICLE);
189             Point2d[] coordsHalf2 = new Point2d[127];
190             for (int i = 0; i < coordsHalf2.length; i++)
191             {
192                 double angle = Math.PI + Math.PI * (1 + i) / (1 + coordsHalf2.length);
193                 coordsHalf2[i] = new Point2d(radius * Math.cos(angle), radius * Math.sin(angle));
194             }
195             Lane[] lanes2 = LaneFactory.makeMultiLane(this.network, "SecondHalf", halfway, start, coordsHalf2, laneCount,
196                     laneType, this.speedLimit, this.simulator, DefaultsNl.VEHICLE);
197             for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
198             {
199                 this.paths.get(laneIndex).add(lanes1[laneIndex]);
200                 this.paths.get(laneIndex).add(lanes2[laneIndex]);
201             }
202             // Put the (not very evenly spaced) cars on the track
203             double variability = (headway - 20) * headwayVariability;
204             System.out.println("headway is " + headway + " variability limit is " + variability);
205             Random random = new Random(12345);
206             for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
207             {
208                 double lane1Length = lanes1[laneIndex].getLength().getSI();
209                 double trackLength = lane1Length + lanes2[laneIndex].getLength().getSI();
210                 for (double pos = 0; pos <= trackLength - headway - variability;)
211                 {
212                     Lane lane = pos >= lane1Length ? lanes2[laneIndex] : lanes1[laneIndex];
213                     // Actual headway is uniformly distributed around headway
214                     double laneRelativePos = pos > lane1Length ? pos - lane1Length : pos;
215                     double actualHeadway = headway + (random.nextDouble() * 2 - 1) * variability;
216                     // System.out.println(lane + ", len=" + lane.getLength() + ", pos=" + laneRelativePos);
217                     generateGTU(new Length(laneRelativePos, METER), lane, gtuType);
218                     pos += actualHeadway;
219                 }
220             }
221         }
222         catch (Exception exception)
223         {
224             exception.printStackTrace();
225         }
226     }
227 
228     /**
229      * Generate one gtu.
230      * @param initialPosition Length; the initial position of the new cars
231      * @param lane Lane; the lane on which the new cars are placed
232      * @param gtuType GtuType; the type of the new cars
233      * @throws SimRuntimeException cannot happen
234      * @throws NetworkException on network inconsistency
235      * @throws GtuException when something goes wrong during construction of the car
236      * @throws OtsGeometryException when the initial position is outside the center line of the lane
237      */
238     protected final void generateGTU(final Length initialPosition, final Lane lane, final GtuType gtuType)
239             throws GtuException, NetworkException, SimRuntimeException, OtsGeometryException
240     {
241         // GTU itself
242         boolean generateTruck = this.stream.nextDouble() > this.carProbability;
243         Length vehicleLength = new Length(generateTruck ? 15 : 4, METER);
244         LaneBasedGtu gtu = new LaneBasedGtu("" + (++this.carsCreated), gtuType, vehicleLength, new Length(1.8, METER),
245                 new Speed(200, KM_PER_HOUR), vehicleLength.times(0.5), this.network);
246         gtu.setParameters(generateTruck ? this.parametersTruck : this.parametersCar);
247         gtu.setNoLaneChangeDistance(Length.ZERO);
248         gtu.setMaximumAcceleration(Acceleration.instantiateSI(3.0));
249         gtu.setMaximumDeceleration(Acceleration.instantiateSI(-8.0));
250 
251         // strategical planner
252         LaneBasedStrategicalPlanner strategicalPlanner;
253         Route route = null;
254         if (!generateTruck)
255         {
256             strategicalPlanner = this.strategicalPlannerGeneratorCars.create(gtu, route, null, null);
257         }
258         else
259         {
260             strategicalPlanner = this.strategicalPlannerGeneratorTrucks.create(gtu, route, null, null);
261         }
262 
263         // init
264         Speed initialSpeed = new Speed(0, KM_PER_HOUR);
265         gtu.init(strategicalPlanner, new LanePosition(lane, initialPosition), initialSpeed);
266     }
267 
268     /** {@inheritDoc} */
269     @Override
270     public RoadNetwork getNetwork()
271     {
272         return this.network;
273     }
274 
275     /**
276      * @return minimumDistance
277      */
278     public final Length getMinimumDistance()
279     {
280         return this.minimumDistance;
281     }
282 
283     /**
284      * Stop simulation and throw an Error.
285      * @param theSimulator OtsSimulatorInterface; the simulator
286      * @param errorMessage String; the error message
287      */
288     public void stopSimulator(final OtsSimulatorInterface theSimulator, final String errorMessage)
289     {
290         System.out.println("Error: " + errorMessage);
291         try
292         {
293             if (theSimulator.isStartingOrRunning())
294             {
295                 theSimulator.stop();
296             }
297         }
298         catch (SimRuntimeException exception)
299         {
300             exception.printStackTrace();
301         }
302         throw new Error(errorMessage);
303     }
304 
305 }