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