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