View Javadoc
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   * <p>
55   * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
56   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
57   * <p>
58   * $LastChangedDate: 2015-09-14 01:33:02 +0200 (Mon, 14 Sep 2015) $, @version $Revision: 1401 $, by $Author: averbraeck $,
59   * initial version Aug 25, 2014 <br>
60   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
61   */
62  public class FundamentalDiagramPlotTest implements OTSModelInterface, UNITS
63  {
64      /** */
65      private static final long serialVersionUID = 20150226L;
66  
67      /** The network. */
68      private OTSNetwork network = new OTSNetwork("network");
69  
70      /** the simulator. */
71      private OTSDEVSSimulatorInterface simulator;
72  
73      /**
74       * Test the FundamentalDiagram.
75       * @throws Exception when something goes wrong (should not happen)
76       */
77      @SuppressWarnings("static-method")
78      // XXX @Test
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             // Ignore
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             // Ignore
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         // add a sink 100 meter before the end of the lane.
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; // ignore
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         // Construct a car
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; // ignore
165             }
166         }
167         for (int sample = 0; sample < 10; sample++)
168         {
169             boolean shouldHaveData = sample == bucket;
170             value = fd.getXValue(0, sample);
171             // System.out.println("value of sample " + sample + " is " + value);
172             if (shouldHaveData)
173             {
174                 double expectedDensity = 3600 / aggregationTime.getSI() / speed.getSI();
175                 // TODO THIS TEST FAILS!!!
176                 // assertEquals("Density should be " + expectedDensity, expectedDensity, value, 0.00001);
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         // Check that harmonic mean speed is computed
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; // ignore
254             }
255         }
256         fd.actionPerformed(setXToSpeed);
257         value = fd.getYValue(0, bucket);
258         double expected = 2d / (1d / 100 + 1d / 10);
259         // System.out.println("harmonic speed is " + value + ", expected is " + expected);
260         assertEquals("Harmonic mean of 10 and 100 is " + expected, expected, value, 0.0001);
261         // Test the actionPerformed method with various malformed ActionEvents.
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             // Ignore
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             // Ignore
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             // Ignore
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             // Ignore
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             // Ignore
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             // Ignore
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             // Ignore
324         }
325     }
326 
327     /**
328      * Test the updateHint method in the PointerHandler.
329      * @throws Exception when something goes wrong (should not happen)
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         // First get the panel that stores the result of updateHint (this is ugly)
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                         // System.out.println("c2 is " + c2);
356                         if (c2 instanceof Container)
357                         {
358                             for (Component c3 : ((Container) c2).getComponents())
359                             {
360                                 // System.out.println("c3 is " + c3);
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         // System.out.println("Hint text is now " + hintPanel.getText());
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     /** {@inheritDoc} */
425     @Override
426     public void constructModel(SimulatorInterface<Time, Duration, OTSSimTimeDouble> arg0) throws SimRuntimeException
427     {
428         // Do nothing
429     }
430 
431     /** {@inheritDoc} */
432     @Override
433     public SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator()
434 
435     {
436         return this.simulator;
437     }
438 
439     /** {@inheritDoc} */
440     @Override
441     public OTSNetwork getNetwork()
442     {
443         return this.network;
444     }
445 
446 }