package org.opentrafficsim.graphs; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.awt.Component; import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.MouseListener; import java.util.LinkedHashSet; import java.util.Set; import javax.swing.JLabel; import nl.tudelft.simulation.dsol.SimRuntimeException; import nl.tudelft.simulation.dsol.simulators.SimulatorInterface; import org.djunits.unit.TimeUnit; import org.djunits.unit.UNITS; import org.djunits.value.vdouble.scalar.Acceleration; import org.djunits.value.vdouble.scalar.DoubleScalar; import org.djunits.value.vdouble.scalar.Length; import org.djunits.value.vdouble.scalar.Speed; import org.djunits.value.vdouble.scalar.Time; import org.jfree.chart.ChartPanel; import org.junit.Test; import org.opentrafficsim.core.dsol.OTSModelInterface; import org.opentrafficsim.core.dsol.OTSSimTimeDouble; import org.opentrafficsim.core.gtu.GTUDirectionality; import org.opentrafficsim.core.gtu.GTUType; import org.opentrafficsim.core.network.OTSNetwork; import org.opentrafficsim.road.car.CarTest; import org.opentrafficsim.road.car.LaneBasedIndividualCar; import org.opentrafficsim.road.gtu.lane.driver.LaneBasedDrivingCharacteristics; import org.opentrafficsim.road.gtu.lane.perception.LanePerceptionFull; import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedCFLCTacticalPlanner; import org.opentrafficsim.road.gtu.lane.tactical.following.FixedAccelerationModel; import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModel; import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.Egoistic; import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.LaneChangeModel; import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner; import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlanner; import org.opentrafficsim.road.network.lane.DirectedLanePosition; import org.opentrafficsim.road.network.lane.Lane; import org.opentrafficsim.road.network.lane.LaneType; import org.opentrafficsim.road.network.lane.SinkSensor; import org.opentrafficsim.simulationengine.SimpleSimulator; /** *

* Copyright (c) 2013-2015 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See OpenTrafficSim License. *

* $LastChangedDate: 2015-09-14 01:33:02 +0200 (Mon, 14 Sep 2015) $, @version $Revision: 1401 $, by $Author: averbraeck $, * initial version Aug 25, 2014
* @author Peter Knoppers */ public class FundamentalDiagramPlotTest implements OTSModelInterface, UNITS { /** */ private static final long serialVersionUID = 20150226L; /** network. */ private OTSNetwork network = new OTSNetwork("network"); /** * Test the FundamentalDiagram. * @throws Exception when something goes wrong (should not happen) */ @SuppressWarnings("static-method") @Test public final void fundamentalDiagramTest() throws Exception { Time.Rel aggregationTime = new Time.Rel(30, SECOND); Length.Rel position = new Length.Rel(123, METER); Length.Rel carPosition = new Length.Rel(122.5, METER); LaneType laneType = new LaneType("CarLane"); GTUType gtuType = GTUType.makeGTUType("Car"); laneType.addCompatibility(gtuType); Lane lane = CarTest.makeLane(laneType); FundamentalDiagram fd = new FundamentalDiagram("Fundamental Diagram", aggregationTime, lane, position); assertEquals("SeriesCount should match numberOfLanes", 1, fd.getSeriesCount()); assertEquals("Position should match the supplied position", position.getSI(), fd.getPosition().getSI(), 0.0001); try { fd.getXValue(-1, 0); fail("Bad series should have thrown an Error"); } catch (Error e) { // Ignore } try { fd.getXValue(1, 0); fail("Bad series should have thrown an Error"); } catch (Error e) { // Ignore } double value = fd.getXValue(0, 0); assertTrue("No data should result in NaN", java.lang.Double.isNaN(value)); value = fd.getX(0, 0).doubleValue(); assertTrue("No data should result in NaN", java.lang.Double.isNaN(value)); value = fd.getYValue(0, 0); assertTrue("No data should result in NaN", java.lang.Double.isNaN(value)); value = fd.getY(0, 0).doubleValue(); assertTrue("No data should result in NaN", java.lang.Double.isNaN(value)); ActionEvent setXToSpeed = new ActionEvent(fd, 0, "Speed/Speed"); ActionEvent resetAxis = new ActionEvent(fd, 0, "Flow/Density"); Speed speed = new Speed(100, KM_PER_HOUR); Time.Abs time = new Time.Abs(123, SECOND); Length.Rel length = new Length.Rel(5.0, METER); Length.Rel width = new Length.Rel(2.0, METER); Speed maxSpeed = new Speed(120, KM_PER_HOUR); Set initialLongitudinalPositions = new LinkedHashSet<>(1); initialLongitudinalPositions.add(new DirectedLanePosition(lane, carPosition, GTUDirectionality.DIR_PLUS)); SimpleSimulator simulator = new SimpleSimulator(new Time.Abs(0, SECOND), new Time.Rel(0, SECOND), new Time.Rel(1800, SECOND), this); // add a sink 100 meter before the end of the lane. lane.addSensor(new SinkSensor(lane, new Length.Rel(lane.getLength().getSI() - 100, METER), simulator), GTUType.ALL); simulator.runUpTo(time); while (simulator.isRunning()) { try { Thread.sleep(1); } catch (InterruptedException ie) { ie = null; // ignore } } int bucket = (int) Math.floor(time.getSI() / aggregationTime.getSI()); LaneChangeModel laneChangeModel = new Egoistic(); GTUFollowingModel gtuFollowingModel = new FixedAccelerationModel(new Acceleration(0, METER_PER_SECOND_2), new Time.Rel(1000, SECOND)); // Construct a car LaneBasedDrivingCharacteristics drivingCharacteristics = new LaneBasedDrivingCharacteristics(gtuFollowingModel, laneChangeModel); LaneBasedStrategicalPlanner strategicalPlanner = new LaneBasedStrategicalRoutePlanner(drivingCharacteristics, new LaneBasedCFLCTacticalPlanner()); new LaneBasedIndividualCar("1", gtuType, initialLongitudinalPositions, speed, length, width, maxSpeed, simulator, strategicalPlanner, new LanePerceptionFull(), this.network); simulator.runUpTo(new Time.Abs(124, SECOND)); while (simulator.isRunning()) { try { Thread.sleep(1); } catch (InterruptedException ie) { ie = null; // ignore } } for (int sample = 0; sample < 10; sample++) { boolean shouldHaveData = sample == bucket; value = fd.getXValue(0, sample); // System.out.println("value " + value); if (shouldHaveData) { double expectedDensity = 3600 / aggregationTime.getSI() / speed.getSI(); assertEquals("Density should be " + expectedDensity, expectedDensity, value, 0.00001); } else { assertTrue("Data should be NaN", java.lang.Double.isNaN(value)); } value = fd.getX(0, sample).doubleValue(); if (shouldHaveData) { double expectedDensity = 3600 / aggregationTime.getSI() / speed.getSI(); assertEquals("Density should be " + expectedDensity, expectedDensity, value, 0.00001); } else { assertTrue("Data should be NaN", java.lang.Double.isNaN(value)); } shouldHaveData = sample <= bucket; value = fd.getYValue(0, sample); if (shouldHaveData) { double expectedFlow = sample == bucket ? 3600 / aggregationTime.getSI() : 0; assertEquals("Flow should be " + expectedFlow, expectedFlow, value, 0.00001); } else { assertTrue("Data should be NaN", java.lang.Double.isNaN(value)); } value = fd.getY(0, sample).doubleValue(); if (shouldHaveData) { double expectedFlow = sample == bucket ? 3600 / aggregationTime.getSI() : 0; assertEquals("Flow should be " + expectedFlow, expectedFlow, value, 0.00001); } else { assertTrue("Data should be NaN", java.lang.Double.isNaN(value)); } fd.actionPerformed(setXToSpeed); value = fd.getYValue(0, sample); if (shouldHaveData) { double expectedSpeed = sample == bucket ? speed.getInUnit() : 0; assertEquals("Speed should be " + expectedSpeed, expectedSpeed, value, 0.00001); } else { assertTrue("Data should be NaN", java.lang.Double.isNaN(value)); } value = fd.getY(0, sample).doubleValue(); if (shouldHaveData) { double expectedSpeed = sample == bucket ? speed.getInUnit() : 0; assertEquals("Speed should be " + expectedSpeed, expectedSpeed, value, 0.00001); } else { assertTrue("Data should be NaN", java.lang.Double.isNaN(value)); } fd.actionPerformed(resetAxis); } // Check that harmonic mean speed is computed speed = new Speed(10, KM_PER_HOUR); drivingCharacteristics = new LaneBasedDrivingCharacteristics(gtuFollowingModel, laneChangeModel); strategicalPlanner = new LaneBasedStrategicalRoutePlanner(drivingCharacteristics, new LaneBasedCFLCTacticalPlanner()); new LaneBasedIndividualCar("1234", gtuType, initialLongitudinalPositions, speed, length, width, maxSpeed, simulator, strategicalPlanner, new LanePerceptionFull(), this.network); simulator.runUpTo(new Time.Abs(125, SECOND)); while (simulator.isRunning()) { try { Thread.sleep(1); } catch (InterruptedException ie) { ie = null; // ignore } } fd.actionPerformed(setXToSpeed); value = fd.getYValue(0, bucket); double expected = 2d / (1d / 100 + 1d / 10); // System.out.println("harmonic speed is " + value + ", expected is " + expected); assertEquals("Harmonic mean of 10 and 100 is " + expected, expected, value, 0.0001); // Test the actionPerformed method with various malformed ActionEvents. try { fd.actionPerformed(new ActionEvent(fd, 0, "bla")); fail("Bad ActionEvent should have thrown an Error"); } catch (Error e) { // Ignore } try { fd.actionPerformed(new ActionEvent(fd, 0, "Speed/bla")); fail("Bad ActionEvent should have thrown an Error"); } catch (Error e) { // Ignore } try { fd.actionPerformed(new ActionEvent(fd, 0, "Flow/bla")); fail("Bad ActionEvent should have thrown an Error"); } catch (Error e) { // Ignore } try { fd.actionPerformed(new ActionEvent(fd, 0, "Density/bla")); fail("Bad ActionEvent should have thrown an Error"); } catch (Error e) { // Ignore } try { fd.actionPerformed(new ActionEvent(fd, 0, "bla/Speed")); fail("Bad ActionEvent should have thrown an Error"); } catch (Error e) { // Ignore } try { fd.actionPerformed(new ActionEvent(fd, 0, "bla/Flow")); fail("Bad ActionEvent should have thrown an Error"); } catch (Error e) { // Ignore } try { fd.actionPerformed(new ActionEvent(fd, 0, "bla/Density")); fail("Bad ActionEvent should have thrown an Error"); } catch (Error e) { // Ignore } } /** * Test the updateHint method in the PointerHandler. * @throws Exception when something goes wrong (should not happen) */ @SuppressWarnings("static-method") @Test public final void testHints() throws Exception { Time.Rel aggregationTime = new Time.Rel(30, SECOND); Length.Rel position = new Length.Rel(123, METER); LaneType laneType = new LaneType("CarLane"); FundamentalDiagram fd = new FundamentalDiagram("Fundamental Diagram", aggregationTime, CarTest.makeLane(laneType), position); // First get the panel that stores the result of updateHint (this is ugly) JLabel hintPanel = null; ChartPanel chartPanel = null; for (Component c0 : fd.getComponents()) { for (Component c1 : ((Container) c0).getComponents()) { if (c1 instanceof Container) { for (Component c2 : ((Container) c1).getComponents()) { // System.out.println("c2 is " + c2); if (c2 instanceof Container) { for (Component c3 : ((Container) c2).getComponents()) { // System.out.println("c3 is " + c3); if (c3 instanceof JLabel) { if (null == hintPanel) { hintPanel = (JLabel) c3; } else { fail("There should be only one JPanel in a FundamentalDiagram"); } } if (c3 instanceof ChartPanel) { if (null == chartPanel) { chartPanel = (ChartPanel) c3; } else { fail("There should be only one ChartPanel in a FundamentalDiagram"); } } } } } } } } if (null == hintPanel) { fail("Could not find a JLabel in FundamentalDiagram"); } if (null == chartPanel) { fail("Could not find a ChartPanel in FundamentalDiagram"); } assertEquals("Initially the text should be a single space", " ", hintPanel.getText()); PointerHandler ph = null; for (MouseListener ml : chartPanel.getMouseListeners()) { if (ml instanceof PointerHandler) { if (null == ph) { ph = (PointerHandler) ml; } else { fail("There should be only one PointerHandler on the chartPanel"); } } } if (null == ph) { fail("Could not find the PointerHandler for the chartPanel"); } ph.updateHint(1, 2); // System.out.println("Hint text is now " + hintPanel.getText()); assertFalse("Hint should not be a single space", " ".equals(hintPanel.getText())); ph.updateHint(java.lang.Double.NaN, java.lang.Double.NaN); assertEquals("The text should again be a single space", " ", hintPanel.getText()); } /** {@inheritDoc} */ @Override public void constructModel( SimulatorInterface, DoubleScalar.Rel, OTSSimTimeDouble> arg0) throws SimRuntimeException { // Do nothing } /** {@inheritDoc} */ @Override public SimulatorInterface, DoubleScalar.Rel, OTSSimTimeDouble> getSimulator() { return null; } }