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