View Javadoc
1   package org.opentrafficsim.road.network.lane.object.sensor;
2   
3   import static org.junit.Assert.assertEquals;
4   import static org.opentrafficsim.road.gtu.lane.RoadGTUTypes.TRUCK;
5   
6   import java.rmi.RemoteException;
7   import java.util.ArrayList;
8   import java.util.LinkedHashSet;
9   import java.util.List;
10  import java.util.Set;
11  
12  import javax.naming.NamingException;
13  
14  import org.djunits.unit.AccelerationUnit;
15  import org.djunits.unit.DurationUnit;
16  import org.djunits.unit.LengthUnit;
17  import org.djunits.unit.SpeedUnit;
18  import org.djunits.unit.TimeUnit;
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.opentrafficsim.core.dsol.OTSDEVSSimulator;
25  import org.opentrafficsim.core.dsol.OTSModelInterface;
26  import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
27  import org.opentrafficsim.core.geometry.OTSGeometryException;
28  import org.opentrafficsim.core.geometry.OTSPoint3D;
29  import org.opentrafficsim.core.gtu.GTUDirectionality;
30  import org.opentrafficsim.core.gtu.GTUException;
31  import org.opentrafficsim.core.gtu.GTUType;
32  import org.opentrafficsim.core.gtu.RelativePosition;
33  import org.opentrafficsim.core.gtu.RelativePosition.TYPE;
34  import org.opentrafficsim.core.gtu.behavioralcharacteristics.BehavioralCharacteristics;
35  import org.opentrafficsim.core.network.LongitudinalDirectionality;
36  import org.opentrafficsim.core.network.NetworkException;
37  import org.opentrafficsim.core.network.OTSNetwork;
38  import org.opentrafficsim.core.network.OTSNode;
39  import org.opentrafficsim.road.DefaultTestParameters;
40  import org.opentrafficsim.road.gtu.lane.AbstractLaneBasedGTU;
41  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
42  import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
43  import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedCFLCTacticalPlanner;
44  import org.opentrafficsim.road.gtu.lane.tactical.following.FixedAccelerationModel;
45  import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
46  import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.Egoistic;
47  import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.LaneChangeModel;
48  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
49  import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlanner;
50  import org.opentrafficsim.road.network.factory.LaneFactory;
51  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
52  import org.opentrafficsim.road.network.lane.Lane;
53  import org.opentrafficsim.road.network.lane.LaneType;
54  import org.opentrafficsim.simulationengine.SimpleSimulator;
55  
56  import nl.tudelft.simulation.dsol.SimRuntimeException;
57  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
58  import nl.tudelft.simulation.event.EventInterface;
59  import nl.tudelft.simulation.event.EventListenerInterface;
60  
61  /**
62   * Test the TrafficLightSensor class.
63   * <p>
64   * Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
65   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
66   * <p>
67   * @version $Revision$, $LastChangedDate$, by $Author$, initial version Nov 7, 2016 <br>
68   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
69   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
70   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
71   */
72  public class TrafficLightSensorTest implements EventListenerInterface
73  {
74  
75      /**
76       * Make a simulator.
77       * @return OTSDEVSSimulator; the new simulator
78       * @throws SimRuntimeException ...
79       * @throws NamingException ...
80       */
81      private static OTSDEVSSimulator makeSimulator() throws SimRuntimeException, NamingException
82      {
83          return new SimpleSimulator(Time.ZERO, Duration.ZERO, new Duration(1, DurationUnit.HOUR), new OTSModelInterface()
84          {
85  
86              /** */
87              private static final long serialVersionUID = 1L;
88  
89              /** Store the simulator. */
90              private SimulatorInterface<Time, Duration, OTSSimTimeDouble> sim;
91  
92              @Override
93              public void constructModel(final SimulatorInterface<Time, Duration, OTSSimTimeDouble> theSimulator)
94                      throws SimRuntimeException, RemoteException
95              {
96                  this.sim = theSimulator;
97              }
98  
99              @Override
100             public SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator() throws RemoteException
101             {
102                 return this.sim;
103             }
104 
105             /** {@inheritDoc} */
106             @Override
107             public OTSNetwork getNetwork()
108             {
109                 return null;
110             }
111         });
112     }
113 
114     /**
115      * Build the test network.
116      * @param lengths double[]; The lengths of the subsequent lanes to construct; negative lengths indicate that the design
117      *            direction must be reversed
118      * @param simulator OTSDEVSSimulator; the simulator
119      * @return Lane[]; an array of linearly connected (single) lanes
120      * @throws NetworkException ...
121      * @throws OTSGeometryException ...
122      * @throws NamingException ...
123      * @throws SimRuntimeException ...
124      */
125     private static Lane[] buildNetwork(final double[] lengths, final OTSDEVSSimulator simulator)
126             throws NetworkException, NamingException, OTSGeometryException, SimRuntimeException
127     {
128         OTSNetwork network = new OTSNetwork("network");
129         OTSNode prevNode = null;
130         Lane[] result = new Lane[lengths.length];
131         LaneType laneType = LaneType.ALL;
132         Speed speedLimit = new Speed(50, SpeedUnit.KM_PER_HOUR);
133         double cumulativeLength = 0;
134         for (int nodeNumber = 0; nodeNumber <= lengths.length; nodeNumber++)
135         {
136             OTSNode node = new OTSNode(network, "node" + nodeNumber, new OTSPoint3D(cumulativeLength, 0, 0));
137             if (null != prevNode)
138             {
139                 LongitudinalDirectionality direction = lengths[nodeNumber - 1] > 0 ? LongitudinalDirectionality.DIR_PLUS
140                         : LongitudinalDirectionality.DIR_MINUS;
141                 OTSNode fromNode = LongitudinalDirectionality.DIR_PLUS == direction ? prevNode : node;
142                 OTSNode toNode = LongitudinalDirectionality.DIR_PLUS == direction ? node : prevNode;
143                 int laneOffset = LongitudinalDirectionality.DIR_PLUS == direction ? 0 : -1;
144                 result[nodeNumber - 1] = LaneFactory.makeMultiLane(network, "Link" + nodeNumber, fromNode, toNode, null, 1,
145                         laneOffset, laneOffset, laneType, speedLimit, simulator, direction)[0];
146                 System.out.println("Created lane with center line " + result[nodeNumber - 1].getCenterLine()
147                         + ", directionality " + direction);
148             }
149             if (nodeNumber < lengths.length)
150             {
151                 cumulativeLength += Math.abs(lengths[nodeNumber]);
152             }
153             prevNode = node;
154         }
155         // put a sink at halfway point of last lane
156         Lane lastLane = result[lengths.length - 1];
157         Length sinkPosition = new Length(lengths[lengths.length - 1] > 0 ? lastLane.getLength().si - 10 : 10, LengthUnit.METER);
158         new SinkSensor(lastLane, sinkPosition, simulator);
159         return result;
160     }
161 
162     /**
163      * Figure out on which lane and at which position we are when we're a given distance from the origin.
164      * @param lanes Lane[]; the sequence of lanes
165      * @param position Length; the distance
166      * @return DirectedLanePosition
167      * @throws GTUException should not happen; if it does; the test has failed
168      */
169     private DirectedLanePosition findLaneAndPosition(final Lane[] lanes, final Length position) throws GTUException
170     {
171         Length remainingLength = position;
172         for (Lane lane : lanes)
173         {
174             if (lane.getLength().ge(remainingLength))
175             {
176                 boolean reverse =
177                         lane.getParentLink().getEndNode().getPoint().x < lane.getParentLink().getStartNode().getPoint().x;
178                 if (reverse)
179                 {
180                     remainingLength = lane.getLength().minus(remainingLength);
181                 }
182                 return new DirectedLanePosition(lane, remainingLength,
183                         reverse ? GTUDirectionality.DIR_MINUS : GTUDirectionality.DIR_PLUS);
184             }
185             remainingLength = remainingLength.minus(lane.getLength());
186         }
187         return null;
188     }
189 
190     /**
191      * Test the TrafficLightSensor.
192      * @throws SimRuntimeException if that happens (uncaught) this test has failed
193      * @throws OTSGeometryException if that happens (uncaught) this test has failed
194      * @throws NamingException if that happens (uncaught) this test has failed
195      * @throws NetworkException if that happens (uncaught) this test has failed
196      * @throws GTUException if that happens (uncaught) this test has failed
197      */
198     // XXX @Test
199     public final void trafficLightSensorTest()
200             throws NetworkException, NamingException, OTSGeometryException, SimRuntimeException, GTUException
201     {
202         double[][] lengthLists =
203                 { { 101.1, -1, 1, -1, 1, -900 }, { 1000 }, { -1000 }, { 101.1, 900 }, { 101.1, 1, 1, 1, 1, 900 }, };
204         for (double[] lengthList : lengthLists)
205         {
206             for (int pos = 50; pos < 130; pos++)
207             {
208                 System.out.println("Number of lanes is " + lengthList.length + " pos is " + pos);
209                 OTSDEVSSimulator simulator = makeSimulator();
210                 Lane[] lanes = buildNetwork(lengthList, simulator);
211                 OTSNetwork network = (OTSNetwork) lanes[0].getParentLink().getNetwork();
212                 Length a = new Length(100, LengthUnit.METER);
213                 Length b = new Length(120, LengthUnit.METER);
214                 DirectedLanePosition pA = findLaneAndPosition(lanes, a);
215                 DirectedLanePosition pB = findLaneAndPosition(lanes, b);
216                 String sensorId = "D123";
217                 TYPE entryPosition = RelativePosition.FRONT;
218                 TYPE exitPosition = RelativePosition.REAR;
219                 List<Lane> intermediateLanes = null;
220                 if (lanes.length > 2)
221                 {
222                     intermediateLanes = new ArrayList<>();
223                     for (Lane lane : lanes)
224                     {
225                         if (lane.equals(pA.getLane()))
226                         {
227                             continue;
228                         }
229                         if (lane.equals(pB.getLane()))
230                         {
231                             break;
232                         }
233                         intermediateLanes.add(lane);
234                     }
235                 }
236                 TrafficLightSensor tls = new TrafficLightSensor(sensorId, pA.getLane(), pA.getPosition(), pB.getLane(),
237                         pB.getPosition(), intermediateLanes, entryPosition, exitPosition, simulator);
238                 assertEquals("Id should match the provided id", sensorId, tls.getId());
239                 assertEquals("Simulator should match", simulator, tls.getSimulator());
240                 assertEquals("Entry position", entryPosition, tls.getPositionTypeEntry());
241                 assertEquals("Exit position", exitPosition, tls.getPositionTypeExit());
242                 assertEquals("Position a", pA.getPosition().si, tls.getLanePositionA().si, 0.00001);
243                 assertEquals("Position b", pB.getPosition().si, tls.getLanePositionB().si, 0.00001);
244                 this.loggedEvents.clear();
245                 assertEquals("event list is empty", 0, this.loggedEvents.size());
246                 tls.addListener(this, NonDirectionalOccupancySensor.NON_DIRECTIONAL_OCCUPANCY_SENSOR_TRIGGER_ENTRY_EVENT);
247                 tls.addListener(this, NonDirectionalOccupancySensor.NON_DIRECTIONAL_OCCUPANCY_SENSOR_TRIGGER_EXIT_EVENT);
248                 assertEquals("event list is empty", 0, this.loggedEvents.size());
249 
250                 GTUType gtuType = TRUCK;
251                 Length gtuLength = new Length(17, LengthUnit.METER);
252                 Length gtuWidth = new Length(2, LengthUnit.METER);
253                 Speed maximumSpeed = new Speed(90, SpeedUnit.KM_PER_HOUR);
254                 LaneBasedGTU gtu =
255                         new LaneBasedIndividualGTU("GTU1", gtuType, gtuLength, gtuWidth, maximumSpeed, simulator, network);
256                 Set<DirectedLanePosition> initialLongitudinalPositions = new LinkedHashSet<>(1);
257                 Length initialPosition = new Length(pos, LengthUnit.METER);
258                 DirectedLanePosition gtuPosition = findLaneAndPosition(lanes, initialPosition);
259                 initialLongitudinalPositions.add(new DirectedLanePosition(gtuPosition.getLane(), gtuPosition.getPosition(),
260                         gtuPosition.getGtuDirection()));
261                 BehavioralCharacteristics behavioralCharacteristics = DefaultTestParameters.create();
262                 LaneChangeModel laneChangeModel = new Egoistic();
263                 GTUFollowingModelOld gtuFollowingModel = new FixedAccelerationModel(
264                         new Acceleration(0, AccelerationUnit.METER_PER_SECOND_2), new Duration(10, DurationUnit.SECOND));
265                 LaneBasedStrategicalPlanner strategicalPlanner = new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics,
266                         new LaneBasedCFLCTacticalPlanner(gtuFollowingModel, laneChangeModel, gtu), gtu);
267                 Speed initialSpeed = new Speed(10, SpeedUnit.METER_PER_SECOND);
268                 if (lanes.length == 6 && pos >= 103)
269                 {
270                     System.out.println("let op. InitialLongitudinalPositions: " + initialLongitudinalPositions);
271                 }
272                 ((AbstractLaneBasedGTU) gtu).init(strategicalPlanner, initialLongitudinalPositions, initialSpeed);
273                 if (initialPosition.plus(gtuLength.divideBy(2)).lt(a) || initialPosition.minus(gtuLength.divideBy(2)).gt(b))
274                 {
275                     assertEquals("event list is empty", 0, this.loggedEvents.size());
276                 }
277                 else
278                 {
279                     if (1 != this.loggedEvents.size())
280                     {
281                         // TODO THIS TEST FAILS!!
282                         // assertEquals("event list should contain one event (due to creation of the GTU on the detector)", 1,
283                         // this.loggedEvents.size());
284                     }
285                 }
286                 Time stopTime = new Time(100, TimeUnit.BASE_SECOND);
287                 while (simulator.getSimulatorTime().get().lt(stopTime))
288                 {
289                     // System.out.println("simulation time is now " + simulator);
290                     simulator.step();
291                 }
292                 System.out.println("simulation time is now " + simulator);
293                 if (initialPosition.minus(gtuLength.divideBy(2)).lt(b))
294                 {
295                     assertEquals("event list contains 2 events", 2, this.loggedEvents.size());
296                 }
297                 else
298                 {
299                     assertEquals("event list contains 0 events", 0, this.loggedEvents.size());
300                 }
301                 simulator.cleanUp();
302             }
303         }
304     }
305 
306     /** Storage for logged events. */
307     private List<EventInterface> loggedEvents = new ArrayList<>();
308 
309     /** {@inheritDoc} */
310     @Override
311     public final void notify(final EventInterface event) throws RemoteException
312     {
313         System.out.println("Received event " + event);
314         this.loggedEvents.add(event);
315     }
316 
317 }