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.core.gtu.GTUType.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.LinkedHashSet;
14 import java.util.Set;
15
16 import javax.swing.JLabel;
17
18 import org.djunits.unit.TimeUnit;
19 import org.djunits.unit.UNITS;
20 import org.djunits.value.vdouble.scalar.Acceleration;
21 import org.djunits.value.vdouble.scalar.Duration;
22 import org.djunits.value.vdouble.scalar.Length;
23 import org.djunits.value.vdouble.scalar.Speed;
24 import org.djunits.value.vdouble.scalar.Time;
25 import org.jfree.chart.ChartPanel;
26 import org.junit.Test;
27 import org.opentrafficsim.base.parameters.Parameters;
28 import org.opentrafficsim.core.compatibility.Compatible;
29 import org.opentrafficsim.core.dsol.OTSModelInterface;
30 import org.opentrafficsim.core.gtu.GTUDirectionality;
31 import org.opentrafficsim.core.gtu.GTUType;
32 import org.opentrafficsim.core.network.OTSNetwork;
33 import org.opentrafficsim.road.DefaultTestParameters;
34 import org.opentrafficsim.road.car.CarTest;
35 import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
36 import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedCFLCTacticalPlanner;
37 import org.opentrafficsim.road.gtu.lane.tactical.following.FixedAccelerationModel;
38 import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
39 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.Egoistic;
40 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.LaneChangeModel;
41 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
42 import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlanner;
43 import org.opentrafficsim.road.network.lane.DirectedLanePosition;
44 import org.opentrafficsim.road.network.lane.Lane;
45 import org.opentrafficsim.road.network.lane.LaneType;
46 import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
47 import org.opentrafficsim.simulationengine.SimpleSimulator;
48
49 import nl.tudelft.simulation.dsol.SimRuntimeException;
50 import nl.tudelft.simulation.dsol.simtime.SimTimeDoubleUnit;
51 import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
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 DEVSSimulatorInterface.TimeDoubleUnit 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 LaneType laneType = LaneType.TWO_WAY_LANE;
90 Lane lane = CarTest.makeLane(this.network, laneType, this.simulator);
91 FundamentalDiagram fd = new FundamentalDiagram("Fundamental Diagram", aggregationTime, lane, position,
92 Compatible.EVERYTHING, this.simulator);
93 assertEquals("SeriesCount should match numberOfLanes", 1, fd.getSeriesCount());
94 assertEquals("Position should match the supplied position", position.getSI(), fd.getPosition().getSI(), 0.0001);
95 try
96 {
97 fd.getXValue(-1, 0);
98 fail("Bad series should have thrown an Error");
99 }
100 catch (Error e)
101 {
102
103 }
104 try
105 {
106 fd.getXValue(1, 0);
107 fail("Bad series should have thrown an Error");
108 }
109 catch (Error e)
110 {
111
112 }
113 double value = fd.getXValue(0, 0);
114 assertTrue("No data should result in NaN", java.lang.Double.isNaN(value));
115 value = fd.getX(0, 0).doubleValue();
116 assertTrue("No data should result in NaN", java.lang.Double.isNaN(value));
117 value = fd.getYValue(0, 0);
118 assertTrue("No data should result in NaN", java.lang.Double.isNaN(value));
119 value = fd.getY(0, 0).doubleValue();
120 assertTrue("No data should result in NaN", java.lang.Double.isNaN(value));
121 ActionEvent setXToSpeed = new ActionEvent(fd, 0, "Speed/Speed");
122 ActionEvent resetAxis = new ActionEvent(fd, 0, "Flow/Density");
123 Speed speed = new Speed(100, KM_PER_HOUR);
124 Time time = new Time(123, TimeUnit.BASE_SECOND);
125 Length length = new Length(5.0, METER);
126 Length width = new Length(2.0, METER);
127 Speed maxSpeed = new Speed(120, KM_PER_HOUR);
128 Set<DirectedLanePosition> initialLongitudinalPositions = new LinkedHashSet<>(1);
129 initialLongitudinalPositions.add(new DirectedLanePosition(lane, carPosition, GTUDirectionality.DIR_PLUS));
130
131
132 new SinkSensor(lane, new Length(lane.getLength().getSI() - 100, METER), this.simulator);
133
134 this.simulator.runUpTo(time);
135 while (this.simulator.isRunning())
136 {
137 try
138 {
139 Thread.sleep(1);
140 }
141 catch (InterruptedException ie)
142 {
143 ie = null;
144 }
145 }
146 int bucket = (int) Math.floor(time.getSI() / aggregationTime.getSI());
147 LaneChangeModel laneChangeModel = new Egoistic();
148 GTUFollowingModelOld gtuFollowingModel =
149 new FixedAccelerationModel(new Acceleration(0, METER_PER_SECOND_2), new Duration(1000, SECOND));
150
151 Parameters parameters = DefaultTestParameters.create();
152 LaneBasedIndividualGTU gtu = new LaneBasedIndividualGTU("1", gtuType, length, width, maxSpeed, length.multiplyBy(0.5),
153 this.simulator, this.network);
154 LaneBasedStrategicalPlanner strategicalPlanner = new LaneBasedStrategicalRoutePlanner(
155 new LaneBasedCFLCTacticalPlanner(gtuFollowingModel, laneChangeModel, gtu), gtu);
156 gtu.setParameters(parameters);
157 gtu.init(strategicalPlanner, initialLongitudinalPositions, speed);
158 this.simulator.runUpTo(new Time(124, TimeUnit.BASE_SECOND));
159 while (this.simulator.isRunning())
160 {
161 try
162 {
163 Thread.sleep(1);
164 }
165 catch (InterruptedException ie)
166 {
167 ie = null;
168 }
169 }
170 for (int sample = 0; sample < 10; sample++)
171 {
172 boolean shouldHaveData = sample == bucket;
173 value = fd.getXValue(0, sample);
174
175 if (shouldHaveData)
176 {
177 double expectedDensity = 3600 / aggregationTime.getSI() / speed.getSI();
178
179
180 }
181 else
182 {
183 assertTrue("Data should be NaN", java.lang.Double.isNaN(value));
184 }
185 value = fd.getX(0, sample).doubleValue();
186 if (shouldHaveData)
187 {
188 double expectedDensity = 3600 / aggregationTime.getSI() / speed.getSI();
189 assertEquals("Density should be " + expectedDensity, expectedDensity, value, 0.00001);
190 }
191 else
192 {
193 assertTrue("Data should be NaN", java.lang.Double.isNaN(value));
194 }
195 shouldHaveData = sample <= bucket;
196 value = fd.getYValue(0, sample);
197 if (shouldHaveData)
198 {
199 double expectedFlow = sample == bucket ? 3600 / aggregationTime.getSI() : 0;
200 assertEquals("Flow should be " + expectedFlow, expectedFlow, value, 0.00001);
201 }
202 else
203 {
204 assertTrue("Data should be NaN", java.lang.Double.isNaN(value));
205 }
206 value = fd.getY(0, sample).doubleValue();
207 if (shouldHaveData)
208 {
209 double expectedFlow = sample == bucket ? 3600 / aggregationTime.getSI() : 0;
210 assertEquals("Flow should be " + expectedFlow, expectedFlow, value, 0.00001);
211 }
212 else
213 {
214 assertTrue("Data should be NaN", java.lang.Double.isNaN(value));
215 }
216 fd.actionPerformed(setXToSpeed);
217 value = fd.getYValue(0, sample);
218 if (shouldHaveData)
219 {
220 double expectedSpeed = sample == bucket ? speed.getInUnit() : 0;
221 assertEquals("Speed should be " + expectedSpeed, expectedSpeed, value, 0.00001);
222 }
223 else
224 {
225 assertTrue("Data should be NaN", java.lang.Double.isNaN(value));
226 }
227 value = fd.getY(0, sample).doubleValue();
228 if (shouldHaveData)
229 {
230 double expectedSpeed = sample == bucket ? speed.getInUnit() : 0;
231 assertEquals("Speed should be " + expectedSpeed, expectedSpeed, value, 0.00001);
232 }
233 else
234 {
235 assertTrue("Data should be NaN", java.lang.Double.isNaN(value));
236 }
237 fd.actionPerformed(resetAxis);
238 }
239
240 speed = new Speed(10, KM_PER_HOUR);
241 parameters = DefaultTestParameters.create();
242 LaneBasedIndividualGTU gtuX = new LaneBasedIndividualGTU("1234", gtuType, length, width, maxSpeed,
243 length.multiplyBy(0.5), this.simulator, this.network);
244 strategicalPlanner = new LaneBasedStrategicalRoutePlanner(
245 new LaneBasedCFLCTacticalPlanner(gtuFollowingModel, laneChangeModel, gtuX), gtuX);
246 gtuX.init(strategicalPlanner, initialLongitudinalPositions, speed);
247 gtuX.setParameters(parameters);
248 this.simulator.runUpTo(new Time(125, TimeUnit.BASE_SECOND));
249 while (this.simulator.isRunning())
250 {
251 try
252 {
253 Thread.sleep(1);
254 }
255 catch (InterruptedException ie)
256 {
257 ie = null;
258 }
259 }
260 fd.actionPerformed(setXToSpeed);
261 value = fd.getYValue(0, bucket);
262 double expected = 2d / (1d / 100 + 1d / 10);
263
264 assertEquals("Harmonic mean of 10 and 100 is " + expected, expected, value, 0.0001);
265
266 try
267 {
268 fd.actionPerformed(new ActionEvent(fd, 0, "bla"));
269 fail("Bad ActionEvent should have thrown an Error");
270 }
271 catch (Error e)
272 {
273
274 }
275 try
276 {
277 fd.actionPerformed(new ActionEvent(fd, 0, "Speed/bla"));
278 fail("Bad ActionEvent should have thrown an Error");
279 }
280 catch (Error e)
281 {
282
283 }
284 try
285 {
286 fd.actionPerformed(new ActionEvent(fd, 0, "Flow/bla"));
287 fail("Bad ActionEvent should have thrown an Error");
288 }
289 catch (Error e)
290 {
291
292 }
293 try
294 {
295 fd.actionPerformed(new ActionEvent(fd, 0, "Density/bla"));
296 fail("Bad ActionEvent should have thrown an Error");
297 }
298 catch (Error e)
299 {
300
301 }
302 try
303 {
304 fd.actionPerformed(new ActionEvent(fd, 0, "bla/Speed"));
305 fail("Bad ActionEvent should have thrown an Error");
306 }
307 catch (Error e)
308 {
309
310 }
311 try
312 {
313 fd.actionPerformed(new ActionEvent(fd, 0, "bla/Flow"));
314 fail("Bad ActionEvent should have thrown an Error");
315 }
316 catch (Error e)
317 {
318
319 }
320 try
321 {
322 fd.actionPerformed(new ActionEvent(fd, 0, "bla/Density"));
323 fail("Bad ActionEvent should have thrown an Error");
324 }
325 catch (Error e)
326 {
327
328 }
329 }
330
331
332
333
334
335 @SuppressWarnings("static-method")
336 @Test
337 public final void testHints() throws Exception
338 {
339 this.simulator = new SimpleSimulator(new Time(0, TimeUnit.BASE_SECOND), new Duration(0, SECOND),
340 new Duration(1800, SECOND), this);
341
342 Duration aggregationTime = new Duration(30, SECOND);
343 Length position = new Length(123, METER);
344 LaneType laneType = LaneType.TWO_WAY_LANE;
345 FundamentalDiagram fd = new FundamentalDiagram("Fundamental Diagram", aggregationTime,
346 CarTest.makeLane(this.network, laneType, this.simulator), position, Compatible.EVERYTHING, 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(final SimulatorInterface<Time, Duration, SimTimeDoubleUnit> arg0) throws SimRuntimeException
430 {
431
432 }
433
434
435 @Override
436 public final SimulatorInterface<Time, Duration, SimTimeDoubleUnit> getSimulator()
437
438 {
439 return this.simulator;
440 }
441
442
443 @Override
444 public final OTSNetwork getNetwork()
445 {
446 return this.network;
447 }
448
449 }