View Javadoc
1   package org.opentrafficsim.road.gtu;
2   
3   import static org.junit.Assert.assertEquals;
4   import static org.junit.Assert.assertTrue;
5   import static org.junit.Assert.fail;
6   
7   import java.util.ArrayList;
8   import java.util.HashSet;
9   import java.util.LinkedHashSet;
10  import java.util.List;
11  import java.util.Map;
12  import java.util.Set;
13  
14  import nl.tudelft.simulation.dsol.SimRuntimeException;
15  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
16  
17  import org.djunits.unit.LengthUnit;
18  import org.djunits.unit.TimeUnit;
19  import org.djunits.unit.UNITS;
20  import org.djunits.value.vdouble.scalar.Acceleration;
21  import org.djunits.value.vdouble.scalar.DoubleScalar;
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.junit.Test;
27  import org.opentrafficsim.core.dsol.OTSModelInterface;
28  import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
29  import org.opentrafficsim.core.geometry.OTSPoint3D;
30  import org.opentrafficsim.core.gtu.GTUDirectionality;
31  import org.opentrafficsim.core.gtu.GTUException;
32  import org.opentrafficsim.core.gtu.GTUType;
33  import org.opentrafficsim.core.gtu.RelativePosition;
34  import org.opentrafficsim.core.gtu.behavioralcharacteristics.BehavioralCharacteristics;
35  import org.opentrafficsim.core.network.LongitudinalDirectionality;
36  import org.opentrafficsim.core.network.Node;
37  import org.opentrafficsim.core.network.OTSNetwork;
38  import org.opentrafficsim.core.network.OTSNode;
39  import org.opentrafficsim.core.network.route.CompleteRoute;
40  import org.opentrafficsim.road.DefaultTestParameters;
41  import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
42  import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedCFLCTacticalPlanner;
43  import org.opentrafficsim.road.gtu.lane.tactical.following.FixedAccelerationModel;
44  import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
45  import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.FixedLaneChangeModel;
46  import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.LaneChangeModel;
47  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
48  import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlanner;
49  import org.opentrafficsim.road.network.factory.LaneFactory;
50  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
51  import org.opentrafficsim.road.network.lane.Lane;
52  import org.opentrafficsim.road.network.lane.LaneType;
53  import org.opentrafficsim.simulationengine.SimpleSimulator;
54  import org.opentrafficsim.simulationengine.SimpleSimulatorInterface;
55  
56  /**
57   * Test the various methods of an AbstractLaneBasedGTU.<br>
58   * As abstract classes cannot be directly
59   * <p>
60   * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
61   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
62   * <p>
63   * $LastChangedDate: 2015-09-14 01:33:02 +0200 (Mon, 14 Sep 2015) $, @version $Revision: 1401 $, by $Author: averbraeck $,
64   * initial version 14 jan. 2015 <br>
65   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
66   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
67   */
68  public class AbstractLaneBasedGTUTest implements UNITS
69  {
70      /** The network. */
71      private OTSNetwork network = new OTSNetwork("lane base gtu test network");
72  
73      /**
74       * Test that the constructor puts the supplied values in the correct fields, then check the motion of the GTU.
75       * @throws Exception when something goes wrong (should not happen)
76       */
77      @Test
78      public void abstractLaneBasedGTUTest() throws Exception
79      {
80          // This initialization code should probably be moved to a helper method that will be used in several tests.
81          // First we need a set of Lanes
82          // To create Lanes we need Nodes and a LaneType
83          OTSNode nodeAFrom = new OTSNode(this.network, "AFrom", new OTSPoint3D(0, 0, 0));
84          OTSNode nodeATo = new OTSNode(this.network, "ATo", new OTSPoint3D(1000, 0, 0));
85          GTUType gtuType = new GTUType("Car");
86          Set<GTUType> compatibility = new HashSet<GTUType>();
87          compatibility.add(gtuType);
88          LaneType laneType = new LaneType("CarLane", compatibility);
89          // And a simulator, but for that we first need something that implements OTSModelInterface
90          OTSModelInterface model = new DummyModel();
91          final SimpleSimulatorInterface simulator =
92                  new SimpleSimulator(new Time(0.0, SECOND), new Duration(0.0, SECOND), new Duration(3600.0, SECOND), model);
93  
94          Lane[] lanesGroupA =
95                  LaneFactory.makeMultiLane(this.network, "A", nodeAFrom, nodeATo, null, 3, laneType, new Speed(100, KM_PER_HOUR),
96                          simulator, LongitudinalDirectionality.DIR_PLUS);
97          // A GTU can exist on several lanes at once; create another lane group to test that
98          OTSNode nodeBFrom = new OTSNode(this.network, "BFrom", new OTSPoint3D(10, 0, 0));
99          OTSNode nodeBTo = new OTSNode(this.network, "BTo", new OTSPoint3D(1000, 0, 0));
100         Lane[] lanesGroupB =
101                 LaneFactory.makeMultiLane(this.network, "B", nodeBFrom, nodeBTo, null, 3, laneType, new Speed(100, KM_PER_HOUR),
102                         simulator, LongitudinalDirectionality.DIR_PLUS);
103         Set<DirectedLanePosition> initialLongitudinalPositions = new LinkedHashSet<>(2);
104 
105         Length positionA = new Length(100, METER);
106         initialLongitudinalPositions.add(new DirectedLanePosition(lanesGroupA[1], positionA, GTUDirectionality.DIR_PLUS));
107         Length positionB = new Length(90, METER);
108         initialLongitudinalPositions.add(new DirectedLanePosition(lanesGroupB[1], positionB, GTUDirectionality.DIR_PLUS));
109         // A Car needs a CarFollowingModel
110         Acceleration acceleration = new Acceleration(2, METER_PER_SECOND_2);
111         Duration validFor = new Duration(10, SECOND);
112         GTUFollowingModelOld gfm = new FixedAccelerationModel(acceleration, validFor);
113         // A Car needs a lane change model
114         // AbstractLaneChangeModel laneChangeModel = new Egoistic();
115         LaneChangeModel laneChangeModel = new FixedLaneChangeModel(null);
116         // A Car needs an initial speed
117         Speed initialSpeed = new Speed(50, KM_PER_HOUR);
118         // Length of the Car
119         Length carLength = new Length(4, METER);
120         // Width of the Car
121         Length carWidth = new Length(1.8, METER);
122         // Maximum speed of the Car
123         Speed maximumSpeed = new Speed(200, KM_PER_HOUR);
124         // ID of the Car
125         String carID = "theCar";
126         // List of Nodes visited by the Car
127         List<Node> nodeList = new ArrayList<Node>();
128         nodeList.add(nodeAFrom);
129         nodeList.add(nodeATo);
130         // Route of the Car
131         CompleteRoute route = new CompleteRoute("Route", gtuType, nodeList);
132         // Now we can make a GTU
133         BehavioralCharacteristics behavioralCharacteristics = DefaultTestParameters.create(); // new
134                                                                                               // BehavioralCharacteristics();
135         // LaneBasedBehavioralCharacteristics drivingCharacteristics =
136         // new LaneBasedBehavioralCharacteristics(gfm, laneChangeModel);
137         LaneBasedIndividualGTU car =
138                 new LaneBasedIndividualGTU(carID, gtuType, carLength, carWidth, maximumSpeed, simulator, this.network);
139         LaneBasedStrategicalPlanner strategicalPlanner =
140                 new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics, new LaneBasedCFLCTacticalPlanner(gfm,
141                         laneChangeModel, car), car);
142         car.init(strategicalPlanner, initialLongitudinalPositions, initialSpeed);
143         // Now we can verify the various fields in the newly created Car
144         assertEquals("ID of the car should be identical to the provided one", carID, car.getId());
145         // TODO: Test with gfm as part of tactical planner
146         // assertEquals("GTU following model should be identical to the provided one", gfm, car
147         // .getBehavioralCharacteristics().getGTUFollowingModel());
148         assertEquals("Width should be identical to the provided width", carWidth, car.getWidth());
149         assertEquals("Length should be identical to the provided length", carLength, car.getLength());
150         assertEquals("GTU type should be identical to the provided one", gtuType, car.getGTUType());
151         assertEquals("front in lanesGroupA[1] is positionA", positionA.getSI(), car
152                 .position(lanesGroupA[1], car.getReference()).getSI(), 0.0001);
153         assertEquals("front in lanesGroupB[1] is positionB", positionB.getSI(), car
154                 .position(lanesGroupB[1], car.getReference()).getSI(), 0.0001);
155         // assertEquals("acceleration is 0", 0, car.getAcceleration().getSI(), 0.00001);
156         // edit wouter schakel: fixed acceleration model has a=2.0m/s^2, first plan is made during initialization
157         assertEquals("acceleration is 2", 2.0, car.getAcceleration().getSI(), 0.00001);
158         assertEquals("longitudinal speed is " + initialSpeed, initialSpeed.getSI(), car.getSpeed().getSI(), 0.00001);
159         assertEquals("lastEvaluation time is 0", 0, car.getOperationalPlan().getStartTime().getSI(), 0.00001);
160         // Test the position(Lane, RelativePosition) method
161         try
162         {
163             car.position(null, car.getFront());
164             fail("position on null lane should have thrown a NetworkException");
165         }
166         catch (GTUException ne)
167         {
168             // Ignore
169         }
170         for (Lane[] laneGroup : new Lane[][] { lanesGroupA, lanesGroupB })
171         {
172             for (int laneIndex = 0; laneIndex < laneGroup.length; laneIndex++)
173             {
174                 Lane lane = laneGroup[laneIndex];
175                 boolean expectException = 1 != laneIndex;
176                 for (RelativePosition relativePosition : new RelativePosition[] { car.getFront(), car.getReference(),
177                         car.getRear() })
178                 {
179                     // System.out.println("lane:" + lane + ", expectedException: " + expectException
180                     // + ", relativePostion: " + relativePosition);
181                     try
182                     {
183                         Length position = car.position(lane, relativePosition);
184                         if (expectException)
185                         {
186                             // System.out.println("position: " + position);
187                             fail("Calling position on lane that the car is NOT on should have thrown a NetworkException");
188                         }
189                         else
190                         {
191                             Length expectedPosition = laneGroup == lanesGroupA ? positionA : positionB;
192                             expectedPosition = expectedPosition.plus(relativePosition.getDx());
193                             // System.out.println("reported position: " + position);
194                             // System.out.println("expected position: " + expectedPosition);
195                             assertEquals("Position should match initial position", expectedPosition.getSI(), position.getSI(),
196                                     0.0001);
197                         }
198                     }
199                     catch (GTUException ne)
200                     {
201                         if (!expectException)
202                         {
203                             System.out.println(ne);
204                             fail("Calling position on lane that the car is on should NOT have thrown a NetworkException");
205                         }
206                     }
207                 }
208             }
209         }
210         // Assign a movement to the car (10 seconds of acceleration of 2 m/s/s)
211         // scheduled event that moves the car at t=0
212         assertEquals("lastEvaluation time is 0", 0, car.getOperationalPlan().getStartTime().getSI(), 0.00001);
213         // assertEquals("nextEvaluation time is 0", 0, car.getOperationalPlan().getEndTime().getSI(), 0.00001);
214         // edit wouter schakel: fixed acceleration model has t=10s, first plan is made during initialization
215         assertEquals("nextEvaluation time is 10", 10.0, car.getOperationalPlan().getEndTime().getSI(), 0.00001);
216         // Increase the simulator clock in small steps and verify the both positions on all lanes at each step
217         double step = 0.01d;
218         for (int i = 0;; i++)
219         {
220             Time stepTime = new Time(i * step, SECOND);
221             if (stepTime.getSI() > validFor.getSI())
222             {
223                 break;
224             }
225             if (stepTime.getSI() > 0.5)
226             {
227                 step = 0.1; // Reduce testing time by increasing the step size
228             }
229             // System.out.println("Simulating until " + stepTime.getSI());
230             simulator.runUpTo(stepTime);
231             while (simulator.isRunning())
232             {
233                 try
234                 {
235                     Thread.sleep(1);
236                 }
237                 catch (InterruptedException ie)
238                 {
239                     ie = null; // ignore
240                 }
241             }
242 
243             if (stepTime.getSI() > 0)
244             {
245                 assertEquals("nextEvaluation time is " + validFor, validFor.getSI(), car.getOperationalPlan().getEndTime()
246                         .getSI(), 0.0001);
247                 assertEquals("acceleration is " + acceleration, acceleration.getSI(), car.getAcceleration().getSI(), 0.00001);
248             }
249             Speed longitudinalSpeed = car.getSpeed();
250             double expectedLongitudinalSpeed = initialSpeed.getSI() + stepTime.getSI() * acceleration.getSI();
251             assertEquals("longitudinal speed is " + expectedLongitudinalSpeed, expectedLongitudinalSpeed,
252                     longitudinalSpeed.getSI(), 0.00001);
253             for (RelativePosition relativePosition : new RelativePosition[] { car.getFront(), car.getRear() })
254             {
255                 Map<Lane, Double> positions = car.fractionalPositions(relativePosition);
256                 assertEquals("Car should be in two lanes", 2, positions.size());
257                 Double pos = positions.get(lanesGroupA[1]);
258                 // System.out.println("Fractional positions: " + positions);
259                 assertTrue("Car should be in lane 1 of lane group A", null != pos);
260                 assertEquals("fractional position should be equal to result of fractionalPosition(lane, ...)", pos,
261                         car.fractionalPosition(lanesGroupA[1], relativePosition), 0.0000001);
262                 pos = positions.get(lanesGroupB[1]);
263                 assertTrue("Car should be in lane 1 of lane group B", null != pos);
264                 assertEquals("fractional position should be equal to result of fractionalPosition(lane, ...)", pos,
265                         car.fractionalPosition(lanesGroupB[1], relativePosition), 0.0000001);
266             }
267             for (Lane[] laneGroup : new Lane[][] { lanesGroupA, lanesGroupB })
268             {
269                 for (int laneIndex = 0; laneIndex < laneGroup.length; laneIndex++)
270                 {
271                     Lane lane = laneGroup[laneIndex];
272                     boolean expectException = 1 != laneIndex;
273                     for (RelativePosition relativePosition : new RelativePosition[] { car.getFront(), car.getReference(),
274                             car.getRear() })
275                     {
276                         // System.out.println("lane:" + lane + ", expectedException: " + expectException
277                         // + ", relativePostion: " + relativePosition);
278                         try
279                         {
280                             Length position = car.position(lane, relativePosition);
281                             if (expectException)
282                             {
283                                 // System.out.println("position: " + position);
284                                 fail("Calling position on lane that the car is NOT on should have thrown a "
285                                         + "NetworkException");
286                             }
287                             else
288                             {
289                                 Length expectedPosition = laneGroup == lanesGroupA ? positionA : positionB;
290                                 expectedPosition =
291                                         expectedPosition
292                                                 .plus(new Length(stepTime.getSI() * initialSpeed.getSI(), LengthUnit.SI));
293                                 expectedPosition =
294                                         expectedPosition.plus(new Length(0.5 * acceleration.getSI() * stepTime.getSI()
295                                                 * stepTime.getSI(), LengthUnit.SI));
296                                 expectedPosition = expectedPosition.plus(relativePosition.getDx());
297                                 // System.out.println("reported position: " + position);
298                                 // System.out.println("expected position: " + expectedPosition);
299                                 assertEquals("Position should match initial position", expectedPosition.getSI(),
300                                         position.getSI(), 0.0001);
301                             }
302                         }
303                         catch (GTUException ne)
304                         {
305                             if (!expectException)
306                             {
307                                 System.out.println(ne);
308                                 fail("Calling position on lane that the car is on should NOT have thrown a NetworkException");
309                             }
310                         }
311                         try
312                         {
313                             double fractionalPosition = car.fractionalPosition(lane, relativePosition);
314                             if (expectException)
315                             {
316                                 // System.out.println("position: " + position);
317                                 fail("Calling position on lane that the car is NOT on should have thrown a NetworkException");
318                             }
319                             else
320                             {
321                                 Length expectedPosition = laneGroup == lanesGroupA ? positionA : positionB;
322                                 expectedPosition =
323                                         expectedPosition
324                                                 .plus(new Length(stepTime.getSI() * initialSpeed.getSI(), LengthUnit.SI));
325                                 expectedPosition =
326                                         expectedPosition.plus(new Length(0.5 * acceleration.getSI() * stepTime.getSI()
327                                                 * stepTime.getSI(), LengthUnit.SI));
328                                 expectedPosition = expectedPosition.plus(relativePosition.getDx());
329                                 // System.out.println("reported position: " + position);
330                                 // System.out.println("expected position: " + expectedPosition);
331                                 double expectedFractionalPosition = expectedPosition.getSI() / lane.getLength().getSI();
332                                 assertEquals("Position should match initial position", expectedFractionalPosition,
333                                         fractionalPosition, 0.000001);
334                             }
335                         }
336                         catch (GTUException ne)
337                         {
338                             if (!expectException)
339                             {
340                                 System.out.println(ne);
341                                 fail("Calling fractionalPosition on lane that the car is on should NOT have thrown a "
342                                         + "NetworkException");
343                             }
344                         }
345                     }
346                 }
347             }
348         }
349         // A GTU can exist on several lanes at once; create another lane group to test that
350         OTSNode nodeCFrom = new OTSNode(this.network, "CFrom", new OTSPoint3D(10, 100, 0));
351         OTSNode nodeCTo = new OTSNode(this.network, "CTo", new OTSPoint3D(1000, 0, 0));
352         Lane[] lanesGroupC =
353                 LaneFactory.makeMultiLane(this.network, "C", nodeCFrom, nodeCTo, null, 3, laneType, new Speed(100, KM_PER_HOUR),
354                         simulator, LongitudinalDirectionality.DIR_PLUS);
355         car.enterLane(lanesGroupC[0], new Length(0.0, LengthUnit.SI), GTUDirectionality.DIR_PLUS);
356         for (RelativePosition relativePosition : new RelativePosition[] { car.getFront(), car.getRear() })
357         {
358             Map<Lane, Double> positions = car.fractionalPositions(relativePosition);
359             assertEquals("Car should be in three lanes", 3, positions.size());
360             Double pos = positions.get(lanesGroupA[1]);
361             assertTrue("Car should be in lane 1 of lane group A", null != pos);
362             assertEquals("fractional position should be equal to result of fractionalPosition(lane, ...)", pos,
363                     car.fractionalPosition(lanesGroupA[1], relativePosition), 0.0000001);
364             pos = positions.get(lanesGroupB[1]);
365             assertTrue("Car should be in lane 1 of lane group B", null != pos);
366             assertEquals("fractional position should be equal to result of fractionalPosition(lane, ...)", pos,
367                     car.fractionalPosition(lanesGroupB[1], relativePosition), 0.0000001);
368             pos = positions.get(lanesGroupC[0]);
369             assertTrue("Car should be in lane 0 of lane group C", null != pos);
370             // The next one fails - maybe I don't understand something - PK
371             // assertEquals("fractional position should be 0", 0,
372             // car.fractionalPosition(lanesGroupC[0], relativePosition), 0.0000001);
373             assertEquals("fractional position should be equal to result of fractionalPosition(lane, ...)", pos,
374                     car.fractionalPosition(lanesGroupC[0], relativePosition), 0.0000001);
375         }
376         car.leaveLane(lanesGroupA[1]);
377         for (RelativePosition relativePosition : new RelativePosition[] { car.getFront(), car.getRear() })
378         {
379             Map<Lane, Double> positions = car.fractionalPositions(relativePosition);
380             assertEquals("Car should be in two lanes", 2, positions.size());
381             Double pos = positions.get(lanesGroupB[1]);
382             assertTrue("Car should be in lane 1 of lane group B", null != pos);
383             assertEquals("fractional position should be equal to result of fractionalPosition(lane, ...)", pos,
384                     car.fractionalPosition(lanesGroupB[1], relativePosition), 0.0000001);
385             pos = positions.get(lanesGroupC[0]);
386             assertTrue("Car should be in lane 0 of lane group C", null != pos);
387             // The next one fails - maybe I don't understand something - PK
388             // assertEquals("fractional position should be 0", 0,
389             // car.fractionalPosition(lanesGroupC[0], relativePosition), 0.0000001);
390             assertEquals("fractional position should be equal to result of fractionalPosition(lane, ...)", pos,
391                     car.fractionalPosition(lanesGroupC[0], relativePosition), 0.0000001);
392         }
393         // TODO removeLane should throw an Error when the car is not on that lane (currently this is silently ignored)
394         // TODO figure out why the added lane has a non-zero position
395     }
396 }
397 
398 /**
399  * Dummy OTSModelInterface.
400  * <p>
401  * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
402  * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
403  * <p>
404  * $LastChangedDate: 2015-09-14 01:33:02 +0200 (Mon, 14 Sep 2015) $, @version $Revision: 1401 $, by $Author: averbraeck $,
405  * initial version 4 jan. 2015 <br>
406  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
407  */
408 class DummyModel implements OTSModelInterface
409 {
410     /** */
411     private static final long serialVersionUID = 20150114L;
412 
413     /** The simulator. */
414     private SimulatorInterface<Time, Duration, OTSSimTimeDouble> simulator;
415 
416     /**
417      * Register the simulator.
418      * @param simulator SimulatorInterface&lt;Time, Duration, OTSSimTimeDouble&gt;; the simulator
419      */
420     public void setSimulator(
421             SimulatorInterface<Time, Duration, OTSSimTimeDouble> simulator)
422     {
423         this.simulator = simulator;
424     }
425 
426     /** {@inheritDoc} */
427     @Override
428     public void constructModel(SimulatorInterface<Time, Duration, OTSSimTimeDouble> arg0)
429             throws SimRuntimeException
430     {
431         // Nothing happens here
432     }
433 
434     /** {@inheritDoc} */
435     @Override
436     public SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator()
437 
438     {
439         if (null == this.simulator)
440         {
441             throw new Error("getSimulator called, but simulator field is null");
442         }
443         return this.simulator;
444     }
445 
446 }