1 package org.opentrafficsim.web.test;
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(120, 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 void sample(final TraceVerifier tv)
161 {
162 try
163 {
164 StringBuilder state = new StringBuilder();
165 for (Gtu gtu : this.network.getGTUs())
166 {
167 LaneBasedGtu lbg = (LaneBasedGtu) gtu;
168 state.append(String.format("%s: %130.130s ", lbg.getId(), lbg.getLocation().toString()));
169 }
170
171 tv.sample(this.simulator.getSimulatorTime().toString(), state.toString());
172 this.simulator.scheduleEventRel(Duration.ONE, () -> sample(tv));
173 }
174 catch (IOException e)
175 {
176 e.printStackTrace();
177 }
178 }
179
180 @Override
181 public void constructModel() throws SimRuntimeException
182 {
183 try
184 {
185
186
187
188
189
190 final int laneCount = 2;
191 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
192 {
193 this.paths.add(new ArrayList<Lane>());
194 }
195
196 this.carProbability = (double) getInputParameter("generic.carProbability");
197 double radius = ((Length) getInputParameter("generic.trackLength")).si / 2 / Math.PI;
198 double headway = 1000.0 / (double) getInputParameter("generic.densityMean");
199 double headwayVariability = (double) getInputParameter("generic.densityVariability");
200
201 this.parametersCar = InputParameterHelper.getParametersCar(getInputParameterMap());
202 this.parametersTruck = InputParameterHelper.getParametersTruck(getInputParameterMap());
203
204 this.strategicalPlannerGeneratorCars =
205 new LaneBasedStrategicalRoutePlannerFactory(new LmrsFactory<>(Lmrs::new).setStream(this.stream));
206 this.strategicalPlannerGeneratorTrucks =
207 new LaneBasedStrategicalRoutePlannerFactory(new LmrsFactory<>(Lmrs::new).setStream(this.stream));
208
209 GtuType gtuType = DefaultsNl.CAR;
210 LaneType laneType = DefaultsRoadNl.TWO_WAY_LANE;
211 Node start = new Node(this.network, "Start", new Point2d(radius, 0), new Direction(90, DirectionUnit.EAST_DEGREE));
212 Node halfway =
213 new Node(this.network, "Halfway", new Point2d(-radius, 0), new Direction(270, DirectionUnit.EAST_DEGREE));
214
215 Point2d[] coordsHalf1 = new Point2d[127];
216 for (int i = 0; i < coordsHalf1.length; i++)
217 {
218 double angle = Math.PI * i / (coordsHalf1.length - 1);
219 coordsHalf1[i] = new Point2d(radius * Math.cos(angle), radius * Math.sin(angle));
220 }
221 Lane[] lanes1 = LaneFactory.makeMultiLane(this.network, "FirstHalf", start, halfway, coordsHalf1, laneCount,
222 laneType, this.speedLimits, this.simulator);
223 Point2d[] coordsHalf2 = new Point2d[127];
224 for (int i = 0; i < coordsHalf2.length; i++)
225 {
226 double angle = Math.PI + Math.PI * i / (coordsHalf2.length - 1);
227 coordsHalf2[i] = new Point2d(radius * Math.cos(angle), radius * Math.sin(angle));
228 }
229 Lane[] lanes2 = LaneFactory.makeMultiLane(this.network, "SecondHalf", halfway, start, coordsHalf2, laneCount,
230 laneType, this.speedLimits, this.simulator);
231 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
232 {
233 this.paths.get(laneIndex).add(lanes1[laneIndex]);
234 this.paths.get(laneIndex).add(lanes2[laneIndex]);
235 }
236
237 double variability = (headway - 20) * headwayVariability;
238 System.out.println("headway is " + headway + " variability limit is " + variability);
239 Random random = new Random(12345);
240 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
241 {
242 double lane1Length = lanes1[laneIndex].getLength().getSI();
243 double trackLength = lane1Length + lanes2[laneIndex].getLength().getSI();
244 for (double pos = 0; pos <= trackLength - headway - variability;)
245 {
246 Lane lane = pos >= lane1Length ? lanes2[laneIndex] : lanes1[laneIndex];
247
248 double laneRelativePos = pos > lane1Length ? pos - lane1Length : pos;
249 double actualHeadway = headway + (random.nextDouble() * 2 - 1) * variability;
250
251 generateGTU(new Length(laneRelativePos, METER), lane, gtuType);
252 pos += actualHeadway;
253 }
254 }
255 }
256 catch (Exception exception)
257 {
258 exception.printStackTrace();
259 }
260 }
261
262
263
264
265
266
267
268
269
270
271
272 protected final void generateGTU(final Length initialPosition, final Lane lane, final GtuType gtuType)
273 throws GtuException, NetworkException, SimRuntimeException, InputParameterException
274 {
275
276 boolean generateTruck = this.stream.nextDouble() > this.carProbability;
277 Length vehicleLength = new Length(generateTruck ? 15 : 4, METER);
278 LaneBasedGtu gtu = new LaneBasedGtu("" + (++this.carsCreated), gtuType, vehicleLength, new Length(1.8, METER),
279 new Speed(200, KM_PER_HOUR), vehicleLength.times(0.5), this.network);
280 gtu.setParameters(generateTruck ? this.parametersTruck : this.parametersCar);
281 gtu.setNoLaneChangeDistance(Length.ZERO);
282 gtu.setBookkeeping(
283 ((boolean) getInputParameter("generic.gradualLaneChange")) ? LaneBookkeeping.START : LaneBookkeeping.INSTANT);
284 gtu.setMaximumAcceleration(Acceleration.ofSI(3.0));
285 gtu.setMaximumDeceleration(Acceleration.ofSI(-8.0));
286
287
288 LaneBasedStrategicalPlanner strategicalPlanner;
289 Route route = null;
290 if (!generateTruck)
291 {
292 strategicalPlanner = this.strategicalPlannerGeneratorCars.create(gtu, route, null, null);
293 }
294 else
295 {
296 strategicalPlanner = this.strategicalPlannerGeneratorTrucks.create(gtu, route, null, null);
297 }
298
299
300 Speed initialSpeed = new Speed(0, KM_PER_HOUR);
301 gtu.init(strategicalPlanner, new LanePosition(lane, initialPosition).getLocation(), initialSpeed);
302 }
303
304 @Override
305 public RoadNetwork getNetwork()
306 {
307 return this.network;
308 }
309
310
311
312
313
314 public final Length getMinimumDistance()
315 {
316 return this.minimumDistance;
317 }
318
319
320
321
322
323
324 public void stopSimulator(final OtsSimulatorInterface theSimulator, final String errorMessage)
325 {
326 System.out.println("Error: " + errorMessage);
327 try
328 {
329 if (theSimulator.isStartingOrRunning())
330 {
331 theSimulator.stop();
332 }
333 }
334 catch (SimRuntimeException exception)
335 {
336 exception.printStackTrace();
337 }
338 throw new Error(errorMessage);
339 }
340
341 }