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   
8   import java.awt.Component;
9   import java.awt.Container;
10  import java.awt.event.ActionEvent;
11  import java.awt.event.MouseListener;
12  import java.util.HashSet;
13  import java.util.LinkedHashSet;
14  import java.util.Set;
15  
16  import javax.swing.JLabel;
17  
18  import org.djunits.unit.UNITS;
19  import org.djunits.value.vdouble.scalar.Acceleration;
20  import org.djunits.value.vdouble.scalar.Duration;
21  import org.djunits.value.vdouble.scalar.Length;
22  import org.djunits.value.vdouble.scalar.Speed;
23  import org.djunits.value.vdouble.scalar.Time;
24  import org.jfree.chart.ChartPanel;
25  import org.junit.Test;
26  import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
27  import org.opentrafficsim.core.dsol.OTSModelInterface;
28  import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
29  import org.opentrafficsim.core.gtu.GTUDirectionality;
30  import org.opentrafficsim.core.gtu.GTUType;
31  import org.opentrafficsim.core.gtu.behavioralcharacteristics.BehavioralCharacteristics;
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.simulators.SimulatorInterface;
51  
52  /**
53   * <p>
54   * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
55   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
56   * <p>
57   * $LastChangedDate: 2015-09-14 01:33:02 +0200 (Mon, 14 Sep 2015) $, @version $Revision: 1401 $, by $Author: averbraeck $,
58   * initial version Aug 25, 2014 <br>
59   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
60   */
61  public class FundamentalDiagramPlotTest implements OTSModelInterface, UNITS
62  {
63      /** */
64      private static final long serialVersionUID = 20150226L;
65  
66      /** The network. */
67      private OTSNetwork network = new OTSNetwork("network");
68      
69      /** the simulator. */
70      private OTSDEVSSimulatorInterface simulator;
71  
72      /**
73       * Test the FundamentalDiagram.
74       * @throws Exception when something goes wrong (should not happen)
75       */
76      @SuppressWarnings("static-method")
77      // XXX @Test
78      public final void fundamentalDiagramTest() throws Exception
79      {
80          this.simulator =
81                  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 = new 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 =
153                 new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics, new LaneBasedCFLCTacticalPlanner(
154                         gtuFollowingModel, laneChangeModel, gtu), gtu);
155         gtu.init(strategicalPlanner, initialLongitudinalPositions, speed);
156         simulator.runUpTo(new Time(124, SECOND));
157         while (simulator.isRunning())
158         {
159             try
160             {
161                 Thread.sleep(1);
162             }
163             catch (InterruptedException ie)
164             {
165                 ie = null; // ignore
166             }
167         }
168         for (int sample = 0; sample < 10; sample++)
169         {
170             boolean shouldHaveData = sample == bucket;
171             value = fd.getXValue(0, sample);
172             // System.out.println("value of sample " + sample + " is " + value);
173             if (shouldHaveData)
174             {
175                 double expectedDensity = 3600 / aggregationTime.getSI() / speed.getSI();
176                 // TODO THIS TEST FAILS!!!
177                 // assertEquals("Density should be " + expectedDensity, expectedDensity, value, 0.00001);
178             }
179             else
180             {
181                 assertTrue("Data should be NaN", java.lang.Double.isNaN(value));
182             }
183             value = fd.getX(0, sample).doubleValue();
184             if (shouldHaveData)
185             {
186                 double expectedDensity = 3600 / aggregationTime.getSI() / speed.getSI();
187                 assertEquals("Density should be " + expectedDensity, expectedDensity, value, 0.00001);
188             }
189             else
190             {
191                 assertTrue("Data should be NaN", java.lang.Double.isNaN(value));
192             }
193             shouldHaveData = sample <= bucket;
194             value = fd.getYValue(0, sample);
195             if (shouldHaveData)
196             {
197                 double expectedFlow = sample == bucket ? 3600 / aggregationTime.getSI() : 0;
198                 assertEquals("Flow should be " + expectedFlow, expectedFlow, value, 0.00001);
199             }
200             else
201             {
202                 assertTrue("Data should be NaN", java.lang.Double.isNaN(value));
203             }
204             value = fd.getY(0, sample).doubleValue();
205             if (shouldHaveData)
206             {
207                 double expectedFlow = sample == bucket ? 3600 / aggregationTime.getSI() : 0;
208                 assertEquals("Flow should be " + expectedFlow, expectedFlow, value, 0.00001);
209             }
210             else
211             {
212                 assertTrue("Data should be NaN", java.lang.Double.isNaN(value));
213             }
214             fd.actionPerformed(setXToSpeed);
215             value = fd.getYValue(0, sample);
216             if (shouldHaveData)
217             {
218                 double expectedSpeed = sample == bucket ? speed.getInUnit() : 0;
219                 assertEquals("Speed should be " + expectedSpeed, expectedSpeed, value, 0.00001);
220             }
221             else
222             {
223                 assertTrue("Data should be NaN", java.lang.Double.isNaN(value));
224             }
225             value = fd.getY(0, sample).doubleValue();
226             if (shouldHaveData)
227             {
228                 double expectedSpeed = sample == bucket ? speed.getInUnit() : 0;
229                 assertEquals("Speed should be " + expectedSpeed, expectedSpeed, value, 0.00001);
230             }
231             else
232             {
233                 assertTrue("Data should be NaN", java.lang.Double.isNaN(value));
234             }
235             fd.actionPerformed(resetAxis);
236         }
237         // Check that harmonic mean speed is computed
238         speed = new Speed(10, KM_PER_HOUR);
239         behavioralCharacteristics = DefaultTestParameters.create();
240         LaneBasedIndividualGTU gtuX =
241                 new LaneBasedIndividualGTU("1234", gtuType, length, width, maxSpeed, simulator, this.network);
242         strategicalPlanner =
243                 new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics, new LaneBasedCFLCTacticalPlanner(
244                         gtuFollowingModel, laneChangeModel, gtuX), gtuX);
245         gtuX.init(strategicalPlanner, initialLongitudinalPositions, speed);
246         simulator.runUpTo(new Time(125, SECOND));
247         while (simulator.isRunning())
248         {
249             try
250             {
251                 Thread.sleep(1);
252             }
253             catch (InterruptedException ie)
254             {
255                 ie = null; // ignore
256             }
257         }
258         fd.actionPerformed(setXToSpeed);
259         value = fd.getYValue(0, bucket);
260         double expected = 2d / (1d / 100 + 1d / 10);
261         // System.out.println("harmonic speed is " + value + ", expected is " + expected);
262         assertEquals("Harmonic mean of 10 and 100 is " + expected, expected, value, 0.0001);
263         // Test the actionPerformed method with various malformed ActionEvents.
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             // Ignore
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             // Ignore
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             // Ignore
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             // Ignore
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             // Ignore
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             // Ignore
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             // Ignore
326         }
327     }
328 
329     /**
330      * Test the updateHint method in the PointerHandler.
331      * @throws Exception when something goes wrong (should not happen)
332      */
333     @SuppressWarnings("static-method")
334     @Test
335     public final void testHints() throws Exception
336     {
337         this.simulator =
338                 new SimpleSimulator(new Time(0, SECOND), new Duration(0, SECOND), 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 =
346                 new FundamentalDiagram("Fundamental Diagram", aggregationTime, CarTest.makeLane(this.network, laneType),
347                         position, this.simulator);
348         // First get the panel that stores the result of updateHint (this is ugly)
349         JLabel hintPanel = null;
350         ChartPanel chartPanel = null;
351         for (Component c0 : fd.getComponents())
352         {
353             for (Component c1 : ((Container) c0).getComponents())
354             {
355                 if (c1 instanceof Container)
356                 {
357                     for (Component c2 : ((Container) c1).getComponents())
358                     {
359                         // System.out.println("c2 is " + c2);
360                         if (c2 instanceof Container)
361                         {
362                             for (Component c3 : ((Container) c2).getComponents())
363                             {
364                                 // System.out.println("c3 is " + c3);
365                                 if (c3 instanceof JLabel)
366                                 {
367                                     if (null == hintPanel)
368                                     {
369                                         hintPanel = (JLabel) c3;
370                                     }
371                                     else
372                                     {
373                                         fail("There should be only one JPanel in a FundamentalDiagram");
374                                     }
375                                 }
376                                 if (c3 instanceof ChartPanel)
377                                 {
378                                     if (null == chartPanel)
379                                     {
380                                         chartPanel = (ChartPanel) c3;
381                                     }
382                                     else
383                                     {
384                                         fail("There should be only one ChartPanel in a FundamentalDiagram");
385                                     }
386                                 }
387                             }
388                         }
389                     }
390                 }
391             }
392         }
393         if (null == hintPanel)
394         {
395             fail("Could not find a JLabel in FundamentalDiagram");
396         }
397         if (null == chartPanel)
398         {
399             fail("Could not find a ChartPanel in FundamentalDiagram");
400         }
401         assertEquals("Initially the text should be a single space", " ", hintPanel.getText());
402         PointerHandler ph = null;
403         for (MouseListener ml : chartPanel.getMouseListeners())
404         {
405             if (ml instanceof PointerHandler)
406             {
407                 if (null == ph)
408                 {
409                     ph = (PointerHandler) ml;
410                 }
411                 else
412                 {
413                     fail("There should be only one PointerHandler on the chartPanel");
414                 }
415             }
416         }
417         if (null == ph)
418         {
419             fail("Could not find the PointerHandler for the chartPanel");
420         }
421         ph.updateHint(1, 2);
422         // System.out.println("Hint text is now " + hintPanel.getText());
423         assertFalse("Hint should not be a single space", " ".equals(hintPanel.getText()));
424         ph.updateHint(java.lang.Double.NaN, java.lang.Double.NaN);
425         assertEquals("The text should again be a single space", " ", hintPanel.getText());
426     }
427 
428     /** {@inheritDoc} */
429     @Override
430     public void constructModel(SimulatorInterface<Time, Duration, OTSSimTimeDouble> arg0)
431             throws SimRuntimeException
432     {
433         // Do nothing
434     }
435 
436     /** {@inheritDoc} */
437     @Override
438     public SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator()
439 
440     {
441         return this.simulator;
442     }
443 
444 }