1 package org.opentrafficsim.road.gtu;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertFalse;
5 import static org.junit.Assert.assertTrue;
6 import static org.junit.Assert.fail;
7
8 import java.util.ArrayList;
9 import java.util.Collection;
10 import java.util.HashSet;
11 import java.util.LinkedHashSet;
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.TimeUnit;
18 import org.djunits.unit.UNITS;
19 import org.djunits.value.vdouble.scalar.Acceleration;
20 import org.djunits.value.vdouble.scalar.DoubleScalar;
21 import org.djunits.value.vdouble.scalar.Duration;
22 import org.djunits.value.vdouble.scalar.Length;
23 import org.djunits.value.vdouble.scalar.Speed;
24 import org.djunits.value.vdouble.scalar.Time;
25 import org.junit.Test;
26 import org.opentrafficsim.core.dsol.OTSModelInterface;
27 import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
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.behavioralcharacteristics.BehavioralCharacteristics;
33 import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypes;
34 import org.opentrafficsim.core.idgenerator.IdGenerator;
35 import org.opentrafficsim.core.network.LongitudinalDirectionality;
36 import org.opentrafficsim.core.network.OTSNetwork;
37 import org.opentrafficsim.core.network.OTSNode;
38 import org.opentrafficsim.road.DefaultTestParameters;
39 import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
40 import org.opentrafficsim.road.gtu.lane.perception.categories.DefaultSimplePerception;
41 import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
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.following.IDMPlusOld;
46 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.FixedLaneChangeModel;
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.CrossSectionElement;
52 import org.opentrafficsim.road.network.lane.CrossSectionLink;
53 import org.opentrafficsim.road.network.lane.DirectedLanePosition;
54 import org.opentrafficsim.road.network.lane.Lane;
55 import org.opentrafficsim.road.network.lane.LaneType;
56 import org.opentrafficsim.simulationengine.SimpleSimulator;
57
58
59
60
61
62
63
64
65
66
67
68
69 public class LaneBasedGTUTest implements UNITS
70 {
71
72 private OTSNetwork network = new OTSNetwork("leader follower parallel gtu test network");
73
74
75 private IdGenerator idGenerator = new IdGenerator("id");
76
77
78
79
80
81
82
83
84
85
86 private void leaderFollowerParallel(int truckFromLane, int truckUpToLane, int carLanesCovered) throws Exception
87 {
88
89 if (carLanesCovered < 1)
90 {
91 fail("carLanesCovered must be >= 1 (got " + carLanesCovered + ")");
92 }
93 if (truckUpToLane < truckFromLane)
94 {
95 fail("truckUpToLane must be >= truckFromLane");
96 }
97 OTSModelInterface model = new Model();
98 SimpleSimulator simulator =
99 new SimpleSimulator(new Time(0.0, SECOND), new Duration(0.0, SECOND), new Duration(3600.0, SECOND), model);
100 GTUType carType = new GTUType("car");
101 GTUType truckType = new GTUType("truck");
102 Set<GTUType> compatibility = new HashSet<GTUType>();
103 compatibility.add(carType);
104 compatibility.add(truckType);
105 LaneType laneType = new LaneType("CarLane", compatibility);
106
107 ArrayList<OTSNode> nodes = new ArrayList<OTSNode>();
108 int[] linkBoundaries = { 0, 25, 50, 100, 101, 102, 103, 104, 105, 150, 175, 200 };
109 for (int xPos : linkBoundaries)
110 {
111 nodes.add(new OTSNode(this.network, "Node at " + xPos, new OTSPoint3D(xPos, 20, 0)));
112 }
113
114 ArrayList<CrossSectionLink> links = new ArrayList<CrossSectionLink>();
115 final int laneCount = 5;
116 for (int i = 1; i < nodes.size(); i++)
117 {
118 OTSNode fromNode = nodes.get(i - 1);
119 OTSNode toNode = nodes.get(i);
120 String linkName = fromNode.getId() + "-" + toNode.getId();
121 Lane[] lanes =
122 LaneFactory.makeMultiLane(this.network, linkName, fromNode, toNode, null, laneCount, laneType, new Speed(
123 100, KM_PER_HOUR), simulator, LongitudinalDirectionality.DIR_PLUS);
124 links.add(lanes[0].getParentLink());
125 }
126
127 Length truckPosition = new Length(99.5, METER);
128 Length truckLength = new Length(15, METER);
129
130 Set<DirectedLanePosition> truckPositions =
131 buildPositionsSet(truckPosition, truckLength, links, truckFromLane, truckUpToLane);
132 Speed truckSpeed = new Speed(0, KM_PER_HOUR);
133 Length truckWidth = new Length(2.5, METER);
134 LaneChangeModel laneChangeModel = new FixedLaneChangeModel(null);
135 Speed maximumSpeed = new Speed(120, KM_PER_HOUR);
136 GTUFollowingModelOld gtuFollowingModel = new IDMPlusOld();
137 BehavioralCharacteristics behavioralCharacteristics = DefaultTestParameters.create();
138
139 LaneBasedIndividualGTU truck =
140 new LaneBasedIndividualGTU("Truck", truckType, truckLength, truckWidth, maximumSpeed, simulator, this.network);
141 LaneBasedStrategicalPlanner strategicalPlanner =
142 new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics, new LaneBasedCFLCTacticalPlanner(
143 gtuFollowingModel, laneChangeModel, truck), truck);
144 truck.init(strategicalPlanner, truckPositions, truckSpeed);
145
146 int lanesChecked = 0;
147 int found = 0;
148 for (CrossSectionLink link : links)
149 {
150 for (CrossSectionElement cse : link.getCrossSectionElementList())
151 {
152 if (cse instanceof Lane)
153 {
154 Lane lane = (Lane) cse;
155 boolean truckPositionsOnLane = false;
156 for (DirectedLanePosition pos : truckPositions)
157 {
158 if (pos.getLane().equals(lane))
159 {
160 truckPositionsOnLane = true;
161 }
162 }
163 if (truckPositionsOnLane)
164 {
165 assertTrue("Truck should be registered on Lane " + lane, lane.getGtuList().contains(truck));
166 found++;
167 }
168 else
169 {
170 assertFalse("Truck should NOT be registered on Lane " + lane, lane.getGtuList().contains(truck));
171 }
172 lanesChecked++;
173 }
174 }
175 }
176
177 assertEquals("lanesChecked should equals the number of Links times the number of lanes on each Link",
178 laneCount * links.size(), lanesChecked);
179 assertEquals("Truck should be registered in " + truckPositions.size() + " lanes", truckPositions.size(), found);
180 Length forwardMaxDistance = truck.getBehavioralCharacteristics().getParameter(ParameterTypes.LOOKAHEAD);
181
182 truck.getTacticalPlanner().getPerception().perceive();
183 Headway leader =
184 truck.getTacticalPlanner().getPerception().getPerceptionCategory(DefaultSimplePerception.class).getForwardHeadway();
185 assertTrue(
186 "With one vehicle in the network forward headway should return a value larger than zero, and smaller than maxDistance",
187 forwardMaxDistance.getSI() >= leader.getDistance().si && leader.getDistance().si > 0);
188 assertEquals("With one vehicle in the network forward headwayGTU should return null", null, leader.getId());
189
190 Length reverseMaxDistance = truck.getBehavioralCharacteristics().getParameter(ParameterTypes.LOOKBACKOLD);
191 Headway follower =
192 truck.getTacticalPlanner().getPerception().getPerceptionCategory(DefaultSimplePerception.class).getBackwardHeadway();
193 assertTrue(
194 "With one vehicle in the network reverse headway should return a value less than zero, and smaller than |maxDistance|",
195 Math.abs(reverseMaxDistance.getSI()) >= Math.abs(follower.getDistance().si) && follower.getDistance().si < 0);
196 assertEquals("With one vehicle in the network reverse headwayGTU should return null", null, follower.getId());
197 Length carLength = new Length(4, METER);
198 Length carWidth = new Length(1.8, METER);
199 Speed carSpeed = new Speed(0, KM_PER_HOUR);
200 int maxStep = linkBoundaries[linkBoundaries.length - 1];
201 for (int laneRank = 0; laneRank < laneCount + 1 - carLanesCovered; laneRank++)
202 {
203 for (int step = 0; step < maxStep; step += 5)
204 {
205 if (laneRank >= truckFromLane && laneRank <= truckUpToLane
206 && step >= truckPosition.getSI() - truckLength.getSI()
207 && step - carLength.getSI() <= truckPosition.getSI())
208 {
209 continue;
210 }
211 Length carPosition = new Length(step, METER);
212 Set<DirectedLanePosition> carPositions =
213 buildPositionsSet(carPosition, carLength, links, laneRank, laneRank + carLanesCovered - 1);
214 behavioralCharacteristics = DefaultTestParameters.create();
215
216 LaneBasedIndividualGTU car =
217 new LaneBasedIndividualGTU("Car", carType, carLength, carWidth, maximumSpeed, simulator, this.network);
218 strategicalPlanner =
219 new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics, new LaneBasedCFLCTacticalPlanner(
220 gtuFollowingModel, laneChangeModel, car), car);
221 car.init(strategicalPlanner, carPositions, carSpeed);
222
223
224 leader =
225 truck.getTacticalPlanner().getPerception().getPerceptionCategory(DefaultSimplePerception.class)
226 .getForwardHeadway();
227 double actualHeadway = leader.getDistance().si;
228 double expectedHeadway =
229 laneRank + carLanesCovered - 1 < truckFromLane || laneRank > truckUpToLane
230 || step - truckPosition.getSI() - truckLength.getSI() <= 0 ? Double.MAX_VALUE : step
231 - truckLength.getSI() - truckPosition.getSI();
232
233
234
235
236 assertEquals("Forward headway should return " + expectedHeadway, expectedHeadway, actualHeadway, 0.1);
237 String leaderGtuId = leader.getId();
238 if (expectedHeadway == Double.MAX_VALUE)
239 {
240 assertEquals("Leader id should be null", null, leaderGtuId);
241 }
242 else
243 {
244 assertEquals("Leader id should be the car id", car, leaderGtuId);
245 }
246
247 follower =
248 truck.getTacticalPlanner().getPerception().getPerceptionCategory(DefaultSimplePerception.class)
249 .getBackwardHeadway();
250 double actualReverseHeadway = follower.getDistance().si;
251 double expectedReverseHeadway =
252 laneRank + carLanesCovered - 1 < truckFromLane || laneRank > truckUpToLane
253 || step + carLength.getSI() >= truckPosition.getSI() ? Double.MAX_VALUE : truckPosition.getSI()
254 - carLength.getSI() - step;
255 assertEquals("Reverse headway should return " + expectedReverseHeadway, expectedReverseHeadway,
256 actualReverseHeadway, 0.1);
257 String followerGtuId = follower.getId();
258 if (expectedReverseHeadway == Double.MAX_VALUE)
259 {
260 assertEquals("Follower id should be null", null, followerGtuId);
261 }
262 else
263 {
264 assertEquals("Follower id should be the car id", car.getId(), followerGtuId);
265 }
266 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
267 {
268 Lane l = null;
269 double cumulativeDistance = 0;
270 for (CrossSectionLink csl : links)
271 {
272 cumulativeDistance += csl.getLength().getSI();
273 if (cumulativeDistance >= truckPosition.getSI())
274 {
275 l = getNthLane(csl, laneIndex);
276 break;
277 }
278 }
279 leader =
280 truck.getTacticalPlanner().getPerception().getPerceptionCategory(DefaultSimplePerception.class)
281 .getForwardHeadway();
282 actualHeadway = leader.getDistance().si;
283 expectedHeadway =
284 laneIndex < laneRank || laneIndex > laneRank + carLanesCovered - 1
285 || step - truckLength.getSI() - truckPosition.getSI() <= 0 ? Double.MAX_VALUE : step
286 - truckLength.getSI() - truckPosition.getSI();
287 assertEquals("Headway on lane " + laneIndex + " should be " + expectedHeadway, expectedHeadway,
288 actualHeadway, 0.001);
289 leaderGtuId = leader.getId();
290 if (laneIndex >= laneRank && laneIndex <= laneRank + carLanesCovered - 1
291 && step - truckLength.getSI() - truckPosition.getSI() > 0)
292 {
293 assertEquals("Leader id should be the car id", car.getId(), leaderGtuId);
294 }
295 else
296 {
297 assertEquals("Leader id should be null", null, leaderGtuId);
298 }
299 follower =
300 truck.getTacticalPlanner().getPerception().getPerceptionCategory(DefaultSimplePerception.class)
301 .getBackwardHeadway();
302 actualReverseHeadway = follower.getDistance().si;
303 expectedReverseHeadway =
304 laneIndex < laneRank || laneIndex > laneRank + carLanesCovered - 1
305 || step + carLength.getSI() >= truckPosition.getSI() ? Double.MAX_VALUE : truckPosition
306 .getSI() - carLength.getSI() - step;
307 assertEquals("Headway on lane " + laneIndex + " should be " + expectedReverseHeadway,
308 expectedReverseHeadway, actualReverseHeadway, 0.001);
309 followerGtuId = follower.getId();
310 if (laneIndex >= laneRank && laneIndex <= laneRank + carLanesCovered - 1
311 && step + carLength.getSI() < truckPosition.getSI())
312 {
313 assertEquals("Follower id should be the car id", car, followerGtuId);
314 }
315 else
316 {
317 assertEquals("Follower id should be null", null, followerGtuId);
318 }
319 }
320 Collection<Headway> leftParallel =
321 truck.getTacticalPlanner().getPerception().getPerceptionCategory(DefaultSimplePerception.class)
322 .getParallelHeadwaysLeft();
323 int expectedLeftSize =
324 laneRank + carLanesCovered - 1 < truckFromLane - 1 || laneRank >= truckUpToLane
325 || step + carLength.getSI() <= truckPosition.getSI()
326 || step > truckPosition.getSI() + truckLength.getSI() ? 0 : 1;
327
328 assertEquals("Left parallel set size should be " + expectedLeftSize, expectedLeftSize, leftParallel.size());
329 boolean foundCar = false;
330 for (Headway hw : leftParallel)
331 {
332 if (car.getId().equals(hw.getId()))
333 {
334 foundCar = true;
335 break;
336 }
337 }
338 assertTrue("car was not found in rightParallel", foundCar);
339 Collection<Headway> rightParallel =
340 truck.getTacticalPlanner().getPerception().getPerceptionCategory(DefaultSimplePerception.class)
341 .getParallelHeadwaysRight();
342 int expectedRightSize =
343 laneRank + carLanesCovered - 1 <= truckFromLane || laneRank > truckUpToLane + 1
344 || step + carLength.getSI() < truckPosition.getSI()
345 || step > truckPosition.getSI() + truckLength.getSI() ? 0 : 1;
346 assertEquals("Right parallel set size should be " + expectedRightSize, expectedRightSize, rightParallel.size());
347 foundCar = false;
348 for (Headway hw : rightParallel)
349 {
350 if (car.getId().equals(hw.getId()))
351 {
352 foundCar = true;
353 break;
354 }
355 }
356 assertTrue("car was not found in rightParallel", foundCar);
357 for (DirectedLanePosition pos : carPositions)
358 {
359 pos.getLane().removeGTU(car, true);
360 }
361 }
362 }
363 }
364
365
366
367
368
369 @Test
370 public void leaderFollowerAndParallelTest() throws Exception
371 {
372
373
374
375
376 }
377
378
379
380
381
382 @Test
383 public void timeAtDistanceTest() throws Exception
384 {
385 for (int a = 1; a >= -1; a--)
386 {
387 this.network = new OTSNetwork("test");
388
389 OTSModelInterface model = new Model();
390 SimpleSimulator simulator =
391 new SimpleSimulator(new Time(0.0, SECOND), new Duration(0.0, SECOND), new Duration(3600.0, SECOND), model);
392
393 simulator.runUpTo(new Time(60, SECOND));
394 while (simulator.isRunning())
395 {
396 try
397 {
398 Thread.sleep(1);
399 }
400 catch (InterruptedException ie)
401 {
402 ie = null;
403 }
404 }
405 GTUType carType = new GTUType("car");
406 Set<GTUType> compatibility = new HashSet<GTUType>();
407 compatibility.add(carType);
408 LaneType laneType = new LaneType("CarLane", compatibility);
409 OTSNode fromNode = new OTSNode(this.network, "Node A", new OTSPoint3D(0, 0, 0));
410 OTSNode toNode = new OTSNode(this.network, "Node B", new OTSPoint3D(1000, 0, 0));
411 String linkName = "AB";
412 Lane lane =
413 LaneFactory.makeMultiLane(this.network, linkName, fromNode, toNode, null, 1, laneType, new Speed(200,
414 KM_PER_HOUR), simulator, LongitudinalDirectionality.DIR_PLUS)[0];
415 Length carPosition = new Length(100, METER);
416 Set<DirectedLanePosition> carPositions = new LinkedHashSet<>(1);
417 carPositions.add(new DirectedLanePosition(lane, carPosition, GTUDirectionality.DIR_PLUS));
418 Speed carSpeed = new Speed(10, METER_PER_SECOND);
419 Acceleration acceleration = new Acceleration(a, METER_PER_SECOND_2);
420 FixedAccelerationModel fam = new FixedAccelerationModel(acceleration, new Duration(10, SECOND));
421 LaneChangeModel laneChangeModel = new FixedLaneChangeModel(null);
422 Speed maximumSpeed = new Speed(200, KM_PER_HOUR);
423 BehavioralCharacteristics behavioralCharacteristics = DefaultTestParameters.create();
424
425 LaneBasedIndividualGTU car =
426 new LaneBasedIndividualGTU("Car" + this.idGenerator.nextId(), carType, new Length(4, METER), new Length(
427 1.8, METER), maximumSpeed, simulator, this.network);
428 LaneBasedStrategicalPlanner strategicalPlanner =
429 new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics, new LaneBasedCFLCTacticalPlanner(fam,
430 laneChangeModel, car), car);
431 car.init(strategicalPlanner, carPositions, carSpeed);
432
433 simulator.runUpTo(new Time(61, SECOND));
434 while (simulator.isRunning())
435 {
436 try
437 {
438 Thread.sleep(1);
439 }
440 catch (InterruptedException ie)
441 {
442 ie = null;
443 }
444 }
445
446
447
448 for (int timeStep = 1; timeStep < 100; timeStep++)
449 {
450 double deltaTime = 0.1 * timeStep;
451 double distanceAtTime = carSpeed.getSI() * deltaTime + 0.5 * acceleration.getSI() * deltaTime * deltaTime;
452
453
454
455
456
457
458
459
460
461 }
462 }
463 }
464
465
466
467
468 public final void autoPauseSimulator()
469 {
470
471 }
472
473
474
475
476
477
478
479
480
481
482 private Set<DirectedLanePosition> buildPositionsSet(Length totalLongitudinalPosition, Length gtuLength,
483 ArrayList<CrossSectionLink> links, int fromLaneRank, int uptoLaneRank)
484 {
485 Set<DirectedLanePosition> result = new LinkedHashSet<>(1);
486 double cumulativeLength = 0;
487 for (CrossSectionLink link : links)
488 {
489 double linkLength = link.getLength().getSI();
490 double frontPositionInLink = totalLongitudinalPosition.getSI() - cumulativeLength + gtuLength.getSI();
491 double rearPositionInLink = frontPositionInLink - gtuLength.getSI();
492 double linkEnd = cumulativeLength + linkLength;
493
494
495 if (rearPositionInLink < linkLength && frontPositionInLink >= 0)
496 {
497
498 for (int laneRank = fromLaneRank; laneRank <= uptoLaneRank; laneRank++)
499 {
500 Lane lane = getNthLane(link, laneRank);
501 if (null == lane)
502 {
503 fail("Error in test; canot find lane with rank " + laneRank);
504 }
505 try
506 {
507 result.add(new DirectedLanePosition(lane, new Length(rearPositionInLink, METER),
508 GTUDirectionality.DIR_PLUS));
509 }
510 catch (GTUException exception)
511 {
512 fail("Error in test; DirectedLanePosition for lane " + lane);
513 }
514 }
515 }
516 cumulativeLength += linkLength;
517 }
518 return result;
519 }
520
521
522
523
524
525
526
527 private Lane getNthLane(final CrossSectionLink link, int rank)
528 {
529 for (CrossSectionElement cse : link.getCrossSectionElementList())
530 {
531 if (cse instanceof Lane)
532 {
533 if (0 == rank--)
534 {
535 return (Lane) cse;
536 }
537 }
538 }
539 return null;
540 }
541 }
542
543
544 class Model implements OTSModelInterface
545 {
546
547
548 private static final long serialVersionUID = 20150127L;
549
550
551 @Override
552 public void constructModel(
553 SimulatorInterface<Time, Duration, OTSSimTimeDouble> simulator)
554 throws SimRuntimeException
555 {
556
557 }
558
559
560 @Override
561 public SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator()
562
563 {
564 return null;
565 }
566
567 }