* Copyright (c) 2013-2016 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 14 jan. 2015
* @author Alexander Verbraeck
* @author Peter Knoppers
*/
public class AbstractLaneBasedGTUTest implements UNITS
{
/** The network. */
private OTSNetwork network = new OTSNetwork("lane base gtu test network");
/**
* Test that the constructor puts the supplied values in the correct fields, then check the motion of the GTU.
* @throws Exception when something goes wrong (should not happen)
*/
@Test
public void abstractLaneBasedGTUTest() throws Exception
{
// This initialization code should probably be moved to a helper method that will be used in several tests.
// First we need a set of Lanes
// To create Lanes we need Nodes and a LaneType
OTSNode nodeAFrom = new OTSNode(this.network, "AFrom", new OTSPoint3D(0, 0, 0));
OTSNode nodeATo = new OTSNode(this.network, "ATo", new OTSPoint3D(1000, 0, 0));
GTUType gtuType = new GTUType("Car");
Set compatibility = new HashSet();
compatibility.add(gtuType);
LaneType laneType = new LaneType("CarLane", compatibility);
// And a simulator, but for that we first need something that implements OTSModelInterface
OTSModelInterface model = new DummyModel();
final SimpleSimulatorInterface simulator =
new SimpleSimulator(new Time(0.0, SECOND), new Duration(0.0, SECOND), new Duration(3600.0, SECOND), model);
Lane[] lanesGroupA =
LaneFactory.makeMultiLane(this.network, "A", nodeAFrom, nodeATo, null, 3, laneType, new Speed(100, KM_PER_HOUR),
simulator, LongitudinalDirectionality.DIR_PLUS);
// A GTU can exist on several lanes at once; create another lane group to test that
OTSNode nodeBFrom = new OTSNode(this.network, "BFrom", new OTSPoint3D(10, 0, 0));
OTSNode nodeBTo = new OTSNode(this.network, "BTo", new OTSPoint3D(1000, 0, 0));
Lane[] lanesGroupB =
LaneFactory.makeMultiLane(this.network, "B", nodeBFrom, nodeBTo, null, 3, laneType, new Speed(100, KM_PER_HOUR),
simulator, LongitudinalDirectionality.DIR_PLUS);
Set initialLongitudinalPositions = new LinkedHashSet<>(2);
Length positionA = new Length(100, METER);
initialLongitudinalPositions.add(new DirectedLanePosition(lanesGroupA[1], positionA, GTUDirectionality.DIR_PLUS));
Length positionB = new Length(90, METER);
initialLongitudinalPositions.add(new DirectedLanePosition(lanesGroupB[1], positionB, GTUDirectionality.DIR_PLUS));
// A Car needs a CarFollowingModel
Acceleration acceleration = new Acceleration(2, METER_PER_SECOND_2);
Duration validFor = new Duration(10, SECOND);
GTUFollowingModelOld gfm = new FixedAccelerationModel(acceleration, validFor);
// A Car needs a lane change model
// AbstractLaneChangeModel laneChangeModel = new Egoistic();
LaneChangeModel laneChangeModel = new FixedLaneChangeModel(null);
// A Car needs an initial speed
Speed initialSpeed = new Speed(50, KM_PER_HOUR);
// Length of the Car
Length carLength = new Length(4, METER);
// Width of the Car
Length carWidth = new Length(1.8, METER);
// Maximum speed of the Car
Speed maximumSpeed = new Speed(200, KM_PER_HOUR);
// ID of the Car
String carID = "theCar";
// List of Nodes visited by the Car
List nodeList = new ArrayList();
nodeList.add(nodeAFrom);
nodeList.add(nodeATo);
// Route of the Car
CompleteRoute route = new CompleteRoute("Route", gtuType, nodeList);
// Now we can make a GTU
BehavioralCharacteristics behavioralCharacteristics = DefaultTestParameters.create(); // new
// BehavioralCharacteristics();
// LaneBasedBehavioralCharacteristics drivingCharacteristics =
// new LaneBasedBehavioralCharacteristics(gfm, laneChangeModel);
LaneBasedIndividualGTU car =
new LaneBasedIndividualGTU(carID, gtuType, carLength, carWidth, maximumSpeed, simulator, this.network);
LaneBasedStrategicalPlanner strategicalPlanner =
new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics, new LaneBasedCFLCTacticalPlanner(gfm,
laneChangeModel, car), car);
car.init(strategicalPlanner, initialLongitudinalPositions, initialSpeed);
// Now we can verify the various fields in the newly created Car
assertEquals("ID of the car should be identical to the provided one", carID, car.getId());
// TODO: Test with gfm as part of tactical planner
// assertEquals("GTU following model should be identical to the provided one", gfm, car
// .getBehavioralCharacteristics().getGTUFollowingModel());
assertEquals("Width should be identical to the provided width", carWidth, car.getWidth());
assertEquals("Length should be identical to the provided length", carLength, car.getLength());
assertEquals("GTU type should be identical to the provided one", gtuType, car.getGTUType());
assertEquals("front in lanesGroupA[1] is positionA", positionA.getSI(), car
.position(lanesGroupA[1], car.getReference()).getSI(), 0.0001);
assertEquals("front in lanesGroupB[1] is positionB", positionB.getSI(), car
.position(lanesGroupB[1], car.getReference()).getSI(), 0.0001);
// assertEquals("acceleration is 0", 0, car.getAcceleration().getSI(), 0.00001);
// edit wouter schakel: fixed acceleration model has a=2.0m/s^2, first plan is made during initialization
assertEquals("acceleration is 2", 2.0, car.getAcceleration().getSI(), 0.00001);
assertEquals("longitudinal speed is " + initialSpeed, initialSpeed.getSI(), car.getSpeed().getSI(), 0.00001);
assertEquals("lastEvaluation time is 0", 0, car.getOperationalPlan().getStartTime().getSI(), 0.00001);
// Test the position(Lane, RelativePosition) method
try
{
car.position(null, car.getFront());
fail("position on null lane should have thrown a NetworkException");
}
catch (GTUException ne)
{
// Ignore
}
for (Lane[] laneGroup : new Lane[][] { lanesGroupA, lanesGroupB })
{
for (int laneIndex = 0; laneIndex < laneGroup.length; laneIndex++)
{
Lane lane = laneGroup[laneIndex];
boolean expectException = 1 != laneIndex;
for (RelativePosition relativePosition : new RelativePosition[] { car.getFront(), car.getReference(),
car.getRear() })
{
// System.out.println("lane:" + lane + ", expectedException: " + expectException
// + ", relativePostion: " + relativePosition);
try
{
Length position = car.position(lane, relativePosition);
if (expectException)
{
// System.out.println("position: " + position);
fail("Calling position on lane that the car is NOT on should have thrown a NetworkException");
}
else
{
Length expectedPosition = laneGroup == lanesGroupA ? positionA : positionB;
expectedPosition = expectedPosition.plus(relativePosition.getDx());
// System.out.println("reported position: " + position);
// System.out.println("expected position: " + expectedPosition);
assertEquals("Position should match initial position", expectedPosition.getSI(), position.getSI(),
0.0001);
}
}
catch (GTUException ne)
{
if (!expectException)
{
System.out.println(ne);
fail("Calling position on lane that the car is on should NOT have thrown a NetworkException");
}
}
}
}
}
// Assign a movement to the car (10 seconds of acceleration of 2 m/s/s)
// scheduled event that moves the car at t=0
assertEquals("lastEvaluation time is 0", 0, car.getOperationalPlan().getStartTime().getSI(), 0.00001);
// assertEquals("nextEvaluation time is 0", 0, car.getOperationalPlan().getEndTime().getSI(), 0.00001);
// edit wouter schakel: fixed acceleration model has t=10s, first plan is made during initialization
assertEquals("nextEvaluation time is 10", 10.0, car.getOperationalPlan().getEndTime().getSI(), 0.00001);
// Increase the simulator clock in small steps and verify the both positions on all lanes at each step
double step = 0.01d;
for (int i = 0;; i++)
{
Time stepTime = new Time(i * step, SECOND);
if (stepTime.getSI() > validFor.getSI())
{
break;
}
if (stepTime.getSI() > 0.5)
{
step = 0.1; // Reduce testing time by increasing the step size
}
// System.out.println("Simulating until " + stepTime.getSI());
simulator.runUpTo(stepTime);
while (simulator.isRunning())
{
try
{
Thread.sleep(1);
}
catch (InterruptedException ie)
{
ie = null; // ignore
}
}
if (stepTime.getSI() > 0)
{
assertEquals("nextEvaluation time is " + validFor, validFor.getSI(), car.getOperationalPlan().getEndTime()
.getSI(), 0.0001);
assertEquals("acceleration is " + acceleration, acceleration.getSI(), car.getAcceleration().getSI(), 0.00001);
}
Speed longitudinalSpeed = car.getSpeed();
double expectedLongitudinalSpeed = initialSpeed.getSI() + stepTime.getSI() * acceleration.getSI();
assertEquals("longitudinal speed is " + expectedLongitudinalSpeed, expectedLongitudinalSpeed,
longitudinalSpeed.getSI(), 0.00001);
for (RelativePosition relativePosition : new RelativePosition[] { car.getFront(), car.getRear() })
{
Map positions = car.fractionalPositions(relativePosition);
assertEquals("Car should be in two lanes", 2, positions.size());
Double pos = positions.get(lanesGroupA[1]);
// System.out.println("Fractional positions: " + positions);
assertTrue("Car should be in lane 1 of lane group A", null != pos);
assertEquals("fractional position should be equal to result of fractionalPosition(lane, ...)", pos,
car.fractionalPosition(lanesGroupA[1], relativePosition), 0.0000001);
pos = positions.get(lanesGroupB[1]);
assertTrue("Car should be in lane 1 of lane group B", null != pos);
assertEquals("fractional position should be equal to result of fractionalPosition(lane, ...)", pos,
car.fractionalPosition(lanesGroupB[1], relativePosition), 0.0000001);
}
for (Lane[] laneGroup : new Lane[][] { lanesGroupA, lanesGroupB })
{
for (int laneIndex = 0; laneIndex < laneGroup.length; laneIndex++)
{
Lane lane = laneGroup[laneIndex];
boolean expectException = 1 != laneIndex;
for (RelativePosition relativePosition : new RelativePosition[] { car.getFront(), car.getReference(),
car.getRear() })
{
// System.out.println("lane:" + lane + ", expectedException: " + expectException
// + ", relativePostion: " + relativePosition);
try
{
Length position = car.position(lane, relativePosition);
if (expectException)
{
// System.out.println("position: " + position);
fail("Calling position on lane that the car is NOT on should have thrown a "
+ "NetworkException");
}
else
{
Length expectedPosition = laneGroup == lanesGroupA ? positionA : positionB;
expectedPosition =
expectedPosition
.plus(new Length(stepTime.getSI() * initialSpeed.getSI(), LengthUnit.SI));
expectedPosition =
expectedPosition.plus(new Length(0.5 * acceleration.getSI() * stepTime.getSI()
* stepTime.getSI(), LengthUnit.SI));
expectedPosition = expectedPosition.plus(relativePosition.getDx());
// System.out.println("reported position: " + position);
// System.out.println("expected position: " + expectedPosition);
assertEquals("Position should match initial position", expectedPosition.getSI(),
position.getSI(), 0.0001);
}
}
catch (GTUException ne)
{
if (!expectException)
{
System.out.println(ne);
fail("Calling position on lane that the car is on should NOT have thrown a NetworkException");
}
}
try
{
double fractionalPosition = car.fractionalPosition(lane, relativePosition);
if (expectException)
{
// System.out.println("position: " + position);
fail("Calling position on lane that the car is NOT on should have thrown a NetworkException");
}
else
{
Length expectedPosition = laneGroup == lanesGroupA ? positionA : positionB;
expectedPosition =
expectedPosition
.plus(new Length(stepTime.getSI() * initialSpeed.getSI(), LengthUnit.SI));
expectedPosition =
expectedPosition.plus(new Length(0.5 * acceleration.getSI() * stepTime.getSI()
* stepTime.getSI(), LengthUnit.SI));
expectedPosition = expectedPosition.plus(relativePosition.getDx());
// System.out.println("reported position: " + position);
// System.out.println("expected position: " + expectedPosition);
double expectedFractionalPosition = expectedPosition.getSI() / lane.getLength().getSI();
assertEquals("Position should match initial position", expectedFractionalPosition,
fractionalPosition, 0.000001);
}
}
catch (GTUException ne)
{
if (!expectException)
{
System.out.println(ne);
fail("Calling fractionalPosition on lane that the car is on should NOT have thrown a "
+ "NetworkException");
}
}
}
}
}
}
// A GTU can exist on several lanes at once; create another lane group to test that
OTSNode nodeCFrom = new OTSNode(this.network, "CFrom", new OTSPoint3D(10, 100, 0));
OTSNode nodeCTo = new OTSNode(this.network, "CTo", new OTSPoint3D(1000, 0, 0));
Lane[] lanesGroupC =
LaneFactory.makeMultiLane(this.network, "C", nodeCFrom, nodeCTo, null, 3, laneType, new Speed(100, KM_PER_HOUR),
simulator, LongitudinalDirectionality.DIR_PLUS);
car.enterLane(lanesGroupC[0], new Length(0.0, LengthUnit.SI), GTUDirectionality.DIR_PLUS);
for (RelativePosition relativePosition : new RelativePosition[] { car.getFront(), car.getRear() })
{
Map positions = car.fractionalPositions(relativePosition);
assertEquals("Car should be in three lanes", 3, positions.size());
Double pos = positions.get(lanesGroupA[1]);
assertTrue("Car should be in lane 1 of lane group A", null != pos);
assertEquals("fractional position should be equal to result of fractionalPosition(lane, ...)", pos,
car.fractionalPosition(lanesGroupA[1], relativePosition), 0.0000001);
pos = positions.get(lanesGroupB[1]);
assertTrue("Car should be in lane 1 of lane group B", null != pos);
assertEquals("fractional position should be equal to result of fractionalPosition(lane, ...)", pos,
car.fractionalPosition(lanesGroupB[1], relativePosition), 0.0000001);
pos = positions.get(lanesGroupC[0]);
assertTrue("Car should be in lane 0 of lane group C", null != pos);
// The next one fails - maybe I don't understand something - PK
// assertEquals("fractional position should be 0", 0,
// car.fractionalPosition(lanesGroupC[0], relativePosition), 0.0000001);
assertEquals("fractional position should be equal to result of fractionalPosition(lane, ...)", pos,
car.fractionalPosition(lanesGroupC[0], relativePosition), 0.0000001);
}
car.leaveLane(lanesGroupA[1]);
for (RelativePosition relativePosition : new RelativePosition[] { car.getFront(), car.getRear() })
{
Map positions = car.fractionalPositions(relativePosition);
assertEquals("Car should be in two lanes", 2, positions.size());
Double pos = positions.get(lanesGroupB[1]);
assertTrue("Car should be in lane 1 of lane group B", null != pos);
assertEquals("fractional position should be equal to result of fractionalPosition(lane, ...)", pos,
car.fractionalPosition(lanesGroupB[1], relativePosition), 0.0000001);
pos = positions.get(lanesGroupC[0]);
assertTrue("Car should be in lane 0 of lane group C", null != pos);
// The next one fails - maybe I don't understand something - PK
// assertEquals("fractional position should be 0", 0,
// car.fractionalPosition(lanesGroupC[0], relativePosition), 0.0000001);
assertEquals("fractional position should be equal to result of fractionalPosition(lane, ...)", pos,
car.fractionalPosition(lanesGroupC[0], relativePosition), 0.0000001);
}
// TODO removeLane should throw an Error when the car is not on that lane (currently this is silently ignored)
// TODO figure out why the added lane has a non-zero position
}
}
/**
* Dummy OTSModelInterface.
*
* Copyright (c) 2013-2016 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 4 jan. 2015
* @author Peter Knoppers
*/
class DummyModel implements OTSModelInterface
{
/** */
private static final long serialVersionUID = 20150114L;
/** The simulator. */
private SimulatorInterface