1 package org.opentrafficsim.demo.carFollowing;
2
3 import java.awt.Container;
4 import java.awt.Frame;
5 import java.awt.geom.Rectangle2D;
6 import java.rmi.RemoteException;
7 import java.util.ArrayList;
8 import java.util.HashSet;
9 import java.util.Iterator;
10 import java.util.LinkedHashSet;
11 import java.util.List;
12 import java.util.Random;
13 import java.util.Set;
14
15 import javax.naming.NamingException;
16 import javax.swing.JPanel;
17 import javax.swing.SwingUtilities;
18
19 import org.djunits.unit.TimeUnit;
20 import org.djunits.unit.UNITS;
21 import org.djunits.value.vdouble.scalar.Acceleration;
22 import org.djunits.value.vdouble.scalar.DoubleScalar;
23 import org.djunits.value.vdouble.scalar.DoubleScalar.Abs;
24 import org.djunits.value.vdouble.scalar.DoubleScalar.Rel;
25 import org.djunits.value.vdouble.scalar.Duration;
26 import org.djunits.value.vdouble.scalar.Length;
27 import org.djunits.value.vdouble.scalar.Speed;
28 import org.djunits.value.vdouble.scalar.Time;
29 import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
30 import org.opentrafficsim.core.dsol.OTSModelInterface;
31 import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
32 import org.opentrafficsim.core.geometry.OTSGeometryException;
33 import org.opentrafficsim.core.geometry.OTSPoint3D;
34 import org.opentrafficsim.core.gtu.GTU;
35 import org.opentrafficsim.core.gtu.GTUDirectionality;
36 import org.opentrafficsim.core.gtu.GTUException;
37 import org.opentrafficsim.core.gtu.GTUType;
38 import org.opentrafficsim.core.gtu.animation.GTUColorer;
39 import org.opentrafficsim.core.gtu.behavioralcharacteristics.BehavioralCharacteristics;
40 import org.opentrafficsim.core.network.LongitudinalDirectionality;
41 import org.opentrafficsim.core.network.NetworkException;
42 import org.opentrafficsim.core.network.OTSNetwork;
43 import org.opentrafficsim.core.network.OTSNode;
44 import org.opentrafficsim.graphs.AccelerationContourPlot;
45 import org.opentrafficsim.graphs.ContourPlot;
46 import org.opentrafficsim.graphs.DensityContourPlot;
47 import org.opentrafficsim.graphs.FlowContourPlot;
48 import org.opentrafficsim.graphs.LaneBasedGTUSampler;
49 import org.opentrafficsim.graphs.SpeedContourPlot;
50 import org.opentrafficsim.graphs.TrajectoryPlot;
51 import org.opentrafficsim.imb.observers.IMBTransmitter;
52 import org.opentrafficsim.road.gtu.animation.DefaultCarAnimation;
53 import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
54 import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedCFLCTacticalPlannerFactory;
55 import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedGTUFollowingChange0TacticalPlannerFactory;
56 import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedGTUFollowingLaneChangeTacticalPlannerFactory;
57 import org.opentrafficsim.road.gtu.lane.tactical.following.AbstractIDM;
58 import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
59 import org.opentrafficsim.road.gtu.lane.tactical.following.IDMOld;
60 import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlus;
61 import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusOld;
62 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.AbstractLaneChangeModel;
63 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.Altruistic;
64 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.Egoistic;
65 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LMRSFactory;
66 import org.opentrafficsim.road.gtu.lane.tactical.toledo.ToledoFactory;
67 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
68 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
69 import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlannerFactory;
70 import org.opentrafficsim.road.network.factory.LaneFactory;
71 import org.opentrafficsim.road.network.lane.DirectedLanePosition;
72 import org.opentrafficsim.road.network.lane.Lane;
73 import org.opentrafficsim.road.network.lane.LaneType;
74 import org.opentrafficsim.simulationengine.AbstractWrappableAnimation;
75 import org.opentrafficsim.simulationengine.OTSSimulationException;
76 import org.opentrafficsim.simulationengine.properties.AbstractProperty;
77 import org.opentrafficsim.simulationengine.properties.BooleanProperty;
78 import org.opentrafficsim.simulationengine.properties.CompoundProperty;
79 import org.opentrafficsim.simulationengine.properties.ContinuousProperty;
80 import org.opentrafficsim.simulationengine.properties.IDMPropertySet;
81 import org.opentrafficsim.simulationengine.properties.IntegerProperty;
82 import org.opentrafficsim.simulationengine.properties.ProbabilityDistributionProperty;
83 import org.opentrafficsim.simulationengine.properties.PropertyException;
84 import org.opentrafficsim.simulationengine.properties.SelectionProperty;
85
86 import nl.tudelft.simulation.dsol.SimRuntimeException;
87 import nl.tudelft.simulation.dsol.gui.swing.TablePanel;
88 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
89 import nl.tudelft.simulation.event.EventInterface;
90 import nl.tudelft.simulation.event.EventListenerInterface;
91 import nl.tudelft.simulation.event.EventProducer;
92
93
94
95
96
97
98
99
100
101
102
103 public class CircularRoadIMB extends AbstractWrappableAnimation implements UNITS
104 {
105
106 private static final long serialVersionUID = 1L;
107
108
109 private RoadSimulationModelIMB model;
110
111
112
113
114
115 public CircularRoadIMB() throws PropertyException
116 {
117 this.properties.add(new SelectionProperty("LaneChanging", "Lane changing",
118 "<html>The lane change strategies vary in politeness.<br>"
119 + "Two types are implemented:<ul><li>Egoistic (looks only at personal gain).</li>"
120 + "<li>Altruistic (assigns effect on new and current follower the same weight as "
121 + "the personal gain).</html>",
122 new String[] { "Egoistic", "Altruistic" }, 0, false, 500));
123 this.properties.add(new SelectionProperty("TacticalPlanner", "Tactical planner",
124 "<html>The tactical planner determines if a lane change is desired and possible.</html>",
125 new String[] { "MOBIL", "Verbraeck", "Verbraeck0", "LMRS", "Toledo" }, 0, false, 600));
126 this.properties.add(new IntegerProperty("TrackLength", "Track length", "Circumference of the track", 2000, 500, 6000,
127 "Track length %dm", false, 10));
128 this.properties.add(new ContinuousProperty("MeanDensity", "Mean density", "Number of vehicles per km", 40.0, 5.0, 45.0,
129 "Density %.1f veh/km", false, 11));
130 this.properties.add(new ContinuousProperty("DensityVariability", "Density variability",
131 "Variability of the number of vehicles per km", 0.0, 0.0, 1.0, "%.1f", false, 12));
132 ArrayList<AbstractProperty<?>> outputProperties = new ArrayList<AbstractProperty<?>>();
133 for (int lane = 1; lane <= 2; lane++)
134 {
135 String laneId = String.format("Lane %d ", lane);
136 outputProperties.add(new BooleanProperty(laneId + "Density", laneId + " Density", laneId + "Density contour plot",
137 true, false, 0));
138 outputProperties
139 .add(new BooleanProperty(laneId + "Flow", laneId + " Flow", laneId + "Flow contour plot", true, false, 1));
140 outputProperties.add(
141 new BooleanProperty(laneId + "Speed", laneId + " Speed", laneId + "Speed contour plot", true, false, 2));
142 outputProperties.add(new BooleanProperty(laneId + "Acceleration", laneId + " Acceleration",
143 laneId + "Acceleration contour plot", true, false, 3));
144 outputProperties.add(new BooleanProperty(laneId + "Trajectories", laneId + " Trajectories",
145 laneId + "Trajectory (time/distance) diagram", true, false, 4));
146 }
147 this.properties.add(new CompoundProperty("OutputGraphs", "Output graphs", "Select the graphical output",
148 outputProperties, true, 1000));
149 }
150
151
152 @Override
153 public final void stopTimersThreads()
154 {
155 super.stopTimersThreads();
156 this.model = null;
157 }
158
159
160
161
162
163
164 public static void main(final String[] args) throws SimRuntimeException
165 {
166 SwingUtilities.invokeLater(new Runnable()
167 {
168 @Override
169 public void run()
170 {
171 try
172 {
173 CircularRoadIMB circularRoad = new CircularRoadIMB();
174 ArrayList<AbstractProperty<?>> propertyList = circularRoad.getProperties();
175 try
176 {
177 propertyList.add(new ProbabilityDistributionProperty("TrafficComposition", "Traffic composition",
178 "<html>Mix of passenger cars and trucks</html>", new String[] { "passenger car", "truck" },
179 new Double[] { 0.8, 0.2 }, false, 10));
180 }
181 catch (PropertyException exception)
182 {
183 exception.printStackTrace();
184 }
185 propertyList.add(new SelectionProperty("CarFollowingModel", "Car following model",
186 "<html>The car following model determines "
187 + "the acceleration that a vehicle will make taking into account "
188 + "nearby vehicles, infrastructural restrictions (e.g. speed limit, "
189 + "curvature of the road) capabilities of the vehicle and personality "
190 + "of the driver.</html>",
191 new String[] { "IDM", "IDM+" }, 1, false, 1));
192 propertyList.add(IDMPropertySet.makeIDMPropertySet("IDMCar", "Car",
193 new Acceleration(1.0, METER_PER_SECOND_2), new Acceleration(1.5, METER_PER_SECOND_2),
194 new Length(2.0, METER), new Duration(1.0, SECOND), 2));
195 propertyList.add(IDMPropertySet.makeIDMPropertySet("IDMTruck", "Truck",
196 new Acceleration(0.5, METER_PER_SECOND_2), new Acceleration(1.25, METER_PER_SECOND_2),
197 new Length(2.0, METER), new Duration(1.0, SECOND), 3));
198
199 circularRoad.buildAnimator(new Time(0.0, SECOND), new Duration(0.0, SECOND), new Duration(3600.0, SECOND),
200 propertyList, null, true);
201 }
202 catch (SimRuntimeException | NamingException | OTSSimulationException | PropertyException exception)
203 {
204 exception.printStackTrace();
205 }
206 }
207 });
208 }
209
210
211 @Override
212 protected final OTSModelInterface makeModel(final GTUColorer colorer)
213 {
214 this.model = new RoadSimulationModelIMB(getSavedUserModifiedProperties(), colorer);
215 return this.model;
216 }
217
218
219
220
221 private ArrayList<AbstractProperty<?>> getSavedUserModifiedProperties()
222 {
223 return this.savedUserModifiedProperties;
224 }
225
226
227 @Override
228 protected final Rectangle2D.Double makeAnimationRectangle()
229 {
230 return new Rectangle2D.Double(-350, -350, 700, 700);
231 }
232
233
234 @Override
235 protected final JPanel makeCharts() throws OTSSimulationException, PropertyException
236 {
237
238 AbstractProperty<?> output = new CompoundProperty("", "", "", this.properties, false, 0).findByKey("OutputGraphs");
239 if (null == output)
240 {
241 throw new Error("Cannot find output properties");
242 }
243 ArrayList<BooleanProperty> graphs = new ArrayList<BooleanProperty>();
244 if (output instanceof CompoundProperty)
245 {
246 CompoundProperty outputProperties = (CompoundProperty) output;
247 for (AbstractProperty<?> ap : outputProperties.getValue())
248 {
249 if (ap instanceof BooleanProperty)
250 {
251 BooleanProperty bp = (BooleanProperty) ap;
252 if (bp.getValue())
253 {
254 graphs.add(bp);
255 }
256 }
257 }
258 }
259 else
260 {
261 throw new Error("output properties should be compound");
262 }
263
264 int graphCount = graphs.size();
265 int columns = (int) Math.ceil(Math.sqrt(graphCount));
266 int rows = 0 == columns ? 0 : (int) Math.ceil(graphCount * 1.0 / columns);
267 TablePanel charts = new TablePanel(columns, rows);
268
269 for (int i = 0; i < graphCount; i++)
270 {
271 String graphName = graphs.get(i).getKey();
272 Container container = null;
273 LaneBasedGTUSampler graph;
274 int pos = graphName.indexOf(' ') + 1;
275 String laneNumberText = graphName.substring(pos, pos + 1);
276 int lane = Integer.parseInt(laneNumberText) - 1;
277
278 if (graphName.contains("Trajectories"))
279 {
280 TrajectoryPlot tp = new TrajectoryPlot(graphName, new Duration(0.5, SECOND), this.model.getPath(lane));
281 tp.setTitle("Trajectory Graph");
282 tp.setExtendedState(Frame.MAXIMIZED_BOTH);
283 graph = tp;
284 container = tp.getContentPane();
285 }
286 else
287 {
288 ContourPlot cp;
289 if (graphName.contains("Density"))
290 {
291 cp = new DensityContourPlot(graphName, this.model.getPath(lane));
292 cp.setTitle("Density Contour Graph");
293 }
294 else if (graphName.contains("Speed"))
295 {
296 cp = new SpeedContourPlot(graphName, this.model.getPath(lane));
297 cp.setTitle("Speed Contour Graph");
298 }
299 else if (graphName.contains("Flow"))
300 {
301 cp = new FlowContourPlot(graphName, this.model.getPath(lane));
302 cp.setTitle("Flow Contour Graph");
303 }
304 else if (graphName.contains("Acceleration"))
305 {
306 cp = new AccelerationContourPlot(graphName, this.model.getPath(lane));
307 cp.setTitle("Acceleration Contour Graph");
308 }
309 else
310 {
311 throw new Error("Unhandled type of contourplot: " + graphName);
312 }
313 graph = cp;
314 container = cp.getContentPane();
315 }
316
317 charts.setCell(container, i % columns, i / columns);
318 this.model.getPlots().add(graph);
319 }
320
321 return charts;
322 }
323
324
325 @Override
326 public final String shortName()
327 {
328 return "Circular Road simulation";
329 }
330
331
332 @Override
333 public final String description()
334 {
335 return "<html><h1>Circular Road simulation</h1>" + "Vehicles are unequally distributed over a two lane ring road.<br>"
336 + "When simulation starts, all vehicles begin driving, some lane changes will occurr and some "
337 + "shockwaves should develop.<br>"
338 + "Trajectories and contourplots are generated during the simulation for both lanes.</html>";
339 }
340
341 }
342
343
344
345
346
347
348
349
350
351
352
353 class RoadSimulationModelIMB implements OTSModelInterface, UNITS
354 {
355
356 private static final long serialVersionUID = 20141121L;
357
358
359 private OTSDEVSSimulatorInterface simulator;
360
361
362 private OTSNetwork network = new OTSNetwork("network");
363
364
365 private int carsCreated = 0;
366
367
368 private GTUFollowingModelOld carFollowingModelCars;
369
370
371 private GTUFollowingModelOld carFollowingModelTrucks;
372
373
374 private double carProbability;
375
376
377 private AbstractLaneChangeModel laneChangeModel;
378
379
380 private Length minimumDistance = new Length(0, METER);
381
382
383 private Speed speedLimit = new Speed(100, KM_PER_HOUR);
384
385
386 private ArrayList<LaneBasedGTUSampler> plots = new ArrayList<LaneBasedGTUSampler>();
387
388
389 private ArrayList<AbstractProperty<?>> properties = null;
390
391
392 private ArrayList<List<Lane>> paths = new ArrayList<List<Lane>>();
393
394
395 private Random randomGenerator = new Random(12345);
396
397
398 private final GTUColorer gtuColorer;
399
400
401 private LaneBasedStrategicalPlannerFactory<LaneBasedStrategicalPlanner> strategicalPlannerGeneratorCars = null;
402
403
404 private LaneBasedStrategicalPlannerFactory<LaneBasedStrategicalPlanner> strategicalPlannerGeneratorTrucks = null;
405
406
407 private final CarListener carListener = new CarListener();
408
409
410 private final IMBTransmitter imbTransmitter = new IMBTransmitter();
411
412
413
414
415
416 public RoadSimulationModelIMB(final ArrayList<AbstractProperty<?>> properties, final GTUColorer gtuColorer)
417 {
418 this.properties = properties;
419 this.gtuColorer = gtuColorer;
420 }
421
422
423
424
425
426 public List<Lane> getPath(final int index)
427 {
428 return this.paths.get(index);
429 }
430
431
432 @Override
433 public void constructModel(final SimulatorInterface<Abs<TimeUnit>, Rel<TimeUnit>, OTSSimTimeDouble> theSimulator)
434 throws SimRuntimeException, RemoteException
435 {
436 final int laneCount = 2;
437 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
438 {
439 this.paths.add(new ArrayList<Lane>());
440 }
441 this.simulator = (OTSDEVSSimulatorInterface) theSimulator;
442 double radius = 6000 / 2 / Math.PI;
443 double headway = 40;
444 double headwayVariability = 0;
445 try
446 {
447
448
449 String carFollowingModelName = null;
450 CompoundProperty propertyContainer = new CompoundProperty("", "", "", this.properties, false, 0);
451 AbstractProperty<?> cfmp = propertyContainer.findByKey("CarFollowingModel");
452 if (null == cfmp)
453 {
454 throw new Error("Cannot find \"Car following model\" property");
455 }
456 if (cfmp instanceof SelectionProperty)
457 {
458 carFollowingModelName = ((SelectionProperty) cfmp).getValue();
459 }
460 else
461 {
462 throw new Error("\"Car following model\" property has wrong type");
463 }
464
465
466 Iterator<AbstractProperty<List<AbstractProperty<?>>>> iterator =
467 new CompoundProperty("", "", "", this.properties, false, 0).iterator();
468 while (iterator.hasNext())
469 {
470 AbstractProperty<?> ap = iterator.next();
471 if (ap instanceof CompoundProperty)
472 {
473 CompoundProperty cp = (CompoundProperty) ap;
474 System.out.println("Checking compound property " + cp);
475 if (ap.getKey().contains("IDM"))
476 {
477 System.out.println("Car following model name appears to be " + ap.getKey());
478 Acceleration a = IDMPropertySet.getA(cp);
479 Acceleration b = IDMPropertySet.getB(cp);
480 Length s0 = IDMPropertySet.getS0(cp);
481 Duration tSafe = IDMPropertySet.getTSafe(cp);
482 GTUFollowingModelOld gtuFollowingModel = null;
483 if (carFollowingModelName.equals("IDM"))
484 {
485 gtuFollowingModel = new IDMOld(a, b, s0, tSafe, 1.0);
486 }
487 else if (carFollowingModelName.equals("IDM+"))
488 {
489 gtuFollowingModel = new IDMPlusOld(a, b, s0, tSafe, 1.0);
490 }
491 else
492 {
493 throw new Error("Unknown gtu following model: " + carFollowingModelName);
494 }
495 if (ap.getKey().contains("Car"))
496 {
497 this.carFollowingModelCars = gtuFollowingModel;
498 }
499 else if (ap.getKey().contains("Truck"))
500 {
501 this.carFollowingModelTrucks = gtuFollowingModel;
502 }
503 else
504 {
505 throw new Error("Cannot determine gtu type for " + ap.getKey());
506 }
507 }
508 }
509 }
510
511
512 cfmp = propertyContainer.findByKey("LaneChanging");
513 if (null == cfmp)
514 {
515 throw new Error("Cannot find \"Lane changing\" property");
516 }
517 if (cfmp instanceof SelectionProperty)
518 {
519 String laneChangeModelName = ((SelectionProperty) cfmp).getValue();
520 if ("Egoistic".equals(laneChangeModelName))
521 {
522 this.laneChangeModel = new Egoistic();
523 }
524 else if ("Altruistic".equals(laneChangeModelName))
525 {
526 this.laneChangeModel = new Altruistic();
527 }
528 else
529 {
530 throw new Error("Lane changing " + laneChangeModelName + " not implemented");
531 }
532 }
533 else
534 {
535 throw new Error("\"Lane changing\" property has wrong type");
536 }
537
538
539 iterator = new CompoundProperty("", "", "", this.properties, false, 0).iterator();
540 while (iterator.hasNext())
541 {
542 AbstractProperty<?> ap = iterator.next();
543 if (ap instanceof SelectionProperty)
544 {
545 SelectionProperty sp = (SelectionProperty) ap;
546 if ("TacticalPlanner".equals(sp.getKey()))
547 {
548 String tacticalPlannerName = sp.getValue();
549 if ("MOBIL".equals(tacticalPlannerName))
550 {
551 this.strategicalPlannerGeneratorCars = new LaneBasedStrategicalRoutePlannerFactory(
552 new LaneBasedCFLCTacticalPlannerFactory(this.carFollowingModelCars, this.laneChangeModel));
553 this.strategicalPlannerGeneratorTrucks =
554 new LaneBasedStrategicalRoutePlannerFactory(new LaneBasedCFLCTacticalPlannerFactory(
555 this.carFollowingModelTrucks, this.laneChangeModel));
556 }
557 else if ("Verbraeck".equals(tacticalPlannerName))
558 {
559 this.strategicalPlannerGeneratorCars = new LaneBasedStrategicalRoutePlannerFactory(
560 new LaneBasedGTUFollowingLaneChangeTacticalPlannerFactory(this.carFollowingModelCars));
561 this.strategicalPlannerGeneratorTrucks = new LaneBasedStrategicalRoutePlannerFactory(
562 new LaneBasedGTUFollowingLaneChangeTacticalPlannerFactory(this.carFollowingModelTrucks));
563 }
564 else if ("Verbraeck0".equals(tacticalPlannerName))
565 {
566 this.strategicalPlannerGeneratorCars = new LaneBasedStrategicalRoutePlannerFactory(
567 new LaneBasedGTUFollowingChange0TacticalPlannerFactory(this.carFollowingModelCars));
568 this.strategicalPlannerGeneratorTrucks = new LaneBasedStrategicalRoutePlannerFactory(
569 new LaneBasedGTUFollowingChange0TacticalPlannerFactory(this.carFollowingModelTrucks));
570 }
571 else if ("LMRS".equals(tacticalPlannerName))
572 {
573
574 BehavioralCharacteristics defaultBehavioralCFCharacteristics = new BehavioralCharacteristics();
575 defaultBehavioralCFCharacteristics.setDefaultParameters(AbstractIDM.class);
576 this.strategicalPlannerGeneratorCars = new LaneBasedStrategicalRoutePlannerFactory(
577 new LMRSFactory(IDMPlus.class, defaultBehavioralCFCharacteristics));
578 this.strategicalPlannerGeneratorTrucks = new LaneBasedStrategicalRoutePlannerFactory(
579 new LMRSFactory(IDMPlus.class, defaultBehavioralCFCharacteristics));
580 }
581 else if ("Toledo".equals(tacticalPlannerName))
582 {
583 this.strategicalPlannerGeneratorCars =
584 new LaneBasedStrategicalRoutePlannerFactory(new ToledoFactory());
585 this.strategicalPlannerGeneratorTrucks =
586 new LaneBasedStrategicalRoutePlannerFactory(new ToledoFactory());
587 }
588 else
589 {
590 throw new Error("Don't know how to create a " + tacticalPlannerName + " tactical planner");
591 }
592 }
593 }
594 else if (ap instanceof ProbabilityDistributionProperty)
595 {
596 ProbabilityDistributionProperty pdp = (ProbabilityDistributionProperty) ap;
597 if (ap.getKey().equals("TrafficComposition"))
598 {
599 this.carProbability = pdp.getValue()[0];
600 }
601 }
602 else if (ap instanceof IntegerProperty)
603 {
604 IntegerProperty ip = (IntegerProperty) ap;
605 if ("TrackLength".equals(ip.getKey()))
606 {
607 radius = ip.getValue() / 2 / Math.PI;
608 }
609 }
610 else if (ap instanceof ContinuousProperty)
611 {
612 ContinuousProperty cp = (ContinuousProperty) ap;
613 if (cp.getKey().equals("MeanDensity"))
614 {
615 headway = 1000 / cp.getValue();
616 }
617 if (cp.getKey().equals("DensityVariability"))
618 {
619 headwayVariability = cp.getValue();
620 }
621 }
622 else if (ap instanceof CompoundProperty)
623 {
624 if (ap.getKey().equals("OutputGraphs"))
625 {
626 continue;
627 }
628 }
629 }
630 GTUType gtuType = new GTUType("car");
631 Set<GTUType> compatibility = new HashSet<GTUType>();
632 compatibility.add(gtuType);
633 LaneType laneType = new LaneType("CarLane", compatibility);
634 OTSNode start = new OTSNode("Start", new OTSPoint3D(radius, 0, 0));
635 OTSNode halfway = new OTSNode("Halfway", new OTSPoint3D(-radius, 0, 0));
636
637 OTSPoint3D[] coordsHalf1 = new OTSPoint3D[127];
638 for (int i = 0; i < coordsHalf1.length; i++)
639 {
640 double angle = Math.PI * (1 + i) / (1 + coordsHalf1.length);
641 coordsHalf1[i] = new OTSPoint3D(radius * Math.cos(angle), radius * Math.sin(angle), 0);
642 }
643 Lane[] lanes1 = LaneFactory.makeMultiLane("FirstHalf", start, halfway, coordsHalf1, laneCount, laneType,
644 this.speedLimit, this.simulator, LongitudinalDirectionality.DIR_PLUS);
645 OTSPoint3D[] coordsHalf2 = new OTSPoint3D[127];
646 for (int i = 0; i < coordsHalf2.length; i++)
647 {
648 double angle = Math.PI + Math.PI * (1 + i) / (1 + coordsHalf2.length);
649 coordsHalf2[i] = new OTSPoint3D(radius * Math.cos(angle), radius * Math.sin(angle), 0);
650 }
651 Lane[] lanes2 = LaneFactory.makeMultiLane("SecondHalf", halfway, start, coordsHalf2, laneCount, laneType,
652 this.speedLimit, this.simulator, LongitudinalDirectionality.DIR_PLUS);
653 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
654 {
655 this.paths.get(laneIndex).add(lanes1[laneIndex]);
656 this.paths.get(laneIndex).add(lanes2[laneIndex]);
657 }
658
659 double variability = (headway - 20) * headwayVariability;
660 System.out.println("headway is " + headway + " variability limit is " + variability);
661 Random random = new Random(12345);
662 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
663 {
664 double lane1Length = lanes1[laneIndex].getLength().getSI();
665 double trackLength = lane1Length + lanes2[laneIndex].getLength().getSI();
666 for (double pos = 0; pos <= trackLength - headway - variability;)
667 {
668 Lane lane = pos >= lane1Length ? lanes2[laneIndex] : lanes1[laneIndex];
669
670 double laneRelativePos = pos > lane1Length ? pos - lane1Length : pos;
671 double actualHeadway = headway + (random.nextDouble() * 2 - 1) * variability;
672
673 generateCar(new Length(laneRelativePos, METER), lane, gtuType);
674 pos += actualHeadway;
675 }
676 }
677
678 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(9.999, SECOND), this, this, "drawGraphs", null);
679 }
680 catch (SimRuntimeException | NamingException | NetworkException | GTUException | OTSGeometryException
681 | PropertyException exception)
682 {
683 exception.printStackTrace();
684 }
685 }
686
687
688
689
690 protected final void drawGraphs()
691 {
692 for (LaneBasedGTUSampler plot : this.plots)
693 {
694 plot.reGraph();
695 }
696
697 try
698 {
699 this.simulator.scheduleEventAbs(new Time(this.simulator.getSimulatorTime().get().getSI() + 10, SECOND), this, this,
700 "drawGraphs", null);
701 }
702 catch (SimRuntimeException exception)
703 {
704 exception.printStackTrace();
705 }
706
707 }
708
709
710
711
712
713
714
715
716
717
718
719
720 protected final void generateCar(final Length initialPosition, final Lane lane, final GTUType gtuType)
721 throws NamingException, NetworkException, SimRuntimeException, GTUException, OTSGeometryException
722 {
723
724
725 boolean generateTruck = this.randomGenerator.nextDouble() > this.carProbability;
726 Length vehicleLength = new Length(generateTruck ? 15 : 4, METER);
727 LaneBasedIndividualGTU gtu =
728 new LaneBasedIndividualGTU("" + (++this.carsCreated), gtuType, vehicleLength, new Length(1.8, METER),
729 new Speed(200, KM_PER_HOUR), this.simulator, DefaultCarAnimation.class, this.gtuColorer, this.network);
730
731
732 gtu.addListener(this.carListener, GTU.INIT_EVENT, true);
733 gtu.addListener(this.carListener, GTU.MOVE_EVENT, true);
734 gtu.addListener(this.carListener, GTU.DESTROY_EVENT, true);
735
736
737 gtu.addListener(this.imbTransmitter, GTU.INIT_EVENT, true);
738 gtu.addListener(this.imbTransmitter, GTU.MOVE_EVENT, true);
739 gtu.addListener(this.imbTransmitter, GTU.DESTROY_EVENT, true);
740
741
742 LaneBasedStrategicalPlanner strategicalPlanner;
743 if (!generateTruck)
744 {
745 strategicalPlanner = this.strategicalPlannerGeneratorCars.create(gtu);
746 }
747 else
748 {
749 strategicalPlanner = this.strategicalPlannerGeneratorTrucks.create(gtu);
750 }
751
752
753 Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
754 initialPositions.add(new DirectedLanePosition(lane, initialPosition, GTUDirectionality.DIR_PLUS));
755 Speed initialSpeed = new Speed(0, KM_PER_HOUR);
756 gtu.init(strategicalPlanner, initialPositions, initialSpeed);
757 }
758
759
760 @Override
761 public SimulatorInterface<Abs<TimeUnit>, Rel<TimeUnit>, OTSSimTimeDouble> getSimulator() throws RemoteException
762 {
763 return this.simulator;
764 }
765
766
767
768
769 public final ArrayList<LaneBasedGTUSampler> getPlots()
770 {
771 return this.plots;
772 }
773
774
775
776
777 public final Length getMinimumDistance()
778 {
779 return this.minimumDistance;
780 }
781
782
783
784
785
786
787 public void stopSimulator(final OTSDEVSSimulatorInterface theSimulator, final String errorMessage)
788 {
789 System.out.println("Error: " + errorMessage);
790 try
791 {
792 if (theSimulator.isRunning())
793 {
794 theSimulator.stop();
795 }
796 }
797 catch (SimRuntimeException exception)
798 {
799 exception.printStackTrace();
800 }
801 throw new Error(errorMessage);
802 }
803
804
805 protected static class CarListener extends EventProducer implements EventListenerInterface
806 {
807
808 private static final long serialVersionUID = 1L;
809
810
811
812 @Override
813 public void notify(final EventInterface event) throws RemoteException
814 {
815 if (event.getType().equals(GTU.INIT_EVENT))
816 {
817 Object[] initInfo = (Object[]) event.getContent();
818 System.out.println("GTU " + initInfo[0] + " created");
819 }
820 else if (event.getType().equals(GTU.MOVE_EVENT))
821 {
822 Object[] moveInfo = (Object[]) event.getContent();
823 System.out.println(
824 "GTU " + moveInfo[0] + " moved to " + moveInfo[1] + ", v=" + moveInfo[2] + ", a=" + moveInfo[3]);
825 }
826 else if (event.getType().equals(GTU.DESTROY_EVENT))
827 {
828 Object[] destroyInfo = (Object[]) event.getContent();
829 System.out.println(
830 "GTU " + destroyInfo[0] + " destroyed at position " + destroyInfo[1] + ", odometer=" + destroyInfo[2]);
831 }
832 else
833 {
834 System.err.println("Unrecognized event of type " + event.getType());
835 }
836 }
837 }
838
839 }