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