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.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).multiplyBy(-1.0);
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 }