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.LinkedHashSet;
8 import java.util.List;
9 import java.util.Random;
10 import java.util.Set;
11
12 import javax.naming.NamingException;
13 import javax.swing.JPanel;
14 import javax.swing.SwingUtilities;
15
16 import nl.tudelft.simulation.dsol.SimRuntimeException;
17 import nl.tudelft.simulation.dsol.gui.swing.TablePanel;
18 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
19
20 import org.djunits.unit.TimeUnit;
21 import org.djunits.unit.UNITS;
22 import org.djunits.value.vdouble.scalar.Acceleration;
23 import org.djunits.value.vdouble.scalar.DoubleScalar;
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.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.network.LongitudinalDirectionality;
37 import org.opentrafficsim.core.network.NetworkException;
38 import org.opentrafficsim.core.network.OTSNetwork;
39 import org.opentrafficsim.core.network.OTSNode;
40 import org.opentrafficsim.graphs.FundamentalDiagramLane;
41 import org.opentrafficsim.road.gtu.animation.DefaultCarAnimation;
42 import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
43 import org.opentrafficsim.road.gtu.lane.driver.LaneBasedBehavioralCharacteristics;
44 import org.opentrafficsim.road.gtu.lane.perception.LanePerceptionFull;
45 import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedGTUFollowingTacticalPlanner;
46 import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
47 import org.opentrafficsim.road.gtu.lane.tactical.following.IDMOld;
48 import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusOld;
49 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.AbstractLaneChangeModel;
50 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.Egoistic;
51 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
52 import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlanner;
53 import org.opentrafficsim.road.network.factory.LaneFactory;
54 import org.opentrafficsim.road.network.lane.CrossSectionLink;
55 import org.opentrafficsim.road.network.lane.DirectedLanePosition;
56 import org.opentrafficsim.road.network.lane.Lane;
57 import org.opentrafficsim.road.network.lane.LaneType;
58 import org.opentrafficsim.road.network.lane.Sensor;
59 import org.opentrafficsim.road.network.lane.SinkSensor;
60 import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
61 import org.opentrafficsim.simulationengine.AbstractWrappableAnimation;
62 import org.opentrafficsim.simulationengine.OTSSimulationException;
63 import org.opentrafficsim.simulationengine.properties.AbstractProperty;
64 import org.opentrafficsim.simulationengine.properties.ProbabilityDistributionProperty;
65 import org.opentrafficsim.simulationengine.properties.PropertyException;
66 import org.opentrafficsim.simulationengine.properties.SelectionProperty;
67
68
69
70
71
72
73
74
75
76
77
78 public class FundamentalDiagramsLane extends AbstractWrappableAnimation implements UNITS
79 {
80
81 private FundamentalDiagramLanePlotsModel model;
82
83
84 public FundamentalDiagramsLane()
85 {
86 try
87 {
88 this.properties.add(new SelectionProperty("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>", new String[]{"IDM", "IDM+"},
93 1, false, 500));
94 this.properties.add(new ProbabilityDistributionProperty("Traffic composition",
95 "<html>Mix of passenger cars and trucks</html>", new String[]{"passenger car", "truck"}, new Double[]{
96 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.Abs(0.0, SECOND), new Time.Rel(0.0, SECOND),
129 new Time.Rel(3600.0, SECOND), fundamentalDiagramsLane.getProperties(), null, true);
130 }
131 catch (SimRuntimeException | NamingException | OTSSimulationException 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() 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 =
169 new FundamentalDiagramLane("Fundamental Diagram for [" + xs + ", " + xe + "] m", new Time.Rel(1.0,
170 SECOND), 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 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 Time.Rel headway;
230
231
232 private int carsCreated = 0;
233
234
235 private GTUType gtuType = GTUType.makeGTUType("Car");
236
237
238 private GTUFollowingModelOld carFollowingModelCars;
239
240
241 private GTUFollowingModelOld carFollowingModelTrucks;
242
243
244 private double carProbability;
245
246
247 private AbstractLaneChangeModel laneChangeModel = new Egoistic();
248
249
250 private LaneBasedIndividualGTU block = null;
251
252
253 private Length.Rel startX = new Length.Rel(0, METER);
254
255
256 private Length.Rel laneLength = new Length.Rel(500, METER);
257
258
259 private List<Lane> lanes = new ArrayList<>();
260
261
262 private Speed speedLimit = new Speed(100, KM_PER_HOUR);
263
264
265 private ArrayList<FundamentalDiagramLane> fundamentalDiagramsLane = new ArrayList<>();
266
267
268 private ArrayList<AbstractProperty<?>> properties = null;
269
270
271 private Random randomGenerator = new Random(12345);
272
273
274 private final GTUColorer gtuColorer;
275
276
277
278
279
280 public FundamentalDiagramLanePlotsModel(final ArrayList<AbstractProperty<?>> properties,
281 final GTUColorer gtuColorer)
282 {
283 this.properties = properties;
284 this.gtuColorer = gtuColorer;
285 }
286
287
288 @Override
289 public final
290 void
291 constructModel(
292 final SimulatorInterface<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble> theSimulator)
293 throws SimRuntimeException, RemoteException
294 {
295 this.simulator = (OTSDEVSSimulatorInterface) theSimulator;
296 try
297 {
298 LaneType laneType = new LaneType("CarLane");
299 laneType.addCompatibility(this.gtuType);
300 OTSNode node = new OTSNode("Node 0", new OTSPoint3D(this.startX.getSI(), 0, 0));
301 for (int laneNr = 0; laneNr < 10; laneNr++)
302 {
303 OTSNode next =
304 new OTSNode("Node " + (laneNr + 1),
305 new OTSPoint3D(node.getPoint().x + this.laneLength.si, 0, 0));
306 Lane lane =
307 LaneFactory.makeLane("Lane", node, next, null, laneType, this.speedLimit, this.simulator,
308 LongitudinalDirectionality.DIR_PLUS);
309 this.lanes.add(lane);
310 node = next;
311 }
312
313 OTSNode end = new OTSNode("End", new OTSPoint3D(node.getPoint().x + 50.0, 0, 0));
314 CrossSectionLink endLink =
315 LaneFactory.makeLink("endLink", node, end, null, LongitudinalDirectionality.DIR_PLUS);
316 int last = this.lanes.size() - 1;
317 Lane sinkLane =
318 new Lane(endLink, "sinkLane", this.lanes.get(last).getLateralCenterPosition(1.0), this.lanes.get(
319 last).getLateralCenterPosition(1.0), this.lanes.get(last).getWidth(1.0), this.lanes.get(last)
320 .getWidth(1.0), laneType, LongitudinalDirectionality.DIR_PLUS, this.speedLimit,
321 new OvertakingConditions.None());
322 Sensor sensor = new SinkSensor(sinkLane, new Length.Rel(10.0, METER), this.simulator);
323 sinkLane.addSensor(sensor, GTUType.ALL);
324 }
325 catch (NamingException | NetworkException | OTSGeometryException exception)
326 {
327 exception.printStackTrace();
328 }
329
330 for (AbstractProperty<?> p : this.properties)
331 {
332 if (p instanceof SelectionProperty)
333 {
334 SelectionProperty sp = (SelectionProperty) p;
335 if ("Car following model".equals(sp.getShortName()))
336 {
337 String modelName = sp.getValue();
338 if (modelName.equals("IDM"))
339 {
340 this.carFollowingModelCars =
341 new IDMOld(new Acceleration(1, METER_PER_SECOND_2), new Acceleration(1.5,
342 METER_PER_SECOND_2), new Length.Rel(2, METER), new Time.Rel(1, SECOND), 1d);
343 this.carFollowingModelTrucks =
344 new IDMOld(new Acceleration(0.5, METER_PER_SECOND_2), new Acceleration(1.5,
345 METER_PER_SECOND_2), new Length.Rel(2, METER), new Time.Rel(1, SECOND), 1d);
346 }
347 else if (modelName.equals("IDM+"))
348 {
349 this.carFollowingModelCars =
350 new IDMPlusOld(new Acceleration(1, METER_PER_SECOND_2), new Acceleration(1.5,
351 METER_PER_SECOND_2), new Length.Rel(2, METER), new Time.Rel(1, SECOND), 1d);
352 this.carFollowingModelTrucks =
353 new IDMPlusOld(new Acceleration(0.5, METER_PER_SECOND_2), new Acceleration(1.5,
354 METER_PER_SECOND_2), new Length.Rel(2, METER), new Time.Rel(1, SECOND), 1d);
355 }
356 else
357 {
358 throw new Error("Car following model " + modelName + " not implemented");
359 }
360 }
361 else
362 {
363 throw new Error("Unhandled SelectionProperty " + p.getShortName());
364 }
365 }
366 else if (p instanceof ProbabilityDistributionProperty)
367 {
368 ProbabilityDistributionProperty pdp = (ProbabilityDistributionProperty) p;
369 String modelName = p.getShortName();
370 if (modelName.equals("Traffic composition"))
371 {
372 this.carProbability = pdp.getValue()[0];
373 }
374 else
375 {
376 throw new Error("Unhandled ProbabilityDistributionProperty " + p.getShortName());
377 }
378 }
379 else
380 {
381 throw new Error("Unhandled property: " + p);
382 }
383 }
384
385
386 this.headway = new Time.Rel(3600.0 / 1500.0, SECOND);
387
388 try
389 {
390
391 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(0.0, SECOND), this, this, "generateCar",
392 null);
393
394 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(1000, SECOND), this, this,
395 "createBlock", null);
396
397 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(1200, SECOND), this, this,
398 "removeBlock", null);
399
400 for (int t = 1; t <= this.simulator.getReplication().getTreatment().getRunLength().si / 25; t++)
401 {
402 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(25 * t - 0.001, SECOND), this, this,
403 "drawGraphs", null);
404 }
405 }
406 catch (SimRuntimeException exception)
407 {
408 exception.printStackTrace();
409 }
410 }
411
412
413
414
415
416 protected final void createBlock() throws RemoteException
417 {
418 Length.Rel initialPosition = new Length.Rel(200, METER);
419 Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
420 try
421 {
422 initialPositions.add(new DirectedLanePosition(this.lanes.get(this.lanes.size() - 1), initialPosition,
423 GTUDirectionality.DIR_PLUS));
424 LaneBasedBehavioralCharacteristics drivingCharacteristics =
425 new LaneBasedBehavioralCharacteristics(this.carFollowingModelCars, this.laneChangeModel);
426 LaneBasedStrategicalPlanner strategicalPlanner =
427 new LaneBasedStrategicalRoutePlanner(drivingCharacteristics,
428 new LaneBasedGTUFollowingTacticalPlanner());
429 this.block =
430 new LaneBasedIndividualGTU("999999", this.gtuType, initialPositions, new Speed(0.0, KM_PER_HOUR),
431 new Length.Rel(4, METER), new Length.Rel(1.8, METER), new Speed(0.0, KM_PER_HOUR),
432 this.simulator, strategicalPlanner, new LanePerceptionFull(), DefaultCarAnimation.class,
433 this.gtuColorer, this.network);
434 }
435 catch (SimRuntimeException | NamingException | NetworkException | GTUException | OTSGeometryException exception)
436 {
437 exception.printStackTrace();
438 }
439 }
440
441
442
443
444 protected final void removeBlock()
445 {
446 this.block.destroy();
447 this.block = null;
448 }
449
450
451
452
453 protected final void generateCar()
454 {
455 boolean generateTruck = this.randomGenerator.nextDouble() > this.carProbability;
456 Length.Rel initialPosition = new Length.Rel(0, METER);
457 Speed initialSpeed = new Speed(100, KM_PER_HOUR);
458 Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
459 try
460 {
461 initialPositions.add(new DirectedLanePosition(this.lanes.get(0), initialPosition,
462 GTUDirectionality.DIR_PLUS));
463 Length.Rel vehicleLength = new Length.Rel(generateTruck ? 15 : 4, METER);
464 GTUFollowingModelOld gtuFollowingModel =
465 generateTruck ? this.carFollowingModelTrucks : this.carFollowingModelCars;
466 if (null == gtuFollowingModel)
467 {
468 throw new Error("gtuFollowingModel is null");
469 }
470 LaneBasedBehavioralCharacteristics drivingCharacteristics =
471 new LaneBasedBehavioralCharacteristics(gtuFollowingModel, this.laneChangeModel);
472 LaneBasedStrategicalPlanner strategicalPlanner =
473 new LaneBasedStrategicalRoutePlanner(drivingCharacteristics,
474 new LaneBasedGTUFollowingTacticalPlanner());
475 new LaneBasedIndividualGTU("" + (++this.carsCreated), this.gtuType, initialPositions, initialSpeed,
476 vehicleLength, new Length.Rel(1.8, METER), new Speed(200, KM_PER_HOUR), this.simulator,
477 strategicalPlanner, new LanePerceptionFull(), DefaultCarAnimation.class, this.gtuColorer,
478 this.network);
479 this.simulator.scheduleEventRel(this.headway, this, this, "generateCar", null);
480 }
481 catch (SimRuntimeException | NamingException | NetworkException | GTUException | OTSGeometryException exception)
482 {
483 exception.printStackTrace();
484 }
485 }
486
487
488
489
490 protected final void drawGraphs()
491 {
492
493 for (FundamentalDiagramLane fd : this.fundamentalDiagramsLane)
494 {
495 fd.reGraph();
496 }
497 }
498
499
500 @Override
501 public final SimulatorInterface<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble>
502 getSimulator() throws RemoteException
503 {
504 return this.simulator;
505 }
506
507
508
509
510 public final ArrayList<FundamentalDiagramLane> getFundamentalDiagrams()
511 {
512 return this.fundamentalDiagramsLane;
513 }
514
515
516
517
518
519 public Lane getLane(final int laneNr)
520 {
521 return this.lanes.get(laneNr);
522 }
523 }
524 }