1 package org.opentrafficsim.demo;
2
3 import java.io.IOException;
4 import java.util.ArrayList;
5 import java.util.List;
6 import java.util.Map;
7 import java.util.Random;
8
9 import org.djunits.unit.DirectionUnit;
10 import org.djunits.unit.LengthUnit;
11 import org.djunits.unit.SpeedUnit;
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.Duration;
16 import org.djunits.value.vdouble.scalar.Length;
17 import org.djunits.value.vdouble.scalar.Speed;
18 import org.djutils.draw.point.Point2d;
19 import org.djutils.traceverifier.TraceVerifier;
20 import org.opentrafficsim.base.parameters.Parameters;
21 import org.opentrafficsim.core.definitions.DefaultsNl;
22 import org.opentrafficsim.core.dsol.AbstractOtsModel;
23 import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
24 import org.opentrafficsim.core.gtu.Gtu;
25 import org.opentrafficsim.core.gtu.GtuException;
26 import org.opentrafficsim.core.gtu.GtuType;
27 import org.opentrafficsim.core.network.NetworkException;
28 import org.opentrafficsim.core.network.Node;
29 import org.opentrafficsim.core.network.route.Route;
30 import org.opentrafficsim.road.definitions.DefaultsRoadNl;
31 import org.opentrafficsim.road.gtu.LaneBasedGtu;
32 import org.opentrafficsim.road.gtu.LaneBookkeeping;
33 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
34 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
35 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalRoutePlannerFactory;
36 import org.opentrafficsim.road.gtu.tactical.lmrs.Lmrs;
37 import org.opentrafficsim.road.gtu.tactical.lmrs.LmrsFactory;
38 import org.opentrafficsim.road.network.Lane;
39 import org.opentrafficsim.road.network.LanePosition;
40 import org.opentrafficsim.road.network.LaneType;
41 import org.opentrafficsim.road.network.RoadNetwork;
42 import org.opentrafficsim.road.network.factory.LaneFactory;
43 import org.opentrafficsim.road.network.speed.LaneSpeedLimits;
44
45 import nl.tudelft.simulation.dsol.SimRuntimeException;
46 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterBoolean;
47 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterDouble;
48 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterDoubleScalar;
49 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterException;
50 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterMap;
51 import nl.tudelft.simulation.jstats.streams.MersenneTwister;
52 import nl.tudelft.simulation.jstats.streams.StreamInterface;
53
54
55
56
57
58
59
60
61
62 public class CircularRoadModel extends AbstractOtsModel implements UNITS
63 {
64
65 private int carsCreated = 0;
66
67
68 private double carProbability;
69
70
71 private Length minimumDistance = new Length(0, METER);
72
73
74 private LaneSpeedLimits speedLimits = new LaneSpeedLimits(new Speed(100, SpeedUnit.KM_PER_HOUR),
75 Map.of(DefaultsNl.TRUCK, new Speed(80, SpeedUnit.KM_PER_HOUR)));
76
77
78 private List<List<Lane>> paths = new ArrayList<>();
79
80
81 private StreamInterface stream = new MersenneTwister(12345);
82
83
84 private LaneBasedStrategicalPlannerFactory<?> strategicalPlannerGeneratorCars = null;
85
86
87 private LaneBasedStrategicalPlannerFactory<?> strategicalPlannerGeneratorTrucks = null;
88
89
90 private Parameters parametersCar;
91
92
93 private Parameters parametersTruck;
94
95
96 private final RoadNetwork network;
97
98
99
100
101
102 public CircularRoadModel(final OtsSimulatorInterface simulator)
103 {
104 super(simulator);
105 this.network = new RoadNetwork("network", simulator);
106 makeInputParameterMap();
107 }
108
109
110
111
112 public void makeInputParameterMap()
113 {
114 try
115 {
116 InputParameterHelper.makeInputParameterMapCarTruck(this.inputParameterMap, 1.0);
117
118 InputParameterMap genericMap = null;
119 if (this.inputParameterMap.getValue().containsKey("generic"))
120 {
121 genericMap = (InputParameterMap) this.inputParameterMap.get("generic");
122 }
123 else
124 {
125 genericMap = new InputParameterMap("generic", "Generic", "Generic parameters", 1.0);
126 this.inputParameterMap.add(genericMap);
127 }
128
129 genericMap.add(new InputParameterDoubleScalar<LengthUnit, Length>("trackLength", "Track length",
130 "Track length (circumfence of the track)", Length.ofSI(1000.0), Length.ofSI(500.0), Length.ofSI(2000.0),
131 true, true, "%.0f", 1.5));
132 genericMap.add(new InputParameterDouble("densityMean", "Mean density (veh / km)",
133 "mean density of the vehicles (vehicles per kilometer)", 30.0, 5.0, 45.0, true, true, "%.0f", 2.0));
134 genericMap.add(new InputParameterDouble("densityVariability", "Density variability",
135 "Variability of the denisty: variability * (headway - 20) meters", 0.0, 0.0, 1.0, true, true, "%.00f",
136 3.0));
137 genericMap.add(new InputParameterBoolean("gradualLaneChange", "Gradual lane change",
138 "Gradual lane change when true; instantaneous lane change when false", true, 4.0));
139 }
140 catch (InputParameterException exception)
141 {
142 exception.printStackTrace();
143 }
144 }
145
146
147
148
149
150
151 public List<Lane> getPath(final int index)
152 {
153 return this.paths.get(index);
154 }
155
156
157
158
159
160 public List<List<Lane>> getPaths()
161 {
162 return this.paths;
163 }
164
165
166
167
168
169 public void sample(final TraceVerifier tv)
170 {
171 try
172 {
173 StringBuilder state = new StringBuilder();
174 for (Gtu gtu : this.network.getGTUs())
175 {
176 LaneBasedGtu lbg = (LaneBasedGtu) gtu;
177 state.append(String.format("%s: %130.130s ", lbg.getId(), lbg.getLocation().toString()));
178 }
179
180 tv.sample(this.simulator.getSimulatorTime().toString(), state.toString());
181 this.simulator.scheduleEventRel(Duration.ONE, () -> sample(tv));
182 }
183 catch (IOException e)
184 {
185 e.printStackTrace();
186 }
187 }
188
189 @Override
190 public void constructModel() throws SimRuntimeException
191 {
192 try
193 {
194
195
196
197
198
199 final int laneCount = 2;
200 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
201 {
202 this.paths.add(new ArrayList<Lane>());
203 }
204
205 this.carProbability = (double) getInputParameter("generic.carProbability");
206 double radius = ((Length) getInputParameter("generic.trackLength")).si / 2 / Math.PI;
207 double headway = 1000.0 / (double) getInputParameter("generic.densityMean");
208 double headwayVariability = (double) getInputParameter("generic.densityVariability");
209
210 this.parametersCar = InputParameterHelper.getParametersCar(getInputParameterMap());
211 this.parametersTruck = InputParameterHelper.getParametersTruck(getInputParameterMap());
212
213 this.strategicalPlannerGeneratorCars =
214 new LaneBasedStrategicalRoutePlannerFactory(new LmrsFactory<>(Lmrs::new).setStream(this.stream));
215 this.strategicalPlannerGeneratorTrucks =
216 new LaneBasedStrategicalRoutePlannerFactory(new LmrsFactory<>(Lmrs::new).setStream(this.stream));
217
218 GtuType gtuType = DefaultsNl.CAR;
219 LaneType laneType = DefaultsRoadNl.TWO_WAY_LANE;
220 Node start = new Node(this.network, "Start", new Point2d(radius, 0), new Direction(90, DirectionUnit.EAST_DEGREE));
221 Node halfway =
222 new Node(this.network, "Halfway", new Point2d(-radius, 0), new Direction(270, DirectionUnit.EAST_DEGREE));
223
224 Point2d[] coordsHalf1 = new Point2d[127];
225 for (int i = 0; i < coordsHalf1.length; i++)
226 {
227 double angle = Math.PI * i / (coordsHalf1.length - 1);
228 coordsHalf1[i] = new Point2d(radius * Math.cos(angle), radius * Math.sin(angle));
229 }
230 Lane[] lanes1 = LaneFactory.makeMultiLane(this.network, "FirstHalf", start, halfway, coordsHalf1, laneCount,
231 laneType, this.speedLimits, this.simulator);
232 Point2d[] coordsHalf2 = new Point2d[127];
233 for (int i = 0; i < coordsHalf2.length; i++)
234 {
235 double angle = Math.PI + Math.PI * i / (coordsHalf2.length - 1);
236 coordsHalf2[i] = new Point2d(radius * Math.cos(angle), radius * Math.sin(angle));
237 }
238 Lane[] lanes2 = LaneFactory.makeMultiLane(this.network, "SecondHalf", halfway, start, coordsHalf2, laneCount,
239 laneType, this.speedLimits, this.simulator);
240 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
241 {
242 this.paths.get(laneIndex).add(lanes1[laneIndex]);
243 this.paths.get(laneIndex).add(lanes2[laneIndex]);
244 }
245
246 double variability = (headway - 20) * headwayVariability;
247 Random random = new Random(12345);
248 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
249 {
250 double lane1Length = lanes1[laneIndex].getLength().getSI();
251 double trackLength = lane1Length + lanes2[laneIndex].getLength().getSI();
252 for (double pos = 0; pos <= trackLength - headway - variability;)
253 {
254 Lane lane = pos >= lane1Length ? lanes2[laneIndex] : lanes1[laneIndex];
255
256 double laneRelativePos = pos > lane1Length ? pos - lane1Length : pos;
257 double actualHeadway = headway + (random.nextDouble() * 2 - 1) * variability;
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
271
272
273
274
275
276
277
278
279 protected final void generateGTU(final Length initialPosition, final Lane lane, final GtuType gtuType)
280 throws GtuException, NetworkException, SimRuntimeException, InputParameterException
281 {
282
283 boolean generateTruck = this.stream.nextDouble() > this.carProbability;
284 Length vehicleLength = new Length(generateTruck ? 15 : 4, METER);
285 LaneBasedGtu gtu = new LaneBasedGtu("" + (++this.carsCreated), gtuType, vehicleLength, new Length(1.8, METER),
286 new Speed(200, KM_PER_HOUR), vehicleLength.times(0.5), this.network);
287 gtu.setParameters(generateTruck ? this.parametersTruck : this.parametersCar);
288 gtu.setNoLaneChangeDistance(Length.ZERO);
289 gtu.setBookkeeping(
290 ((boolean) getInputParameter("generic.gradualLaneChange")) ? LaneBookkeeping.START : LaneBookkeeping.INSTANT);
291 gtu.setMaximumAcceleration(Acceleration.ofSI(3.0));
292 gtu.setMaximumDeceleration(Acceleration.ofSI(-8.0));
293
294
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
307 Speed initialSpeed = new Speed(0, KM_PER_HOUR);
308 gtu.init(strategicalPlanner, new LanePosition(lane, initialPosition).getLocation(), initialSpeed);
309 }
310
311 @Override
312 public RoadNetwork getNetwork()
313 {
314 return this.network;
315 }
316
317
318
319
320
321 public final Length getMinimumDistance()
322 {
323 return this.minimumDistance;
324 }
325
326 }