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
58
59
60
61
62
63
64
65
66
67
68 public class AbstractLaneBasedGTUTest implements UNITS
69 {
70
71 private OTSNetwork network = new OTSNetwork("lane base gtu test network");
72
73
74
75
76
77 @Test
78 public void abstractLaneBasedGTUTest() throws Exception
79 {
80
81
82
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
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
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
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
114
115 LaneChangeModel laneChangeModel = new FixedLaneChangeModel(null);
116
117 Speed initialSpeed = new Speed(50, KM_PER_HOUR);
118
119 Length carLength = new Length(4, METER);
120
121 Length carWidth = new Length(1.8, METER);
122
123 Speed maximumSpeed = new Speed(200, KM_PER_HOUR);
124
125 String carID = "theCar";
126
127 List<Node> nodeList = new ArrayList<Node>();
128 nodeList.add(nodeAFrom);
129 nodeList.add(nodeATo);
130
131 CompleteRoute route = new CompleteRoute("Route", gtuType, nodeList);
132
133 BehavioralCharacteristics behavioralCharacteristics = DefaultTestParameters.create();
134
135
136
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
144 assertEquals("ID of the car should be identical to the provided one", carID, car.getId());
145
146
147
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
156
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
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
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
180
181 try
182 {
183 Length position = car.position(lane, relativePosition);
184 if (expectException)
185 {
186
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
194
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
211
212 assertEquals("lastEvaluation time is 0", 0, car.getOperationalPlan().getStartTime().getSI(), 0.00001);
213
214
215 assertEquals("nextEvaluation time is 10", 10.0, car.getOperationalPlan().getEndTime().getSI(), 0.00001);
216
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;
228 }
229
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;
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
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
277
278 try
279 {
280 Length position = car.position(lane, relativePosition);
281 if (expectException)
282 {
283
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
298
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
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
330
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
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
371
372
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
388
389
390 assertEquals("fractional position should be equal to result of fractionalPosition(lane, ...)", pos,
391 car.fractionalPosition(lanesGroupC[0], relativePosition), 0.0000001);
392 }
393
394
395 }
396 }
397
398
399
400
401
402
403
404
405
406
407
408 class DummyModel implements OTSModelInterface
409 {
410
411 private static final long serialVersionUID = 20150114L;
412
413
414 private SimulatorInterface<Time, Duration, OTSSimTimeDouble> simulator;
415
416
417
418
419
420 public void setSimulator(
421 SimulatorInterface<Time, Duration, OTSSimTimeDouble> simulator)
422 {
423 this.simulator = simulator;
424 }
425
426
427 @Override
428 public void constructModel(SimulatorInterface<Time, Duration, OTSSimTimeDouble> arg0)
429 throws SimRuntimeException
430 {
431
432 }
433
434
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 }