View Javadoc
1   package org.opentrafficsim.road.gtu.lane.tactical.util.lmrs;
2   
3   import org.djunits.unit.AccelerationUnit;
4   import org.djunits.value.vdouble.scalar.Acceleration;
5   import org.djunits.value.vdouble.scalar.Speed;
6   import org.opentrafficsim.base.parameters.ParameterException;
7   import org.opentrafficsim.base.parameters.ParameterTypes;
8   import org.opentrafficsim.base.parameters.Parameters;
9   import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
10  import org.opentrafficsim.core.network.LateralDirectionality;
11  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
12  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.NeighborsPerception;
13  import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGtu;
14  import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
15  import org.opentrafficsim.road.network.speed.SpeedLimitInfo;
16  
17  /**
18   * Interface for LMRS gap-acceptance models.
19   * <p>
20   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
21   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
22   * </p>
23   * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
24   * @author <a href="https://github.com/peter-knoppers">Peter Knoppers</a>
25   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
26   */
27  public interface GapAcceptance
28  {
29  
30      /** Being informed of the model and parameters of other drivers (default LMRS). */
31      GapAcceptance INFORMED = new GapAcceptance()
32      {
33          @Override
34          public boolean acceptGap(final LanePerception perception, final Parameters params, final SpeedLimitInfo sli,
35                  final CarFollowingModel cfm, final double desire, final Speed ownSpeed, final Acceleration ownAcceleration,
36                  final LateralDirectionality lat) throws ParameterException, OperationalPlanException
37          {
38              NeighborsPerception neighbors = perception.getPerceptionCategory(NeighborsPerception.class);
39              if (neighbors.isGtuAlongside(lat))
40              {
41                  // gtu alongside
42                  return false;
43              }
44  
45              // TODO
46              /*-
47               * Followers and are accepted if the acceleration and speed is 0, a leader is accepted if the ego speed is 0. This 
48               * is in place as vehicles that provide courtesy, will decelerate for us and overshoot the stand-still distance. As
49               * a consequence, they will cease cooperation as they are too close. A pattern will arise where followers slow down
50               * to (near) stand-still, and accelerate again, before we could ever accept the gap.
51               * 
52               * By accepting the gap in the moment that they reach stand-still, this vehicle can at least accept the gap at some 
53               * point. All of this is only a problem if the own vehicle is standing still. Otherwise the stand-still distance is 
54               * not important and movement of our own will create an acceptable situation.
55               * 
56               * What needs to be done, is to find a better way to deal with the cooperation and gap-acceptance, such that this  
57               * hack is not required.
58               */
59  
60              Acceleration b = params.getParameter(ParameterTypes.B);
61              Acceleration aFollow = new Acceleration(Double.POSITIVE_INFINITY, AccelerationUnit.SI);
62              for (HeadwayGtu follower : neighbors.getFirstFollowers(lat))
63              {
64                  if (follower.getSpeed().gt0() || follower.getAcceleration().gt0() || follower.getDistance().si < 1.0)
65                  {
66                      Acceleration a = LmrsUtil.singleAcceleration(follower.getDistance(), follower.getSpeed(), ownSpeed, desire,
67                              follower.getParameters(), follower.getSpeedLimitInfo(), follower.getCarFollowingModel());
68                      aFollow = Acceleration.min(aFollow, a);
69                  }
70              }
71  
72              Acceleration aSelf = egoAcceleration(perception, params, sli, cfm, desire, ownSpeed, lat);
73              Acceleration threshold = b.times(-desire);
74              return aFollow.ge(threshold) && aSelf.ge(threshold) && ownAcceleration.ge(threshold);
75          }
76  
77          @Override
78          public String toString()
79          {
80              return "INFORMED";
81          }
82      };
83  
84      /** Being informed of the model and parameters of other drivers, but applying own headway value. */
85      GapAcceptance EGO_HEADWAY = new GapAcceptance()
86      {
87          @Override
88          public boolean acceptGap(final LanePerception perception, final Parameters params, final SpeedLimitInfo sli,
89                  final CarFollowingModel cfm, final double desire, final Speed ownSpeed, final Acceleration ownAcceleration,
90                  final LateralDirectionality lat) throws ParameterException, OperationalPlanException
91          {
92              NeighborsPerception neigbors = perception.getPerceptionCategory(NeighborsPerception.class);
93              if (neigbors.isGtuAlongside(lat))
94              {
95                  // gtu alongside
96                  return false;
97              }
98  
99              Acceleration b = params.getParameter(ParameterTypes.B);
100             Acceleration aFollow = new Acceleration(Double.POSITIVE_INFINITY, AccelerationUnit.SI);
101             for (HeadwayGtu follower : neigbors.getFirstFollowers(lat))
102             {
103                 if (follower.getSpeed().gt0() || follower.getAcceleration().gt0())
104                 {
105                     // Change headway parameter
106                     Parameters folParams = follower.getParameters();
107                     folParams.setParameterResettable(ParameterTypes.TMIN, params.getParameter(ParameterTypes.TMIN));
108                     folParams.setParameterResettable(ParameterTypes.TMAX, params.getParameter(ParameterTypes.TMAX));
109                     Acceleration a = LmrsUtil.singleAcceleration(follower.getDistance(), follower.getSpeed(), ownSpeed, desire,
110                             folParams, follower.getSpeedLimitInfo(), follower.getCarFollowingModel());
111                     aFollow = Acceleration.min(aFollow, a);
112                     folParams.resetParameter(ParameterTypes.TMIN);
113                     folParams.resetParameter(ParameterTypes.TMAX);
114                 }
115             }
116 
117             Acceleration aSelf = egoAcceleration(perception, params, sli, cfm, desire, ownSpeed, lat);
118             Acceleration threshold = b.times(-desire);
119             return aFollow.ge(threshold) && aSelf.ge(threshold);
120         }
121 
122         @Override
123         public String toString()
124         {
125             return "EGO_HEADWAY";
126         }
127     };
128 
129     /**
130      * Determine whether a gap is acceptable.
131      * @param perception perception
132      * @param params parameters
133      * @param sli speed limit info
134      * @param cfm car-following model
135      * @param desire level of lane change desire
136      * @param ownSpeed own speed
137      * @param lat lateral direction for synchronization
138      * @return whether a gap is acceptable
139      * @throws ParameterException if a parameter is not defined
140      * @throws OperationalPlanException perception exception
141      */
142     static Acceleration egoAcceleration(final LanePerception perception, final Parameters params, final SpeedLimitInfo sli,
143             final CarFollowingModel cfm, final double desire, final Speed ownSpeed, final LateralDirectionality lat)
144             throws ParameterException, OperationalPlanException
145     {
146         Acceleration aSelf = new Acceleration(Double.POSITIVE_INFINITY, AccelerationUnit.SI);
147         if (ownSpeed.gt0())
148         {
149             for (
150 
151             HeadwayGtu leader : perception.getPerceptionCategory(NeighborsPerception.class).getFirstLeaders(lat))
152             {
153                 Acceleration a = LmrsUtil.singleAcceleration(leader.getDistance(), ownSpeed, leader.getSpeed(), desire, params,
154                         sli, cfm);
155                 aSelf = Acceleration.min(aSelf, a);
156             }
157         }
158         return aSelf;
159     }
160 
161     /**
162      * Determine whether a gap is acceptable.
163      * @param perception perception
164      * @param params parameters
165      * @param sli speed limit info
166      * @param cfm car-following model
167      * @param desire level of lane change desire
168      * @param ownSpeed own speed
169      * @param ownAcceleration current car-following acceleration
170      * @param lat lateral direction for synchronization
171      * @return whether a gap is acceptable
172      * @throws ParameterException if a parameter is not defined
173      * @throws OperationalPlanException perception exception
174      */
175     boolean acceptGap(LanePerception perception, Parameters params, SpeedLimitInfo sli, CarFollowingModel cfm, double desire,
176             Speed ownSpeed, Acceleration ownAcceleration, LateralDirectionality lat)
177             throws ParameterException, OperationalPlanException;
178 
179 }