1 package org.opentrafficsim.demo.carFollowing;
2
3 import java.awt.Frame;
4 import java.awt.geom.Rectangle2D;
5 import java.rmi.RemoteException;
6 import java.util.ArrayList;
7 import java.util.HashSet;
8 import java.util.LinkedHashSet;
9 import java.util.List;
10 import java.util.Random;
11 import java.util.Set;
12
13 import javax.naming.NamingException;
14 import javax.swing.JPanel;
15 import javax.swing.SwingUtilities;
16
17 import nl.tudelft.simulation.dsol.SimRuntimeException;
18 import nl.tudelft.simulation.dsol.gui.swing.TablePanel;
19 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
20
21 import org.djunits.unit.UNITS;
22 import org.djunits.value.vdouble.scalar.Acceleration;
23 import org.djunits.value.vdouble.scalar.Duration;
24 import org.djunits.value.vdouble.scalar.Length;
25 import org.djunits.value.vdouble.scalar.Speed;
26 import org.djunits.value.vdouble.scalar.Time;
27 import org.opentrafficsim.base.modelproperties.ProbabilityDistributionProperty;
28 import org.opentrafficsim.base.modelproperties.Property;
29 import org.opentrafficsim.base.modelproperties.PropertyException;
30 import org.opentrafficsim.base.modelproperties.SelectionProperty;
31 import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
32 import org.opentrafficsim.core.dsol.OTSModelInterface;
33 import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
34 import org.opentrafficsim.core.geometry.OTSGeometryException;
35 import org.opentrafficsim.core.geometry.OTSPoint3D;
36 import org.opentrafficsim.core.gtu.GTUDirectionality;
37 import org.opentrafficsim.core.gtu.GTUException;
38 import org.opentrafficsim.core.gtu.GTUType;
39 import org.opentrafficsim.core.gtu.animation.GTUColorer;
40 import org.opentrafficsim.core.gtu.behavioralcharacteristics.BehavioralCharacteristics;
41 import org.opentrafficsim.core.network.LongitudinalDirectionality;
42 import org.opentrafficsim.core.network.NetworkException;
43 import org.opentrafficsim.core.network.OTSNetwork;
44 import org.opentrafficsim.core.network.OTSNode;
45 import org.opentrafficsim.graphs.FundamentalDiagramLane;
46 import org.opentrafficsim.road.gtu.animation.DefaultCarAnimation;
47 import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
48 import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedGTUFollowingTacticalPlanner;
49 import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
50 import org.opentrafficsim.road.gtu.lane.tactical.following.IDMOld;
51 import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusOld;
52 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
53 import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlanner;
54 import org.opentrafficsim.road.network.factory.LaneFactory;
55 import org.opentrafficsim.road.network.lane.CrossSectionLink;
56 import org.opentrafficsim.road.network.lane.DirectedLanePosition;
57 import org.opentrafficsim.road.network.lane.Lane;
58 import org.opentrafficsim.road.network.lane.LaneType;
59 import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
60 import org.opentrafficsim.road.network.lane.object.sensor.Sensor;
61 import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
62 import org.opentrafficsim.simulationengine.AbstractWrappableAnimation;
63 import org.opentrafficsim.simulationengine.OTSSimulationException;
64 import org.opentrafficsim.simulationengine.SimpleSimulatorInterface;
65
66
67
68
69
70
71
72
73
74
75
76 public class FundamentalDiagramsLane extends AbstractWrappableAnimation implements UNITS
77 {
78
79 private static final long serialVersionUID = 1L;
80
81
82 private FundamentalDiagramLanePlotsModel model;
83
84
85 public FundamentalDiagramsLane()
86 {
87 try
88 {
89 this.properties.add(new SelectionProperty("CarFollowingModel", "Car following model",
90 "<html>The car following model determines "
91 + "the acceleration that a vehicle will make taking into account nearby vehicles, "
92 + "infrastructural restrictions (e.g. speed limit, curvature of the road) "
93 + "capabilities of the vehicle and personality of the driver.</html>",
94 new String[] { "IDM", "IDM+" }, 1, false, 500));
95 this.properties.add(new ProbabilityDistributionProperty("TrafficComposition", "Traffic composition",
96 "<html>Mix of passenger cars and trucks</html>", new String[] { "passenger car", "truck" },
97 new Double[] { 0.8, 0.2 }, false, 10));
98 }
99 catch (PropertyException exception)
100 {
101 exception.printStackTrace();
102 }
103 }
104
105
106 @Override
107 public final void stopTimersThreads()
108 {
109 super.stopTimersThreads();
110 this.model = null;
111 }
112
113
114
115
116
117
118 public static void main(final String[] args) throws SimRuntimeException
119 {
120
121 SwingUtilities.invokeLater(new Runnable()
122 {
123 @Override
124 public void run()
125 {
126 try
127 {
128 FundamentalDiagramsLane fundamentalDiagramsLane = new FundamentalDiagramsLane();
129 fundamentalDiagramsLane.buildAnimator(new Time(0.0, SECOND), new Duration(0.0, SECOND),
130 new Duration(3600.0, SECOND), fundamentalDiagramsLane.getProperties(), null, true);
131 }
132 catch (SimRuntimeException | NamingException | OTSSimulationException | PropertyException exception)
133 {
134 exception.printStackTrace();
135 }
136 }
137 });
138 }
139
140
141 @Override
142 protected final OTSModelInterface makeModel(final GTUColorer colorer)
143 {
144 this.model = new FundamentalDiagramLanePlotsModel(this.savedUserModifiedProperties, colorer);
145 return this.model;
146 }
147
148
149 @Override
150 protected final Rectangle2D.Double makeAnimationRectangle()
151 {
152 return new Rectangle2D.Double(0, -100, 5000, 200);
153 }
154
155
156 @Override
157 protected final JPanel makeCharts(final SimpleSimulatorInterface simulator) throws OTSSimulationException
158 {
159 final int panelsPerRow = 3;
160 TablePanel charts = new TablePanel(3, panelsPerRow);
161 for (int plotNumber = 0; plotNumber < 9; plotNumber++)
162 {
163 FundamentalDiagramLane fd;
164 try
165 {
166 Lane lane = this.model.getLane(plotNumber);
167 int xs = (int) lane.getParentLink().getStartNode().getPoint().x;
168 int xe = (int) lane.getParentLink().getEndNode().getPoint().x;
169 fd = new FundamentalDiagramLane("Fundamental Diagram for [" + xs + ", " + xe + "] m", new Duration(1.0, SECOND),
170 lane, (OTSDEVSSimulatorInterface) this.model.getSimulator());
171 fd.setTitle("Fundamental Diagram Graph");
172 fd.setExtendedState(Frame.MAXIMIZED_BOTH);
173 this.model.getFundamentalDiagrams().add(fd);
174 charts.setCell(fd.getContentPane(), plotNumber / panelsPerRow, plotNumber % panelsPerRow);
175 }
176 catch (NetworkException | RemoteException | SimRuntimeException exception)
177 {
178 exception.printStackTrace();
179 }
180 }
181 return charts;
182 }
183
184
185 @Override
186 public final String shortName()
187 {
188 return "Fundamental Diagrams";
189 }
190
191
192 @Override
193 public final String description()
194 {
195 return "<html><h1>Fundamental Diagram Plots</H1>"
196 + "Simulation of a single lane road of 5 km length. Vechicles are generated at a constant rate of "
197 + "1500 veh/hour. At time 300s a blockade is inserted at position 4km; this blockade is removed at time "
198 + "500s. This blockade simulates a bridge opening.<br>"
199 + "The blockade causes a traffic jam that slowly dissolves after the blockade is removed.<br>"
200 + "Output is a set of Diagrams that plot observed density, flow and speed plots against each other.</html>";
201 }
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218 class FundamentalDiagramLanePlotsModel implements OTSModelInterface, UNITS
219 {
220
221 private static final long serialVersionUID = 20140820L;
222
223
224 private OTSNetwork network = new OTSNetwork("network");
225
226
227 private OTSDEVSSimulatorInterface simulator;
228
229
230 private Duration headway;
231
232
233 private int carsCreated = 0;
234
235
236 private GTUType gtuType = new GTUType("Car");
237
238
239 private GTUFollowingModelOld carFollowingModelCars;
240
241
242 private GTUFollowingModelOld carFollowingModelTrucks;
243
244
245 private double carProbability;
246
247
248 private LaneBasedIndividualGTU block = null;
249
250
251 private Length startX = new Length(0, METER);
252
253
254 private Length laneLength = new Length(500, METER);
255
256
257 private List<Lane> lanes = new ArrayList<>();
258
259
260 private Speed speedLimit = new Speed(100, KM_PER_HOUR);
261
262
263 private List<FundamentalDiagramLane> fundamentalDiagramsLane = new ArrayList<>();
264
265
266 private List<Property<?>> fundamentalDiagramsLaneProperties = null;
267
268
269 private Random randomGenerator = new Random(12345);
270
271
272 private final GTUColorer gtuColorer;
273
274
275
276
277
278 FundamentalDiagramLanePlotsModel(final List<Property<?>> properties, final GTUColorer gtuColorer)
279 {
280 this.fundamentalDiagramsLaneProperties = properties;
281 this.gtuColorer = gtuColorer;
282 }
283
284
285 @Override
286 public final void constructModel(final SimulatorInterface<Time, Duration, OTSSimTimeDouble> theSimulator)
287 throws SimRuntimeException, RemoteException
288 {
289 this.simulator = (OTSDEVSSimulatorInterface) theSimulator;
290 try
291 {
292 Set<GTUType> compatibility = new HashSet<>();
293 compatibility.add(this.gtuType);
294 LaneType laneType = new LaneType("CarLane", compatibility);
295 OTSNode node = new OTSNode(this.network, "Node 0", new OTSPoint3D(this.startX.getSI(), 0, 0));
296 for (int laneNr = 0; laneNr < 10; laneNr++)
297 {
298 OTSNode next = new OTSNode(this.network, "Node " + (laneNr + 1),
299 new OTSPoint3D(node.getPoint().x + this.laneLength.si, 0, 0));
300 Lane lane = LaneFactory.makeLane(this.network, "Lane", node, next, null, laneType, this.speedLimit,
301 this.simulator, LongitudinalDirectionality.DIR_PLUS);
302 this.lanes.add(lane);
303 node = next;
304 }
305
306 OTSNode end = new OTSNode(this.network, "End", new OTSPoint3D(node.getPoint().x + 50.0, 0, 0));
307 CrossSectionLink endLink =
308 LaneFactory.makeLink(this.network, "endLink", node, end, null, LongitudinalDirectionality.DIR_PLUS);
309 int last = this.lanes.size() - 1;
310 Lane sinkLane = new Lane(endLink, "sinkLane", this.lanes.get(last).getLateralCenterPosition(1.0),
311 this.lanes.get(last).getLateralCenterPosition(1.0), this.lanes.get(last).getWidth(1.0),
312 this.lanes.get(last).getWidth(1.0), laneType, LongitudinalDirectionality.DIR_PLUS, this.speedLimit,
313 new OvertakingConditions.None());
314 Sensor sensor = new SinkSensor(sinkLane, new Length(10.0, METER), this.simulator);
315 sinkLane.addSensor(sensor, GTUType.ALL);
316 }
317 catch (NamingException | NetworkException | OTSGeometryException exception)
318 {
319 exception.printStackTrace();
320 }
321
322 for (Property<?> p : this.fundamentalDiagramsLaneProperties)
323 {
324 if (p instanceof SelectionProperty)
325 {
326 SelectionProperty sp = (SelectionProperty) p;
327 if ("CarGollowingModel".equals(sp.getKey()))
328 {
329 String modelName = sp.getValue();
330 if (modelName.equals("IDM"))
331 {
332 this.carFollowingModelCars = new IDMOld(new Acceleration(1, METER_PER_SECOND_2),
333 new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND),
334 1d);
335 this.carFollowingModelTrucks = new IDMOld(new Acceleration(0.5, METER_PER_SECOND_2),
336 new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND),
337 1d);
338 }
339 else if (modelName.equals("IDM+"))
340 {
341 this.carFollowingModelCars = new IDMPlusOld(new Acceleration(1, METER_PER_SECOND_2),
342 new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND),
343 1d);
344 this.carFollowingModelTrucks = new IDMPlusOld(new Acceleration(0.5, METER_PER_SECOND_2),
345 new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND),
346 1d);
347 }
348 else
349 {
350 throw new Error("Car following model " + modelName + " not implemented");
351 }
352 }
353 else
354 {
355 throw new Error("Unhandled SelectionProperty " + p.getKey());
356 }
357 }
358 else if (p instanceof ProbabilityDistributionProperty)
359 {
360 ProbabilityDistributionProperty pdp = (ProbabilityDistributionProperty) p;
361 String modelName = p.getKey();
362 if (modelName.equals("TrafficComposition"))
363 {
364 this.carProbability = pdp.getValue()[0];
365 }
366 else
367 {
368 throw new Error("Unhandled ProbabilityDistributionProperty " + p.getKey());
369 }
370 }
371 else
372 {
373 throw new Error("Unhandled property: " + p);
374 }
375 }
376
377
378 this.headway = new Duration(3600.0 / 1500.0, SECOND);
379
380 try
381 {
382
383 this.simulator.scheduleEventAbs(new Time(0.0, SECOND), this, this, "generateCar", null);
384
385 this.simulator.scheduleEventAbs(new Time(1000, SECOND), this, this, "createBlock", null);
386
387 this.simulator.scheduleEventAbs(new Time(1200, SECOND), this, this, "removeBlock", null);
388
389 for (int t = 1; t <= this.simulator.getReplication().getTreatment().getRunLength().si / 25; t++)
390 {
391 this.simulator.scheduleEventAbs(new Time(25 * t - 0.001, SECOND), this, this, "drawGraphs", null);
392 }
393 }
394 catch (SimRuntimeException exception)
395 {
396 exception.printStackTrace();
397 }
398 }
399
400
401
402
403
404 protected final void createBlock() throws RemoteException
405 {
406 Length initialPosition = new Length(200, METER);
407 Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
408 try
409 {
410 initialPositions.add(new DirectedLanePosition(this.lanes.get(this.lanes.size() - 1), initialPosition,
411 GTUDirectionality.DIR_PLUS));
412 BehavioralCharacteristics behavioralCharacteristics = DefaultsFactory.getDefaultBehavioralCharacteristics();
413 this.block = new LaneBasedIndividualGTU("999999", this.gtuType, new Length(4, METER), new Length(1.8, METER),
414 new Speed(0.0, KM_PER_HOUR), this.simulator, this.network);
415 LaneBasedStrategicalPlanner strategicalPlanner = new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics,
416 new LaneBasedGTUFollowingTacticalPlanner(this.carFollowingModelCars, this.block), this.block);
417 this.block.initWithAnimation(strategicalPlanner, initialPositions, new Speed(0.0, KM_PER_HOUR),
418 DefaultCarAnimation.class, this.gtuColorer);
419 }
420 catch (SimRuntimeException | NamingException | NetworkException | GTUException | OTSGeometryException exception)
421 {
422 exception.printStackTrace();
423 }
424 }
425
426
427
428
429 protected final void removeBlock()
430 {
431 this.block.destroy();
432 this.block = null;
433 }
434
435
436
437
438 protected final void generateCar()
439 {
440 boolean generateTruck = this.randomGenerator.nextDouble() > this.carProbability;
441 Length initialPosition = new Length(0, METER);
442 Speed initialSpeed = new Speed(100, KM_PER_HOUR);
443 Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
444 try
445 {
446 initialPositions.add(new DirectedLanePosition(this.lanes.get(0), initialPosition, GTUDirectionality.DIR_PLUS));
447 Length vehicleLength = new Length(generateTruck ? 15 : 4, METER);
448 GTUFollowingModelOld gtuFollowingModel =
449 generateTruck ? this.carFollowingModelTrucks : this.carFollowingModelCars;
450 if (null == gtuFollowingModel)
451 {
452 throw new Error("gtuFollowingModel is null");
453 }
454 BehavioralCharacteristics behavioralCharacteristics = DefaultsFactory.getDefaultBehavioralCharacteristics();
455
456 LaneBasedIndividualGTU gtu = new LaneBasedIndividualGTU("" + (++this.carsCreated), this.gtuType, vehicleLength,
457 new Length(1.8, METER), new Speed(200, KM_PER_HOUR), this.simulator, this.network);
458 LaneBasedStrategicalPlanner strategicalPlanner = new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics,
459 new LaneBasedGTUFollowingTacticalPlanner(gtuFollowingModel, gtu), gtu);
460 gtu.initWithAnimation(strategicalPlanner, initialPositions, initialSpeed, DefaultCarAnimation.class,
461 this.gtuColorer);
462 this.simulator.scheduleEventRel(this.headway, this, this, "generateCar", null);
463 }
464 catch (SimRuntimeException | NamingException | NetworkException | GTUException | OTSGeometryException exception)
465 {
466 exception.printStackTrace();
467 }
468 }
469
470
471
472
473 protected final void drawGraphs()
474 {
475
476 for (FundamentalDiagramLane fd : this.fundamentalDiagramsLane)
477 {
478 fd.reGraph();
479 }
480 }
481
482
483 @Override
484 public final SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator() throws RemoteException
485 {
486 return this.simulator;
487 }
488
489
490
491
492 public final List<FundamentalDiagramLane> getFundamentalDiagrams()
493 {
494 return this.fundamentalDiagramsLane;
495 }
496
497
498
499
500
501 public Lane getLane(final int laneNr)
502 {
503 return this.lanes.get(laneNr);
504 }
505 }
506 }