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