View Javadoc
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 }