1 package org.opentrafficsim.demo.carFollowing;
2
3 import java.awt.Frame;
4 import java.awt.geom.Rectangle2D;
5 import java.io.IOException;
6 import java.net.URL;
7 import java.rmi.RemoteException;
8 import java.util.ArrayList;
9 import java.util.Collection;
10 import java.util.HashMap;
11 import java.util.Map;
12 import java.util.Random;
13
14 import javax.naming.NamingException;
15 import javax.swing.JScrollPane;
16 import javax.swing.SwingUtilities;
17
18 import nl.tudelft.simulation.dsol.SimRuntimeException;
19 import nl.tudelft.simulation.dsol.gui.swing.DSOLPanel;
20 import nl.tudelft.simulation.dsol.gui.swing.HTMLPanel;
21 import nl.tudelft.simulation.dsol.gui.swing.TablePanel;
22 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
23
24 import org.opentrafficsim.car.Car;
25 import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
26 import org.opentrafficsim.core.dsol.OTSModelInterface;
27 import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
28 import org.opentrafficsim.core.gtu.GTUType;
29 import org.opentrafficsim.core.gtu.following.GTUFollowingModel;
30 import org.opentrafficsim.core.gtu.following.GTUFollowingModel.GTUFollowingModelResult;
31 import org.opentrafficsim.core.gtu.following.IDM;
32 import org.opentrafficsim.core.gtu.following.IDMPlus;
33 import org.opentrafficsim.core.network.NetworkException;
34 import org.opentrafficsim.core.network.factory.LaneFactory;
35 import org.opentrafficsim.core.network.factory.Node;
36 import org.opentrafficsim.core.network.lane.Lane;
37 import org.opentrafficsim.core.network.lane.LaneType;
38 import org.opentrafficsim.core.unit.AccelerationUnit;
39 import org.opentrafficsim.core.unit.LengthUnit;
40 import org.opentrafficsim.core.unit.SpeedUnit;
41 import org.opentrafficsim.core.unit.TimeUnit;
42 import org.opentrafficsim.core.value.vdouble.scalar.DoubleScalar;
43 import org.opentrafficsim.graphs.TrajectoryPlot;
44 import org.opentrafficsim.simulationengine.AbstractProperty;
45 import org.opentrafficsim.simulationengine.ControlPanel;
46 import org.opentrafficsim.simulationengine.ProbabilityDistributionProperty;
47 import org.opentrafficsim.simulationengine.PropertyException;
48 import org.opentrafficsim.simulationengine.SelectionProperty;
49 import org.opentrafficsim.simulationengine.SimpleSimulator;
50 import org.opentrafficsim.simulationengine.SimulatorFrame;
51 import org.opentrafficsim.simulationengine.WrappableSimulation;
52
53 import com.vividsolutions.jts.geom.Coordinate;
54
55
56
57
58
59
60
61
62
63
64 public class Trajectories implements WrappableSimulation
65 {
66
67 private ArrayList<AbstractProperty<?>> properties = new ArrayList<AbstractProperty<?>>();
68
69
70 public Trajectories()
71 {
72 try
73 {
74 this.properties.add(new SelectionProperty("Car following model", "<html>The car following model determines "
75 + "the acceleration that a vehicle will make taking into account nearby vehicles, infrastructural "
76 + "restrictions (e.g. speed limit, curvature of the road) capabilities of the vehicle and "
77 + "personality of the driver.</html>", new String[] {"IDM", "IDM+"}, 1, false, 10));
78 this.properties.add(new ProbabilityDistributionProperty("Traffic composition",
79 "<html>Mix of passenger cars and trucks</html>", new String[] {"passenger car", "truck"}, new Double[] {0.8,
80 0.2}, false, 9));
81 }
82 catch (PropertyException exception)
83 {
84 exception.printStackTrace();
85 }
86 }
87
88
89
90
91
92
93
94 public static void main(final String[] args) throws RemoteException, SimRuntimeException
95 {
96
97 SwingUtilities.invokeLater(new Runnable()
98 {
99 @Override
100 public void run()
101 {
102 try
103 {
104 Trajectories trajectories = new Trajectories();
105 new SimulatorFrame("Trajectory Plots animation", trajectories.buildSimulator(
106 trajectories.getProperties()).getPanel());
107 }
108 catch (RemoteException | SimRuntimeException exception)
109 {
110 exception.printStackTrace();
111 }
112 }
113 });
114 }
115
116
117
118
119
120
121
122 public SimpleSimulator buildSimulator(ArrayList<AbstractProperty<?>> userModifiedProperties) throws RemoteException,
123 SimRuntimeException
124 {
125 TrajectoriesModel model = new TrajectoriesModel(userModifiedProperties);
126 SimpleSimulator result =
127 new SimpleSimulator(new OTSSimTimeDouble(new DoubleScalar.Abs<TimeUnit>(0.0, TimeUnit.SECOND)),
128 new DoubleScalar.Rel<TimeUnit>(0.0, TimeUnit.SECOND),
129 new DoubleScalar.Rel<TimeUnit>(1800.0, TimeUnit.SECOND), model, new Rectangle2D.Double(0, -100, 5000, 200));
130 new ControlPanel(result);
131 makePlot(model, result.getPanel());
132 addInfoTab(result.getPanel());
133 return result;
134 }
135
136
137
138
139
140
141 private static void makePlot(final TrajectoriesModel model,
142 final DSOLPanel<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble> panel)
143 {
144 TablePanel charts = new TablePanel(1, 1);
145 panel.getTabbedPane().addTab("statistics", charts);
146 DoubleScalar.Rel<TimeUnit> sampleInterval = new DoubleScalar.Rel<TimeUnit>(0.5, TimeUnit.SECOND);
147 TrajectoryPlot tp =
148 new TrajectoryPlot("Trajectory Plot", sampleInterval, model.getMinimumDistance(), model.getMaximumDistance());
149 tp.setTitle("Density Contour Graph");
150 tp.setExtendedState(Frame.MAXIMIZED_BOTH);
151 model.setTrajectoryPlot(tp);
152 charts.setCell(tp.getContentPane(), 0, 0);
153 }
154
155
156
157
158 private static void addInfoTab(
159 final DSOLPanel<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble> panel)
160 {
161
162 String helpSource = "/" + TrajectoriesModel.class.getPackage().getName().replace('.', '/') + "/package.html";
163 URL page = TrajectoriesModel.class.getResource(helpSource);
164 if (page != null)
165 {
166 HTMLPanel htmlPanel;
167 try
168 {
169 htmlPanel = new HTMLPanel(page);
170 panel.getTabbedPane().addTab("info", new JScrollPane(htmlPanel));
171 }
172 catch (IOException exception)
173 {
174 exception.printStackTrace();
175 }
176 }
177 }
178
179
180 @Override
181 public String shortName()
182 {
183 return "Trajectory plot";
184 }
185
186
187 @Override
188 public String description()
189 {
190 return "<html><H1>Trajectories</H1>"
191 + "Simulation of a single lane road of 5 km length. Vechicles are generated at a constant rate of "
192 + "1500 veh/hour. At time 300s a blockade is inserted at position 4km; this blockade is removed at time "
193 + "420s. This blockade simulates a bridge opening.<br/>"
194 + "The blockade causes a traffic jam that slowly dissolves after the blockade is removed.<br />"
195 + "Output is a Trajectory plots.</html>";
196 }
197
198
199 @Override
200 public ArrayList<AbstractProperty<?>> getProperties()
201 {
202
203 return new ArrayList<AbstractProperty<?>>(this.properties);
204 }
205
206 }
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222 class TrajectoriesModel implements OTSModelInterface
223 {
224
225 private static final long serialVersionUID = 20140815L;
226
227
228 private OTSDEVSSimulatorInterface simulator;
229
230
231 private DoubleScalar.Rel<TimeUnit> headway;
232
233
234 private int carsCreated = 0;
235
236
237 protected GTUFollowingModel carFollowingModelCars;
238
239
240 protected GTUFollowingModel carFollowingModelTrucks;
241
242
243 double carProbability;
244
245
246 ArrayList<Car<Integer>> cars = new ArrayList<Car<Integer>>();
247
248
249 protected Car<Integer> block = null;
250
251
252 private DoubleScalar.Rel<LengthUnit> minimumDistance = new DoubleScalar.Rel<LengthUnit>(0, LengthUnit.METER);
253
254
255 DoubleScalar.Rel<LengthUnit> maximumDistance = new DoubleScalar.Rel<LengthUnit>(5000, LengthUnit.METER);
256
257
258 Lane lane;
259
260
261 DoubleScalar.Abs<SpeedUnit> speedLimit = new DoubleScalar.Abs<SpeedUnit>(100, SpeedUnit.KM_PER_HOUR);
262
263
264 private TrajectoryPlot trajectoryPlot;
265
266
267 ArrayList<AbstractProperty<?>> properties = null;
268
269
270 Random randomGenerator = new Random(12345);
271
272
273
274
275 public TrajectoriesModel(ArrayList<AbstractProperty<?>> properties)
276 {
277 this.properties = properties;
278 }
279
280
281 @Override
282 public final void constructModel(
283 final SimulatorInterface<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble> theSimulator)
284 throws SimRuntimeException, RemoteException
285 {
286 this.simulator = (OTSDEVSSimulatorInterface) theSimulator;
287 Node from = new Node("From", new Coordinate(getMinimumDistance().getSI(), 0, 0));
288 Node to = new Node("To", new Coordinate(getMaximumDistance().getSI(), 0, 0));
289 LaneType<String> laneType = new LaneType<String>("CarLane");
290 try
291 {
292 this.lane = LaneFactory.makeLane("Lane", from, to, null, laneType, this.simulator);
293 }
294 catch (NamingException | NetworkException exception1)
295 {
296 exception1.printStackTrace();
297 }
298
299 for (AbstractProperty<?> p : this.properties)
300 {
301 if (p instanceof SelectionProperty)
302 {
303 SelectionProperty sp = (SelectionProperty) p;
304 if ("Car following model".equals(sp.getShortName()))
305 {
306 String modelName = sp.getValue();
307 if (modelName.equals("IDM"))
308 {
309 this.carFollowingModelCars =
310 new IDM(new DoubleScalar.Abs<AccelerationUnit>(1, AccelerationUnit.METER_PER_SECOND_2),
311 new DoubleScalar.Abs<AccelerationUnit>(1.5, AccelerationUnit.METER_PER_SECOND_2),
312 new DoubleScalar.Rel<LengthUnit>(2, LengthUnit.METER), new DoubleScalar.Rel<TimeUnit>(1,
313 TimeUnit.SECOND), 1d);
314 this.carFollowingModelTrucks =
315 new IDM(new DoubleScalar.Abs<AccelerationUnit>(0.5, AccelerationUnit.METER_PER_SECOND_2),
316 new DoubleScalar.Abs<AccelerationUnit>(1.5, AccelerationUnit.METER_PER_SECOND_2),
317 new DoubleScalar.Rel<LengthUnit>(2, LengthUnit.METER), new DoubleScalar.Rel<TimeUnit>(1,
318 TimeUnit.SECOND), 1d);
319 }
320 else if (modelName.equals("IDM+"))
321 {
322 this.carFollowingModelCars =
323 new IDMPlus(new DoubleScalar.Abs<AccelerationUnit>(1, AccelerationUnit.METER_PER_SECOND_2),
324 new DoubleScalar.Abs<AccelerationUnit>(1.5, AccelerationUnit.METER_PER_SECOND_2),
325 new DoubleScalar.Rel<LengthUnit>(2, LengthUnit.METER), new DoubleScalar.Rel<TimeUnit>(1,
326 TimeUnit.SECOND), 1d);
327 this.carFollowingModelTrucks =
328 new IDMPlus(new DoubleScalar.Abs<AccelerationUnit>(0.5, AccelerationUnit.METER_PER_SECOND_2),
329 new DoubleScalar.Abs<AccelerationUnit>(1.5, AccelerationUnit.METER_PER_SECOND_2),
330 new DoubleScalar.Rel<LengthUnit>(2, LengthUnit.METER), new DoubleScalar.Rel<TimeUnit>(1,
331 TimeUnit.SECOND), 1d);
332 }
333 else
334 {
335 throw new Error("Car following model " + modelName + " not implemented");
336 }
337 }
338 else
339 {
340 throw new Error("Unhandled SelectionProperty " + p.getShortName());
341 }
342 }
343 else if (p instanceof ProbabilityDistributionProperty)
344 {
345 ProbabilityDistributionProperty pdp = (ProbabilityDistributionProperty) p;
346 String modelName = p.getShortName();
347 if (modelName.equals("Traffic composition"))
348 {
349 this.carProbability = pdp.getValue()[0];
350 }
351 else
352 {
353 throw new Error("Unhandled ProbabilityDistributionProperty " + p.getShortName());
354 }
355 }
356 else
357 {
358 throw new Error("Unhandled property: " + p);
359 }
360 }
361
362 this.headway = new DoubleScalar.Rel<TimeUnit>(3600.0 / 1500.0, TimeUnit.SECOND);
363
364 try
365 {
366
367 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(0.0, TimeUnit.SECOND), this, this, "generateCar",
368 null);
369
370 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(300, TimeUnit.SECOND), this, this, "createBlock",
371 null);
372
373 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(500, TimeUnit.SECOND), this, this, "removeBlock",
374 null);
375
376 for (int t = 1; t <= 1800; t++)
377 {
378 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(t - 0.001, TimeUnit.SECOND), this, this,
379 "drawGraph", null);
380 }
381 }
382 catch (RemoteException | SimRuntimeException exception)
383 {
384 exception.printStackTrace();
385 }
386 }
387
388
389
390
391
392
393 protected final void createBlock() throws RemoteException, NamingException, SimRuntimeException, NetworkException
394 {
395 DoubleScalar.Rel<LengthUnit> initialPosition = new DoubleScalar.Rel<LengthUnit>(4000, LengthUnit.METER);
396 Map<Lane, DoubleScalar.Rel<LengthUnit>> initialPositions = new HashMap<Lane, DoubleScalar.Rel<LengthUnit>>();
397 initialPositions.put(this.lane, initialPosition);
398 this.block =
399 new Car<Integer>(999999, null, null, initialPositions,
400 new DoubleScalar.Abs<SpeedUnit>(0, SpeedUnit.KM_PER_HOUR), new DoubleScalar.Rel<LengthUnit>(0.1,
401 LengthUnit.METER), new DoubleScalar.Rel<LengthUnit>(2, LengthUnit.METER),
402 new DoubleScalar.Abs<SpeedUnit>(0, SpeedUnit.KM_PER_HOUR), this.simulator);
403
404 }
405
406
407
408
409 protected final void removeBlock()
410 {
411 this.block = null;
412 }
413
414
415
416
417 protected final void generateCar()
418 {
419 boolean generateTruck = this.randomGenerator.nextDouble() > this.carProbability;
420 DoubleScalar.Rel<LengthUnit> initialPosition = new DoubleScalar.Rel<LengthUnit>(0, LengthUnit.METER);
421 Map<Lane, DoubleScalar.Rel<LengthUnit>> initialPositions = new HashMap<Lane, DoubleScalar.Rel<LengthUnit>>();
422 initialPositions.put(this.lane, initialPosition);
423 DoubleScalar.Abs<SpeedUnit> initialSpeed = new DoubleScalar.Abs<SpeedUnit>(100, SpeedUnit.KM_PER_HOUR);
424 try
425 {
426 DoubleScalar.Rel<LengthUnit> vehicleLength =
427 new DoubleScalar.Rel<LengthUnit>(generateTruck ? 15 : 4, LengthUnit.METER);
428 IDMCar car =
429 new IDMCar(++this.carsCreated, null, this.simulator, generateTruck ? this.carFollowingModelTrucks
430 : this.carFollowingModelCars, vehicleLength, this.simulator.getSimulatorTime().get(), initialPositions,
431 initialSpeed);
432 this.cars.add(0, car);
433
434 this.simulator.scheduleEventRel(this.headway, this, this, "generateCar", null);
435 }
436 catch (RemoteException | SimRuntimeException | NamingException | NetworkException exception)
437 {
438 exception.printStackTrace();
439 }
440 }
441
442
443 @Override
444 public final SimulatorInterface<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble> getSimulator()
445 throws RemoteException
446 {
447 return this.simulator;
448 }
449
450
451 protected class IDMCar extends Car<Integer>
452 {
453
454 private static final long serialVersionUID = 20141030L;
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470 public IDMCar(final int id, GTUType<String> gtuType, final OTSDEVSSimulatorInterface simulator,
471 final GTUFollowingModel carFollowingModel, DoubleScalar.Rel<LengthUnit> vehicleLength,
472 final DoubleScalar.Abs<TimeUnit> initialTime,
473 final Map<Lane, DoubleScalar.Rel<LengthUnit>> initialLongitudinalPositions,
474 final DoubleScalar.Abs<SpeedUnit> initialSpeed) throws RemoteException, NamingException, SimRuntimeException,
475 NetworkException
476 {
477 super(id, gtuType, carFollowingModel, initialLongitudinalPositions, initialSpeed, vehicleLength,
478 new DoubleScalar.Rel<LengthUnit>(1.8, LengthUnit.METER), new DoubleScalar.Abs<SpeedUnit>(200,
479 SpeedUnit.KM_PER_HOUR), simulator);
480 try
481 {
482 simulator.scheduleEventAbs(simulator.getSimulatorTime(), this, this, "move", null);
483 }
484 catch (SimRuntimeException exception)
485 {
486 exception.printStackTrace();
487 }
488 }
489
490
491
492
493
494
495 protected final void move() throws RemoteException, NetworkException, SimRuntimeException
496 {
497 Lane currentLane = positions(getFront()).keySet().iterator().next();
498
499 if (position(currentLane, getFront()).getSI() > getMaximumDistance().getSI())
500 {
501 TrajectoriesModel.this.cars.remove(this);
502 return;
503 }
504 Collection<Car<Integer>> leaders = new ArrayList<Car<Integer>>();
505
506
507 int carIndex = TrajectoriesModel.this.cars.indexOf(this);
508 if (carIndex < TrajectoriesModel.this.cars.size() - 1)
509 {
510 leaders.add(TrajectoriesModel.this.cars.get(carIndex + 1));
511 }
512 GTUFollowingModelResult cfmr =
513 getGTUFollowingModel().computeAcceleration(this, leaders, TrajectoriesModel.this.speedLimit);
514 if (null != TrajectoriesModel.this.block)
515 {
516 leaders.clear();
517 leaders.add(TrajectoriesModel.this.block);
518 if (position(currentLane, getFront()).getSI() > 3850 && position(currentLane, getFront()).getSI() < 4000
519 && getId() == 57 && getNextEvaluationTime().getSI() > 312)
520 {
521 System.out.println("Pas op; vehicle " + this);
522 }
523 GTUFollowingModelResult blockCFMR =
524 getGTUFollowingModel().computeAcceleration(this, leaders, TrajectoriesModel.this.speedLimit);
525 if (blockCFMR.getAcceleration().getSI() < cfmr.getAcceleration().getSI()
526 && blockCFMR.getAcceleration().getSI() >= -5)
527 {
528 cfmr = blockCFMR;
529 }
530 }
531 if (cfmr.getAcceleration().getSI() < -0.1)
532 {
533
534 }
535 setState(cfmr);
536
537
538 addToTrajectoryPlot(this);
539 getSimulator().scheduleEventRel(new DoubleScalar.Rel<TimeUnit>(0.5, TimeUnit.SECOND), this, this, "move", null);
540 }
541
542 }
543
544
545
546
547
548
549 final void addToTrajectoryPlot(final IDMCar idmCar) throws NetworkException, RemoteException
550 {
551 this.trajectoryPlot.addData(idmCar);
552 }
553
554
555
556
557 protected final void drawGraph()
558 {
559 this.trajectoryPlot.reGraph();
560 }
561
562
563
564
565 public final DoubleScalar.Rel<LengthUnit> getMinimumDistance()
566 {
567 return this.minimumDistance;
568 }
569
570
571
572
573 public final DoubleScalar.Rel<LengthUnit> getMaximumDistance()
574 {
575 return this.maximumDistance;
576 }
577
578
579
580
581 public final void setTrajectoryPlot(final TrajectoryPlot trajectoryPlot)
582 {
583 this.trajectoryPlot = trajectoryPlot;
584 }
585
586 }