1 package org.opentrafficsim.road.gtu.lane.tactical.util;
2
3 import static org.opentrafficsim.core.gtu.behavioralcharacteristics.AbstractParameterType.Check.ATLEASTONE;
4 import static org.opentrafficsim.core.gtu.behavioralcharacteristics.AbstractParameterType.Check.POSITIVE;
5
6 import java.io.Serializable;
7 import java.util.ArrayList;
8 import java.util.HashMap;
9 import java.util.HashSet;
10 import java.util.Iterator;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.Set;
14 import java.util.SortedMap;
15 import java.util.SortedSet;
16 import java.util.TreeMap;
17
18 import org.djunits.unit.AccelerationUnit;
19 import org.djunits.unit.LengthUnit;
20 import org.djunits.unit.TimeUnit;
21 import org.djunits.value.vdouble.scalar.Acceleration;
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.opentrafficsim.core.Throw;
27 import org.opentrafficsim.core.gtu.GTUException;
28 import org.opentrafficsim.core.gtu.behavioralcharacteristics.BehavioralCharacteristics;
29 import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterException;
30 import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypeDouble;
31 import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypeDuration;
32 import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypeLength;
33 import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypes;
34 import org.opentrafficsim.road.gtu.lane.perception.headway.AbstractHeadwayGTU;
35 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayConflict;
36 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayStopLine;
37 import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
38 import org.opentrafficsim.road.network.speed.SpeedLimitInfo;
39
40 /**
41 * This class implements default behavior for intersection conflicts for use in tactical planners.
42 * <p>
43 * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
44 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
45 * <p>
46 * @version $Revision$, $LastChangedDate$, by $Author$, initial version Jun 3, 2016 <br>
47 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
48 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
49 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
50 */
51 public final class ConflictUtil
52 {
53
54 /** Minimum time gap between events. */
55 public static final ParameterTypeDuration MIN_GAP = new ParameterTypeDuration("minGap", "Minimum gap for conflicts.",
56 new Duration(1.0, TimeUnit.SECOND), POSITIVE);
57
58 /** Multiplication factor on time for conservative assessment. */
59 public static final ParameterTypeDouble TIME_FACTOR = new ParameterTypeDouble("timeFactor",
60 "Safety factor on estimated time.", 1.25, ATLEASTONE);
61
62 /** Area before stop line where one is considered arrived at the intersection. */
63 public static final ParameterTypeLength STOP_AREA = new ParameterTypeLength("stopArea",
64 "Area before stop line where one is considered arrived at the intersection.", new Length(4, LengthUnit.METER),
65 POSITIVE);
66
67 /**
68 * Do not instantiate.
69 */
70 private ConflictUtil()
71 {
72 //
73 }
74
75 /**
76 * Approach conflicts by applying appropriate acceleration (or deceleration). The model may yield for a vehicle even while
77 * having priority. Such a 'yield plan' is remembered in <tt>YieldPlans</tt>. By forwarding the same <tt>YieldPlans</tt> for
78 * a GTU consistency of such plans is provided. If any conflict is not accepted to pass, stopping before a more upstream
79 * conflict is applied if there not sufficient stopping length in between conflicts.
80 * @param behavioralCharacteristics behavioral characteristics
81 * @param conflicts set of conflicts to approach
82 * @param leaders leading vehicles
83 * @param carFollowingModel car-following model
84 * @param vehicleLength length of vehicle
85 * @param speed current speed
86 * @param speedLimitInfo speed limit info
87 * @param conflictPlans set of plans for conflict
88 * @return acceleration appropriate for approaching the conflicts
89 * @throws GTUException in case of an unsupported conflict rule
90 * @throws ParameterException if a parameter is not defined or out of bounds
91 */
92 @SuppressWarnings("checkstyle:parameternumber")
93 public static Acceleration approachConflicts(final BehavioralCharacteristics behavioralCharacteristics,
94 final SortedSet<HeadwayConflict> conflicts, final SortedSet<AbstractHeadwayGTU> leaders,
95 final CarFollowingModel carFollowingModel, final Length vehicleLength, final Speed speed,
96 final SpeedLimitInfo speedLimitInfo, final ConflictPlans conflictPlans) throws GTUException, ParameterException
97 {
98
99 Length stopLength = behavioralCharacteristics.getParameter(ParameterTypes.S0).plus(vehicleLength);
100 List<Length> prevStarts = new ArrayList<>();
101 List<Length> prevEnds = new ArrayList<>();
102 Acceleration a = new Acceleration(Double.POSITIVE_INFINITY, AccelerationUnit.SI);
103 conflictPlans.cleanYieldPlans();
104
105 for (HeadwayConflict conflict : conflicts)
106 {
107
108 // adjust acceleration for situations where stopping might not be required
109 if (conflict.isCrossing())
110 {
111 // avoid collision if crossing is occupied
112 a =
113 Acceleration.min(a, avoidCrossingCollision(behavioralCharacteristics, conflict, carFollowingModel,
114 speed, speedLimitInfo));
115 }
116 else
117 {
118 // follow leading GTUs on merge or split
119 a =
120 Acceleration.min(a, followConflictingLeaderOnMergeOrSplit(conflict, behavioralCharacteristics,
121 carFollowingModel, speed, speedLimitInfo));
122 }
123
124 // determine if we need to stop
125 boolean stop;
126 switch (conflict.getConflictRule())
127 {
128 case PRIORITY:
129 {
130 stop =
131 stopForPriorityConflict(conflict, leaders, speed, stopLength, vehicleLength,
132 behavioralCharacteristics, conflictPlans);
133 break;
134 }
135 case GIVE_WAY:
136 {
137 stop =
138 stopForGiveWayConflict(conflict, leaders, speed, stopLength, vehicleLength,
139 behavioralCharacteristics, speedLimitInfo, carFollowingModel);
140 break;
141 }
142 case STOP:
143 {
144 stop =
145 stopForStopConflict(conflict, leaders, speed, stopLength, vehicleLength, behavioralCharacteristics,
146 speedLimitInfo, carFollowingModel);
147 break;
148 }
149 case ALL_STOP:
150 {
151 stop = stopForAllStopConflict(conflict, conflictPlans);
152 break;
153 }
154 default:
155 {
156 throw new GTUException("Unsupported conflict rule encountered while approaching conflicts.");
157 }
158 }
159
160 // stop if required, account for upstream conflicts to keep clear
161 prevStarts.add(conflict.getDistance());
162 if (stop)
163 {
164 // stop for first conflict looking upstream of this blocked conflict that allows sufficient space
165 int j = 0; // most upstream conflict if not in between conflicts
166 for (int i = prevEnds.size() - 1; i >= 0; i--) // downstream to upstream
167 {
168 // note, at this point prevStarts contains one more conflict than prevEnds
169 if (prevStarts.get(i + 1).minus(prevEnds.get(i)).gt(stopLength))
170 {
171 j = i + 1;
172 break;
173 }
174 }
175 // stop for j'th conflict, further conflicts may be ignored
176 return Acceleration.min(a, CarFollowingUtil.stop(carFollowingModel, behavioralCharacteristics, speed,
177 speedLimitInfo, prevStarts.get(j)));
178 }
179 prevEnds.add(conflict.getDistance().plus(conflict.getLength()));
180
181 }
182
183 return a;
184 }
185
186 /**
187 * Determines acceleration for following conflicting vehicles <i>on</i> a merge or split conflict.
188 * @param conflict merge or split conflict
189 * @param behavioralCharacteristics behavioral characteristics
190 * @param carFollowingModel car-following model
191 * @param speed current speed
192 * @param speedLimitInfo speed limit info
193 * @return acceleration for following conflicting vehicles <i>on</i> a merge or split conflict
194 * @throws ParameterException if a parameter is not given or out of bounds
195 */
196 private static Acceleration followConflictingLeaderOnMergeOrSplit(final HeadwayConflict conflict,
197 final BehavioralCharacteristics behavioralCharacteristics, final CarFollowingModel carFollowingModel,
198 final Speed speed, final SpeedLimitInfo speedLimitInfo) throws ParameterException
199 {
200 // ignore if no conflicting GTU's
201 if (conflict.getDownstreamConflictingGTUs().isEmpty())
202 {
203 return new Acceleration(Double.POSITIVE_INFINITY, AccelerationUnit.SI);
204 }
205 // get the most upstream GTU to consider
206 AbstractHeadwayGTU c = conflict.getDownstreamConflictingGTUs().first();
207 if (c.isAhead())
208 {
209 // conflict GTU completely downstream of conflict (i.e. regular car-following, ignore here)
210 return new Acceleration(Double.POSITIVE_INFINITY, AccelerationUnit.SI);
211 }
212 // conflict GTU (partially) on the conflict
213 // TODO plus? confused about rear overlap for two other things... tailway?
214 // {@formatter:off}
215 // ______________________________________________
216 // ___ virtual headway | ___ |
217 // |___|(-----------------------)|___|(vehicle from south, on lane from south)
218 // _____________________________|_______|________
219 // / /
220 // / /
221 // {@formatter:on}
222 Length virtualHeadway = conflict.getDistance().plus(c.getOverlapRear());
223 // follow leader
224 SortedMap<Length, Speed> leaders = new TreeMap<>();
225 leaders.put(virtualHeadway, c.getSpeed());
226 Acceleration a = carFollowingModel.followingAcceleration(behavioralCharacteristics, speed, speedLimitInfo, leaders);
227 // if conflicting GTU is partially upstream of the conflict and at (near) stand-still, stop for the conflict rather than
228 // following the tail of the conflicting GTU
229 if (conflict.isMerge() && virtualHeadway.lt(conflict.getDistance()))
230 {
231 // {@formatter:off}
232 /*
233 * ______________________________________________
234 * ___ stop for conflict | |
235 * |___|(--------------------)| ___ |
236 * _____________________________|__/ /_|________
237 * / /__/ /
238 * / /
239 */
240 // {@formatter:on}
241 Acceleration aStop =
242 CarFollowingUtil.stop(carFollowingModel, behavioralCharacteristics, speed, speedLimitInfo, conflict
243 .getDistance());
244 a = Acceleration.max(a, aStop); // max, which ever allows the largest acceleration
245 }
246 return a;
247 }
248
249 /**
250 * Determines an acceleration required to avoid a collision with GTUs <i>on</i> a crossing conflict.
251 * @param behavioralCharacteristics behavioral characteristics
252 * @param conflict conflict
253 * @param carFollowingModel car-following model
254 * @param speed current speed
255 * @param speedLimitInfo speed limit info
256 * @return acceleration required to avoid a collision
257 * @throws ParameterException if parameter is not defined
258 */
259 private static Acceleration avoidCrossingCollision(final BehavioralCharacteristics behavioralCharacteristics,
260 final HeadwayConflict conflict, final CarFollowingModel carFollowingModel, final Speed speed,
261 final SpeedLimitInfo speedLimitInfo) throws ParameterException
262 {
263 if (!conflict.getDownstreamConflictingGTUs().isEmpty())
264 {
265 AbstractHeadwayGTU conflictingGTU = conflict.getDownstreamConflictingGTUs().first();
266 if (conflictingGTU.isParallel())
267 {
268 Length distance =
269 conflictingGTU.getOverlapRear().abs().plus(conflictingGTU.getOverlap()).plus(
270 conflictingGTU.getOverlapFront().abs());
271 AnticipationInfo ttcC =
272 AnticipationInfo.anticipateMovement(distance, conflictingGTU.getSpeed(), Acceleration.ZERO);
273 AnticipationInfo tteO =
274 AnticipationInfo.anticipateMovementFreeAcceleration(conflict.getDistance(), speed,
275 behavioralCharacteristics, carFollowingModel, speedLimitInfo, new Duration(.5, TimeUnit.SI));
276 // enter before cleared
277 if (tteO.getDuration().lt(ttcC.getDuration()))
278 {
279 if (!conflictingGTU.getSpeed().eq(Speed.ZERO))
280 {
281 // solve parabolic speed profile s = v*t + .5*a*t*t, a =
282 double acc =
283 2 * (conflict.getDistance().si - speed.si * ttcC.getDuration().si)
284 / (ttcC.getDuration().si * ttcC.getDuration().si);
285 // time till zero speed > time to avoid conflict?
286 if (speed.si / -acc > ttcC.getDuration().si)
287 {
288 return new Acceleration(acc, AccelerationUnit.SI);
289 }
290 }
291 // conflicting vehicle on conflict at stand-still, or will reach zero speed ourselves
292 return CarFollowingUtil.stop(carFollowingModel, behavioralCharacteristics, speed, speedLimitInfo,
293 conflict.getDistance());
294 }
295 }
296 }
297 return new Acceleration(Double.POSITIVE_INFINITY, AccelerationUnit.SI);
298 }
299
300 /**
301 * Approach a priority conflict. Stopping is applied to give way to conflicting traffic in case congestion is present on the
302 * own lane.
303 * @param conflict conflict to approach
304 * @param leaders leading vehicles in own lane
305 * @param speed current speed
306 * @param stopLength length required to stop
307 * @param vehicleLength vehicle length
308 * @param behavioralCharacteristics behavioral characteristics
309 * @param yieldPlans set of plans for yielding with priority
310 * @return whether to stop for this conflict
311 * @throws ParameterException if parameter B is not defined
312 */
313 private static boolean stopForPriorityConflict(final HeadwayConflict conflict,
314 final SortedSet<AbstractHeadwayGTU> leaders, final Speed speed, final Length stopLength, final Length vehicleLength,
315 final BehavioralCharacteristics behavioralCharacteristics, final ConflictPlans yieldPlans) throws ParameterException
316 {
317 if (leaders.isEmpty() || conflict.getUpstreamConflictingGTUs().isEmpty()
318 || conflict.getUpstreamConflictingGTUs().first().getSpeed().eq(Speed.ZERO))
319 {
320 // no leader, and no (stand-still) conflicting vehicle
321 return false;
322 }
323 // time till enter; will enter the conflict
324 // AnticipationInfo tteO = AnticipationInfo.anticipateMovement(conflict.getDistance(), speed, Acceleration.ZERO);
325 // time till clear; will clear the conflict
326 Length distance = conflict.getDistance().plus(vehicleLength);
327 if (conflict.isCrossing())
328 {
329 // merge is cleared at start, crossing at end
330 distance = distance.plus(conflict.getLength());
331 }
332 AnticipationInfo ttcC = AnticipationInfo.anticipateMovement(distance, speed, Acceleration.ZERO);
333 // time till passible; downstream vehicle will leave sufficient room (stopLength) after the conflict
334 distance = distance.minus(leaders.first().getDistance()).minus(vehicleLength).plus(stopLength);
335 AnticipationInfo ttpD = AnticipationInfo.anticipateMovement(distance, leaders.first().getSpeed(), Acceleration.ZERO);
336 // MOTUS uses tteO instead of ttcC, but especially for long conflicts this is not appropriate
337 if (ttpD.getDuration().ge(ttcC.getDuration())) // might block conflict
338 {
339 // TODO respond to indicator / expected turn, will the conflict vehicle go over the conflict? Consider further
340 // conflicting vehicles if not.
341
342 // at a merge, the vehicle that was yielded for may become the leader, do not yield (but follow)
343 if (yieldPlans.isYieldPlan(conflict, leaders.first()))
344 {
345 return false;
346 }
347 // In MOTUS these rules are different. Drivers tagged themselves as conflict blocked, which others used. In OTS
348 // this information is (rightfully) not available. This tagging is simplified to 'speed = 0'.
349 if (!yieldPlans.isYieldPlan(conflict, conflict.getUpstreamConflictingGTUs().first())
350 && conflict.getUpstreamConflictingGTUs().first().getSpeed().equals(Speed.ZERO))
351 {
352 Acceleration b = behavioralCharacteristics.getParameter(ParameterTypes.B);
353 Acceleration bReq =
354 new Acceleration(.5 * speed.si * speed.si / conflict.getDistance().si, AccelerationUnit.SI);
355 if (bReq.gt(b))
356 {
357 // cannot stop safely, do not initiate plan
358 return false;
359 }
360 }
361 // initiate or keep plan to yield
362 yieldPlans.setYieldPlan(conflict, conflict.getUpstreamConflictingGTUs().first());
363 return true;
364 }
365 // if the yield was a plan, it is abandoned as the conflict will not be blocked
366 return false;
367 }
368
369 /**
370 * Approach a give-way conflict.
371 * @param conflict conflict
372 * @param leaders leaders
373 * @param speed current speed
374 * @param stopLength length required when stopped
375 * @param vehicleLength vehicle length
376 * @param behavioralCharacteristics behavioral characteristics
377 * @param speedLimitInfo speed limit info
378 * @param carFollowingModel car-following model
379 * @return whether to stop for this conflict
380 * @throws ParameterException if a parameter is not defined
381 */
382 @SuppressWarnings("checkstyle:parameternumber")
383 private static boolean stopForGiveWayConflict(final HeadwayConflict conflict,
384 final SortedSet<AbstractHeadwayGTU> leaders, final Speed speed, final Length stopLength, final Length vehicleLength,
385 final BehavioralCharacteristics behavioralCharacteristics, final SpeedLimitInfo speedLimitInfo,
386 final CarFollowingModel carFollowingModel) throws ParameterException
387 {
388
389 // TODO disregard conflicting vehicles with a route not over the conflict, if known through e.d. indicator
390
391 // Get data independent of conflicting vehicle
392 // parameters
393 Acceleration b = behavioralCharacteristics.getParameter(ParameterTypes.B).multiplyBy(-1.0);
394 double f = behavioralCharacteristics.getParameter(TIME_FACTOR);
395 Duration gap = behavioralCharacteristics.getParameter(MIN_GAP);
396 // time till conflict is cleared
397 Length distance = conflict.getDistance().plus(vehicleLength);
398 if (conflict.isCrossing())
399 {
400 // merge is cleared at start, crossing at end
401 distance = distance.plus(conflict.getLength());
402 }
403 AnticipationInfo ttcO =
404 AnticipationInfo.anticipateMovementFreeAcceleration(distance, speed, behavioralCharacteristics,
405 carFollowingModel, speedLimitInfo, new Duration(.5, TimeUnit.SI));
406 // time till downstream vehicle will make the conflict passible, under constant speed or safe deceleration
407 AnticipationInfo ttpDz = null;
408 AnticipationInfo ttpDs = null;
409 if (conflict.isCrossing())
410 {
411 if (!leaders.isEmpty())
412 {
413 distance =
414 conflict.getDistance().minus(leaders.first().getDistance()).plus(conflict.getLength()).plus(stopLength);
415 ttpDz = AnticipationInfo.anticipateMovement(distance, leaders.first().getSpeed(), Acceleration.ZERO);
416 ttpDs = AnticipationInfo.anticipateMovement(distance, leaders.first().getSpeed(), b);
417 }
418 else
419 {
420 // no leader so conflict is passible within a duration of 0
421 ttpDz = new AnticipationInfo(Duration.ZERO, Speed.ZERO);
422 ttpDs = new AnticipationInfo(Duration.ZERO, Speed.ZERO);
423 }
424 }
425
426 // Get list of conflicting vehicles' information
427 ArrayList<Length> confDistance = new ArrayList<>();
428 ArrayList<Speed> confSpeed = new ArrayList<>();
429 ArrayList<Acceleration> confAcceleration = new ArrayList<>();
430 if (!conflict.getUpstreamConflictingGTUs().isEmpty())
431 {
432 for (AbstractHeadwayGTU conflictingVehicle : conflict.getUpstreamConflictingGTUs())
433 {
434 confDistance.add(conflictingVehicle.getDistance());
435 confSpeed.add(conflictingVehicle.getSpeed());
436 confAcceleration.add(conflictingVehicle.getAcceleration());
437 }
438 }
439 else
440 {
441 // none within visibility, assume a conflicting vehicle just outside of visibility driving at speed limit
442 confDistance.add(conflict.getConflictingVisibility());
443 confSpeed.add(conflict.getConflictingSpeedLimit());
444 confAcceleration.add(Acceleration.ZERO);
445 }
446
447 // Loop over conflicting vehicles
448 for (int i = 0; i < confDistance.size(); i++)
449 {
450
451 // time till conflict vehicle will enter, under current acceleration and safe deceleration
452 AnticipationInfo tteCc =
453 AnticipationInfo.anticipateMovement(confDistance.get(i), confSpeed.get(i), confAcceleration.get(i));
454 AnticipationInfo tteCs = AnticipationInfo.anticipateMovement(confDistance.get(i), confSpeed.get(i), b);
455
456 // check gap
457 if (conflict.isMerge())
458 {
459
460 // Merge, will be each others followers, add time to overcome speed difference
461 double vConflicting = confSpeed.get(i).si + b.si * ttcO.getDuration().si;
462 double vSelf = ttcO.getEndSpeed().si;
463 double speedDiff = vConflicting - vSelf;
464 speedDiff = speedDiff > 0 ? speedDiff : 0;
465 Duration additionalTime = new Duration(speedDiff / -b.si, TimeUnit.SI);
466 // 1) will clear the conflict before the conflict vehicle will enter
467 // 2) conflict vehicle has sufficient time to adjust speed
468 if (ttcO.getDuration().multiplyBy(f).plus(gap).gt(tteCc.getDuration())
469 || ttcO.getDuration().plus(additionalTime).multiplyBy(f).plus(gap).gt(tteCs.getDuration()))
470 {
471 return true;
472 }
473
474 }
475 else if (conflict.isCrossing())
476 {
477
478 // Crossing, stop if order of events is not ok
479 // 1) downstream vehicle must supply sufficient space before conflict vehicle will enter
480 // 2) must clear the conflict before the conflict vehicle will enter
481 // 3) if leader decelerates with b, conflict vehicle should be able to safely delay entering conflict
482 if (ttpDz.getDuration().multiplyBy(f).plus(gap).gt(tteCc.getDuration())
483 || ttcO.getDuration().multiplyBy(f).plus(gap).gt(tteCc.getDuration())
484 || ttpDs.getDuration().multiplyBy(f).plus(gap).gt(tteCs.getDuration()))
485 {
486 return true;
487 }
488
489 }
490 else
491 {
492 throw new RuntimeException("Conflict is of unknown type " + conflict.getConflictType()
493 + ", which is not merge nor crossing.");
494 }
495 }
496
497 // No conflict vehicle triggered stopping
498 return false;
499
500 }
501
502 /**
503 * Approach a stop conflict. Currently this is equal to approaching a give-way conflict.
504 * @param conflict conflict
505 * @param leaders leaders
506 * @param speed current speed
507 * @param stopLength length required when stopped
508 * @param vehicleLength vehicle length
509 * @param behavioralCharacteristics behavioral characteristics
510 * @param speedLimitInfo speed limit info
511 * @param carFollowingModel car-following model
512 * @return whether to stop for this conflict
513 * @throws ParameterException if a parameter is not defined
514 */
515 @SuppressWarnings("checkstyle:parameternumber")
516 private static boolean stopForStopConflict(final HeadwayConflict conflict, final SortedSet<AbstractHeadwayGTU> leaders,
517 final Speed speed, final Length stopLength, final Length vehicleLength,
518 final BehavioralCharacteristics behavioralCharacteristics, final SpeedLimitInfo speedLimitInfo,
519 final CarFollowingModel carFollowingModel) throws ParameterException
520 {
521 return stopForGiveWayConflict(conflict, leaders, speed, stopLength, vehicleLength, behavioralCharacteristics,
522 speedLimitInfo, carFollowingModel);
523 }
524
525 /**
526 * Approach an all-stop conflict.
527 * @param conflict conflict to approach
528 * @param conflictPlans set of plans for conflict
529 * @return whether to stop for this conflict
530 */
531 private static boolean stopForAllStopConflict(final HeadwayConflict conflict, final ConflictPlans conflictPlans)
532 {
533 // TODO all-stop behavior
534
535 if (conflictPlans.isStopPhaseRun(conflict.getStopLine()))
536 {
537 return false;
538 }
539
540 return false;
541 }
542
543 /**
544 * Holds the tactical plans of a driver considering conflicts. These are remembered for consistency. Set of yield plans in
545 * case of having priority. Such plans are remembered to get consistency. For instance, if the decision is made to yield as
546 * current deceleration suggests it's safe to do so, but the trajectory for stopping in front of the conflict results in
547 * deceleration slightly above what is considered safe deceleration, the plan should not be abandoned. Decelerations above
548 * what is considered safe deceleration may result due to numerical overshoot or other factor coming into play in
549 * car-following models. Many other examples exist where a driver sticks to a certain plan.
550 * <p>
551 * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
552 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
553 * <p>
554 * @version $Revision$, $LastChangedDate$, by $Author$, initial version Jun 7, 2016 <br>
555 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
556 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
557 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
558 */
559 public static final class ConflictPlans implements Serializable
560 {
561
562 /** */
563 private static final long serialVersionUID = 20160811L;
564
565 /** Set of current plans. */
566 private final Map<String, String> yieldPlans = new HashMap<>();
567
568 /** Set of conflicts that are still actively considered for a yield plan. */
569 private final Set<String> activeYieldPlans = new HashSet<>();
570
571 /** Phases of navigating an all-stop intersection per intersection. */
572 private final HashMap<String, StopPhase> stopPhases = new HashMap<>();
573
574 /** Estimated arrival times of vehicles at all-stop intersection. */
575 private final HashMap<String, Time> arrivalTimes = new HashMap<>();
576
577 /**
578 * Returns whether a plan exists for yielding at the conflict for the given conflict GTU.
579 * @param conflict conflict
580 * @param gtu conflicting GTU
581 * @return whether a plan exists for yielding at the conflict for the given conflict GTU
582 */
583 boolean isYieldPlan(final HeadwayConflict conflict, final AbstractHeadwayGTU gtu)
584 {
585 return this.yieldPlans.containsKey(conflict.getId())
586 && this.yieldPlans.get(conflict.getId()).equals(gtu.getId());
587 }
588
589 /**
590 * Sets or maintains the plan to yield at the conflict for the given conflict RSU.
591 * @param conflict conflict to yield at
592 * @param gtu conflicting GTU
593 */
594 void setYieldPlan(final HeadwayConflict conflict, final AbstractHeadwayGTU gtu)
595 {
596 this.yieldPlans.put(conflict.getId(), gtu.getId());
597 this.activeYieldPlans.add(conflict.getId());
598 }
599
600 /**
601 * Clears any yield plan that was no longer kept active in the last evaluation of conflicts.
602 */
603 void cleanYieldPlans()
604 {
605 // remove any plan not represented in activePlans
606 Iterator<String> iterator = this.yieldPlans.keySet().iterator();
607 while (iterator.hasNext())
608 {
609 String conflictId = iterator.next();
610 if (!this.activeYieldPlans.contains(conflictId))
611 {
612 iterator.remove();
613 }
614 }
615 // clear the activePlans for the next consideration of conflicts
616 this.activeYieldPlans.clear();
617 }
618
619 /**
620 * Sets the estimated arrival time of a GTU.
621 * @param gtu GTU
622 * @param time estimated arrival time
623 */
624 void setArrivalTime(final AbstractHeadwayGTU gtu, final Time time)
625 {
626 this.arrivalTimes.put(gtu.getId(), time);
627 }
628
629 /**
630 * Returns the estimated arrival time of given GTU.
631 * @param gtu GTU
632 * @return estimated arrival time of given GTU
633 */
634 Time getArrivalTime(final AbstractHeadwayGTU gtu)
635 {
636 return this.arrivalTimes.get(gtu.getId());
637 }
638
639 /**
640 * Sets the current phase to 'approach' for the given stop line.
641 * @param stopLine stop line
642 */
643 void setStopPhaseApproach(final HeadwayStopLine stopLine)
644 {
645 this.stopPhases.put(stopLine.getId(), StopPhase.APPROACH);
646 }
647
648 /**
649 * Sets the current phase to 'yield' for the given stop line.
650 * @param stopLine stop line
651 * @throws RuntimeException if the phase was not set to approach before
652 */
653 void setStopPhaseYield(final HeadwayStopLine stopLine)
654 {
655 Throw.when(!this.stopPhases.containsKey(stopLine.getId())
656 || !this.stopPhases.get(stopLine.getId()).equals(StopPhase.APPROACH), RuntimeException.class,
657 "Yield stop phase is set for stop line that was not approached.");
658 this.stopPhases.put(stopLine.getId(), StopPhase.YIELD);
659 }
660
661 /**
662 * Sets the current phase to 'run' for the given stop line.
663 * @param stopLine stop line
664 * @throws RuntimeException if the phase was not set to approach before
665 */
666 void setStopPhaseRun(final HeadwayStopLine stopLine)
667 {
668 Throw.when(!this.stopPhases.containsKey(stopLine.getId()), RuntimeException.class,
669 "Run stop phase is set for stop line that was not approached.");
670 this.stopPhases.put(stopLine.getId(), StopPhase.YIELD);
671 }
672
673 /**
674 * @param stopLine stop line
675 * @return whether the current phase is 'approach' for the given stop line
676 */
677 boolean isStopPhaseApproach(final HeadwayStopLine stopLine)
678 {
679 return this.stopPhases.containsKey(stopLine.getId())
680 && this.stopPhases.get(stopLine.getId()).equals(StopPhase.APPROACH);
681 }
682
683 /**
684 * @param stopLine stop line
685 * @return whether the current phase is 'yield' for the given stop line
686 */
687 boolean isStopPhaseYield(final HeadwayStopLine stopLine)
688 {
689 return this.stopPhases.containsKey(stopLine.getId())
690 && this.stopPhases.get(stopLine.getId()).equals(StopPhase.YIELD);
691 }
692
693 /**
694 * @param stopLine stop line
695 * @return whether the current phase is 'run' for the given stop line
696 */
697 boolean isStopPhaseRun(final HeadwayStopLine stopLine)
698 {
699 return this.stopPhases.containsKey(stopLine.getId())
700 && this.stopPhases.get(stopLine.getId()).equals(StopPhase.RUN);
701 }
702
703 /** {@inheritDoc} */
704 @Override
705 public String toString()
706 {
707 return "ConflictPlans";
708 }
709
710 }
711
712 /**
713 * Phases of navigating an all-stop intersection.
714 * <p>
715 * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
716 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
717 * <p>
718 * @version $Revision$, $LastChangedDate$, by $Author$, initial version Jun 30, 2016 <br>
719 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
720 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
721 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
722 */
723 private static enum StopPhase
724 {
725 /** Approaching stop intersection. */
726 APPROACH,
727
728 /** Yielding for stop intersection. */
729 YIELD,
730
731 /** Running over stop intersection. */
732 RUN;
733 }
734
735 }