1 package org.opentrafficsim.graphs;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertFalse;
5 import static org.junit.Assert.assertTrue;
6 import static org.junit.Assert.fail;
7 import static org.opentrafficsim.road.gtu.lane.RoadGTUTypes.CAR;
8
9 import java.awt.Component;
10 import java.awt.Container;
11 import java.awt.event.ActionEvent;
12 import java.awt.event.MouseListener;
13 import java.util.HashSet;
14 import java.util.LinkedHashSet;
15 import java.util.Set;
16
17 import javax.swing.JLabel;
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.Duration;
23 import org.djunits.value.vdouble.scalar.Length;
24 import org.djunits.value.vdouble.scalar.Speed;
25 import org.djunits.value.vdouble.scalar.Time;
26 import org.jfree.chart.ChartPanel;
27 import org.junit.Test;
28 import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
29 import org.opentrafficsim.core.dsol.OTSModelInterface;
30 import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
31 import org.opentrafficsim.core.gtu.GTUDirectionality;
32 import org.opentrafficsim.core.gtu.GTUType;
33 import org.opentrafficsim.core.gtu.behavioralcharacteristics.BehavioralCharacteristics;
34 import org.opentrafficsim.core.network.OTSNetwork;
35 import org.opentrafficsim.road.DefaultTestParameters;
36 import org.opentrafficsim.road.car.CarTest;
37 import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
38 import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedCFLCTacticalPlanner;
39 import org.opentrafficsim.road.gtu.lane.tactical.following.FixedAccelerationModel;
40 import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
41 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.Egoistic;
42 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.LaneChangeModel;
43 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
44 import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlanner;
45 import org.opentrafficsim.road.network.lane.DirectedLanePosition;
46 import org.opentrafficsim.road.network.lane.Lane;
47 import org.opentrafficsim.road.network.lane.LaneType;
48 import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
49 import org.opentrafficsim.simulationengine.SimpleSimulator;
50
51 import nl.tudelft.simulation.dsol.SimRuntimeException;
52 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
53
54
55
56
57
58
59
60
61
62
63 public class FundamentalDiagramPlotTest implements OTSModelInterface, UNITS
64 {
65
66 private static final long serialVersionUID = 20150226L;
67
68
69 private OTSNetwork network = new OTSNetwork("network");
70
71
72 private OTSDEVSSimulatorInterface simulator;
73
74
75
76
77
78 @SuppressWarnings("static-method")
79
80 public final void fundamentalDiagramTest() throws Exception
81 {
82 this.simulator = new SimpleSimulator(new Time(0, TimeUnit.BASE_SECOND), new Duration(0, SECOND),
83 new Duration(1800, SECOND), this);
84
85 Duration aggregationTime = new Duration(30, SECOND);
86 Length position = new Length(123, METER);
87 Length carPosition = new Length(122.5, METER);
88 GTUType gtuType = CAR;
89 Set<GTUType> compatibility = new HashSet<GTUType>();
90 compatibility.add(gtuType);
91 LaneType laneType = new LaneType("CarLane", compatibility);
92 Lane lane = CarTest.makeLane(this.network, laneType);
93 FundamentalDiagram fd = new FundamentalDiagram("Fundamental Diagram", aggregationTime, lane, position, this.simulator);
94 assertEquals("SeriesCount should match numberOfLanes", 1, fd.getSeriesCount());
95 assertEquals("Position should match the supplied position", position.getSI(), fd.getPosition().getSI(), 0.0001);
96 try
97 {
98 fd.getXValue(-1, 0);
99 fail("Bad series should have thrown an Error");
100 }
101 catch (Error e)
102 {
103
104 }
105 try
106 {
107 fd.getXValue(1, 0);
108 fail("Bad series should have thrown an Error");
109 }
110 catch (Error e)
111 {
112
113 }
114 double value = fd.getXValue(0, 0);
115 assertTrue("No data should result in NaN", java.lang.Double.isNaN(value));
116 value = fd.getX(0, 0).doubleValue();
117 assertTrue("No data should result in NaN", java.lang.Double.isNaN(value));
118 value = fd.getYValue(0, 0);
119 assertTrue("No data should result in NaN", java.lang.Double.isNaN(value));
120 value = fd.getY(0, 0).doubleValue();
121 assertTrue("No data should result in NaN", java.lang.Double.isNaN(value));
122 ActionEvent setXToSpeed = new ActionEvent(fd, 0, "Speed/Speed");
123 ActionEvent resetAxis = new ActionEvent(fd, 0, "Flow/Density");
124 Speed speed = new Speed(100, KM_PER_HOUR);
125 Time time = new Time(123, TimeUnit.BASE_SECOND);
126 Length length = new Length(5.0, METER);
127 Length width = new Length(2.0, METER);
128 Speed maxSpeed = new Speed(120, KM_PER_HOUR);
129 Set<DirectedLanePosition> initialLongitudinalPositions = new LinkedHashSet<>(1);
130 initialLongitudinalPositions.add(new DirectedLanePosition(lane, carPosition, GTUDirectionality.DIR_PLUS));
131
132
133 new SinkSensor(lane, new Length(lane.getLength().getSI() - 100, METER), simulator);
134
135 simulator.runUpTo(time);
136 while (simulator.isRunning())
137 {
138 try
139 {
140 Thread.sleep(1);
141 }
142 catch (InterruptedException ie)
143 {
144 ie = null;
145 }
146 }
147 int bucket = (int) Math.floor(time.getSI() / aggregationTime.getSI());
148 LaneChangeModel laneChangeModel = new Egoistic();
149 GTUFollowingModelOld gtuFollowingModel =
150 new FixedAccelerationModel(new Acceleration(0, METER_PER_SECOND_2), new Duration(1000, SECOND));
151
152 BehavioralCharacteristics behavioralCharacteristics = DefaultTestParameters.create();
153 LaneBasedIndividualGTU gtu = new LaneBasedIndividualGTU("1", gtuType, length, width, maxSpeed, simulator, this.network);
154 LaneBasedStrategicalPlanner strategicalPlanner = new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics,
155 new LaneBasedCFLCTacticalPlanner(gtuFollowingModel, laneChangeModel, gtu), gtu);
156 gtu.init(strategicalPlanner, initialLongitudinalPositions, speed);
157 simulator.runUpTo(new Time(124, TimeUnit.BASE_SECOND));
158 while (simulator.isRunning())
159 {
160 try
161 {
162 Thread.sleep(1);
163 }
164 catch (InterruptedException ie)
165 {
166 ie = null;
167 }
168 }
169 for (int sample = 0; sample < 10; sample++)
170 {
171 boolean shouldHaveData = sample == bucket;
172 value = fd.getXValue(0, sample);
173
174 if (shouldHaveData)
175 {
176 double expectedDensity = 3600 / aggregationTime.getSI() / speed.getSI();
177
178
179 }
180 else
181 {
182 assertTrue("Data should be NaN", java.lang.Double.isNaN(value));
183 }
184 value = fd.getX(0, sample).doubleValue();
185 if (shouldHaveData)
186 {
187 double expectedDensity = 3600 / aggregationTime.getSI() / speed.getSI();
188 assertEquals("Density should be " + expectedDensity, expectedDensity, value, 0.00001);
189 }
190 else
191 {
192 assertTrue("Data should be NaN", java.lang.Double.isNaN(value));
193 }
194 shouldHaveData = sample <= bucket;
195 value = fd.getYValue(0, sample);
196 if (shouldHaveData)
197 {
198 double expectedFlow = sample == bucket ? 3600 / aggregationTime.getSI() : 0;
199 assertEquals("Flow should be " + expectedFlow, expectedFlow, value, 0.00001);
200 }
201 else
202 {
203 assertTrue("Data should be NaN", java.lang.Double.isNaN(value));
204 }
205 value = fd.getY(0, sample).doubleValue();
206 if (shouldHaveData)
207 {
208 double expectedFlow = sample == bucket ? 3600 / aggregationTime.getSI() : 0;
209 assertEquals("Flow should be " + expectedFlow, expectedFlow, value, 0.00001);
210 }
211 else
212 {
213 assertTrue("Data should be NaN", java.lang.Double.isNaN(value));
214 }
215 fd.actionPerformed(setXToSpeed);
216 value = fd.getYValue(0, sample);
217 if (shouldHaveData)
218 {
219 double expectedSpeed = sample == bucket ? speed.getInUnit() : 0;
220 assertEquals("Speed should be " + expectedSpeed, expectedSpeed, value, 0.00001);
221 }
222 else
223 {
224 assertTrue("Data should be NaN", java.lang.Double.isNaN(value));
225 }
226 value = fd.getY(0, sample).doubleValue();
227 if (shouldHaveData)
228 {
229 double expectedSpeed = sample == bucket ? speed.getInUnit() : 0;
230 assertEquals("Speed should be " + expectedSpeed, expectedSpeed, value, 0.00001);
231 }
232 else
233 {
234 assertTrue("Data should be NaN", java.lang.Double.isNaN(value));
235 }
236 fd.actionPerformed(resetAxis);
237 }
238
239 speed = new Speed(10, KM_PER_HOUR);
240 behavioralCharacteristics = DefaultTestParameters.create();
241 LaneBasedIndividualGTU gtuX =
242 new LaneBasedIndividualGTU("1234", gtuType, length, width, maxSpeed, simulator, this.network);
243 strategicalPlanner = new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics,
244 new LaneBasedCFLCTacticalPlanner(gtuFollowingModel, laneChangeModel, gtuX), gtuX);
245 gtuX.init(strategicalPlanner, initialLongitudinalPositions, speed);
246 simulator.runUpTo(new Time(125, TimeUnit.BASE_SECOND));
247 while (simulator.isRunning())
248 {
249 try
250 {
251 Thread.sleep(1);
252 }
253 catch (InterruptedException ie)
254 {
255 ie = null;
256 }
257 }
258 fd.actionPerformed(setXToSpeed);
259 value = fd.getYValue(0, bucket);
260 double expected = 2d / (1d / 100 + 1d / 10);
261
262 assertEquals("Harmonic mean of 10 and 100 is " + expected, expected, value, 0.0001);
263
264 try
265 {
266 fd.actionPerformed(new ActionEvent(fd, 0, "bla"));
267 fail("Bad ActionEvent should have thrown an Error");
268 }
269 catch (Error e)
270 {
271
272 }
273 try
274 {
275 fd.actionPerformed(new ActionEvent(fd, 0, "Speed/bla"));
276 fail("Bad ActionEvent should have thrown an Error");
277 }
278 catch (Error e)
279 {
280
281 }
282 try
283 {
284 fd.actionPerformed(new ActionEvent(fd, 0, "Flow/bla"));
285 fail("Bad ActionEvent should have thrown an Error");
286 }
287 catch (Error e)
288 {
289
290 }
291 try
292 {
293 fd.actionPerformed(new ActionEvent(fd, 0, "Density/bla"));
294 fail("Bad ActionEvent should have thrown an Error");
295 }
296 catch (Error e)
297 {
298
299 }
300 try
301 {
302 fd.actionPerformed(new ActionEvent(fd, 0, "bla/Speed"));
303 fail("Bad ActionEvent should have thrown an Error");
304 }
305 catch (Error e)
306 {
307
308 }
309 try
310 {
311 fd.actionPerformed(new ActionEvent(fd, 0, "bla/Flow"));
312 fail("Bad ActionEvent should have thrown an Error");
313 }
314 catch (Error e)
315 {
316
317 }
318 try
319 {
320 fd.actionPerformed(new ActionEvent(fd, 0, "bla/Density"));
321 fail("Bad ActionEvent should have thrown an Error");
322 }
323 catch (Error e)
324 {
325
326 }
327 }
328
329
330
331
332
333 @SuppressWarnings("static-method")
334 @Test
335 public final void testHints() throws Exception
336 {
337 this.simulator = new SimpleSimulator(new Time(0, TimeUnit.BASE_SECOND), new Duration(0, SECOND),
338 new Duration(1800, SECOND), this);
339
340 Duration aggregationTime = new Duration(30, SECOND);
341 Length position = new Length(123, METER);
342 Set<GTUType> compatibility = new HashSet<GTUType>();
343 compatibility.add(GTUType.ALL);
344 LaneType laneType = new LaneType("CarLane", compatibility);
345 FundamentalDiagram fd = new FundamentalDiagram("Fundamental Diagram", aggregationTime,
346 CarTest.makeLane(this.network, laneType), position, this.simulator);
347
348 JLabel hintPanel = null;
349 ChartPanel chartPanel = null;
350 for (Component c0 : fd.getComponents())
351 {
352 for (Component c1 : ((Container) c0).getComponents())
353 {
354 if (c1 instanceof Container)
355 {
356 for (Component c2 : ((Container) c1).getComponents())
357 {
358
359 if (c2 instanceof Container)
360 {
361 for (Component c3 : ((Container) c2).getComponents())
362 {
363
364 if (c3 instanceof JLabel)
365 {
366 if (null == hintPanel)
367 {
368 hintPanel = (JLabel) c3;
369 }
370 else
371 {
372 fail("There should be only one JPanel in a FundamentalDiagram");
373 }
374 }
375 if (c3 instanceof ChartPanel)
376 {
377 if (null == chartPanel)
378 {
379 chartPanel = (ChartPanel) c3;
380 }
381 else
382 {
383 fail("There should be only one ChartPanel in a FundamentalDiagram");
384 }
385 }
386 }
387 }
388 }
389 }
390 }
391 }
392 if (null == hintPanel)
393 {
394 fail("Could not find a JLabel in FundamentalDiagram");
395 }
396 if (null == chartPanel)
397 {
398 fail("Could not find a ChartPanel in FundamentalDiagram");
399 }
400 assertEquals("Initially the text should be a single space", " ", hintPanel.getText());
401 PointerHandler ph = null;
402 for (MouseListener ml : chartPanel.getMouseListeners())
403 {
404 if (ml instanceof PointerHandler)
405 {
406 if (null == ph)
407 {
408 ph = (PointerHandler) ml;
409 }
410 else
411 {
412 fail("There should be only one PointerHandler on the chartPanel");
413 }
414 }
415 }
416 if (null == ph)
417 {
418 fail("Could not find the PointerHandler for the chartPanel");
419 }
420 ph.updateHint(1, 2);
421
422 assertFalse("Hint should not be a single space", " ".equals(hintPanel.getText()));
423 ph.updateHint(java.lang.Double.NaN, java.lang.Double.NaN);
424 assertEquals("The text should again be a single space", " ", hintPanel.getText());
425 }
426
427
428 @Override
429 public void constructModel(SimulatorInterface<Time, Duration, OTSSimTimeDouble> arg0) throws SimRuntimeException
430 {
431
432 }
433
434
435 @Override
436 public SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator()
437
438 {
439 return this.simulator;
440 }
441
442
443 @Override
444 public OTSNetwork getNetwork()
445 {
446 return this.network;
447 }
448
449 }