View Javadoc
1   package org.opentrafficsim.road.gtu.tactical.lmrs;
2   
3   import org.djunits.value.vdouble.scalar.Length;
4   import org.djunits.value.vdouble.scalar.Speed;
5   import org.djutils.immutablecollections.ImmutableLinkedHashMap;
6   import org.opentrafficsim.base.parameters.ParameterException;
7   import org.opentrafficsim.base.parameters.ParameterTypeDouble;
8   import org.opentrafficsim.base.parameters.ParameterTypeLength;
9   import org.opentrafficsim.base.parameters.ParameterTypeSpeed;
10  import org.opentrafficsim.base.parameters.ParameterTypes;
11  import org.opentrafficsim.core.gtu.Stateless;
12  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
13  import org.opentrafficsim.core.network.LateralDirectionality;
14  import org.opentrafficsim.road.gtu.LaneBasedGtu;
15  import org.opentrafficsim.road.gtu.perception.PerceptionCollectable;
16  import org.opentrafficsim.road.gtu.perception.RelativeLane;
17  import org.opentrafficsim.road.gtu.perception.categories.InfrastructurePerception;
18  import org.opentrafficsim.road.gtu.perception.categories.neighbors.NeighborsPerception;
19  import org.opentrafficsim.road.gtu.perception.object.PerceivedGtu;
20  import org.opentrafficsim.road.gtu.tactical.TacticalContextEgo;
21  import org.opentrafficsim.road.gtu.tactical.util.lmrs.Desire;
22  import org.opentrafficsim.road.gtu.tactical.util.lmrs.LmrsParameters;
23  import org.opentrafficsim.road.gtu.tactical.util.lmrs.Tailgating;
24  import org.opentrafficsim.road.gtu.tactical.util.lmrs.VoluntaryIncentive;
25  
26  /**
27   * Lane change incentive based on social pressure. Drivers may refrain from changing left to not hinder faster traffic, or
28   * drivers may change right to get out of the way. When drivers are on the left lane, this is considered 'overtaking', and
29   * related to this the desired speed could be increased by using {@code SocioDesiredSpeedModel}.
30   * <p>
31   * Copyright (c) 2013-2026 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
32   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
33   * </p>
34   * @author Alexander Verbraeck
35   * @author Peter Knoppers
36   * @author Wouter Schakel
37   */
38  // TODO keep left or right rules
39  public final class IncentiveSocioSpeed implements VoluntaryIncentive, Stateless<IncentiveSocioSpeed>
40  {
41  
42      /** Social pressure applied to the leader. */
43      protected static final ParameterTypeDouble RHO = Tailgating.RHO;
44  
45      /** Hierarchy parameter. */
46      protected static final ParameterTypeDouble SOCIO = LmrsParameters.SOCIO;
47  
48      /** Speed threshold below which traffic is considered congested. */
49      protected static final ParameterTypeSpeed VCONG = ParameterTypes.VCONG;
50  
51      /** Vgain parameter; ego-speed sensitivity. */
52      protected static final ParameterTypeSpeed VGAIN = LmrsParameters.VGAIN;
53  
54      /** Look-ahead distance. */
55      protected static final ParameterTypeLength LOOKAHEAD = ParameterTypes.LOOKAHEAD;
56  
57      /** Singleton instance. */
58      public static final IncentiveSocioSpeed SINGLETON = new IncentiveSocioSpeed();
59  
60      @Override
61      public IncentiveSocioSpeed get()
62      {
63          return SINGLETON;
64      }
65  
66      /**
67       * Constructor.
68       */
69      private IncentiveSocioSpeed()
70      {
71          //
72      }
73  
74      @Override
75      public Desire determineDesire(final TacticalContextEgo context, final Desire mandatoryDesire,
76              final ImmutableLinkedHashMap<Class<? extends VoluntaryIncentive>, Desire> voluntaryDesire)
77              throws ParameterException, OperationalPlanException
78      {
79          double dLeft = 0;
80          double dRight = 0;
81          if (context.getSpeed().gt(context.getParameters().getParameter(VCONG)))
82          {
83              double sigma = context.getParameters().getParameter(SOCIO);
84              NeighborsPerception neighbors = context.getPerception().getPerceptionCategory(NeighborsPerception.class);
85              InfrastructurePerception infra = context.getPerception().getPerceptionCategory(InfrastructurePerception.class);
86              boolean leftLane = infra.getLegalLaneChangePossibility(RelativeLane.CURRENT, LateralDirectionality.LEFT).si > 0.0;
87              boolean rightLane = infra.getLegalLaneChangePossibility(RelativeLane.CURRENT, LateralDirectionality.RIGHT).si > 0.0;
88              // change right to get out of the way
89              if (rightLane && mandatoryDesire.right() >= 0.0)
90              {
91                  PerceptionCollectable<PerceivedGtu, LaneBasedGtu> followers = neighbors.getFollowers(RelativeLane.CURRENT);
92                  if (!followers.isEmpty())
93                  {
94                      double rho = context.getParameters().getParameter(RHO);
95                      PerceivedGtu follower = followers.first();
96                      double rhoFollower = follower.getBehavior().getParameters().getParameter(RHO);
97                      if (rhoFollower * sigma > rho)
98                      {
99                          dRight = rhoFollower * sigma;
100                     }
101                 }
102             }
103             // stay right to keep out of the way
104             if (leftLane && mandatoryDesire.left() <= 0.0)
105             {
106                 PerceptionCollectable<PerceivedGtu, LaneBasedGtu> followers = neighbors.getFollowers(RelativeLane.LEFT);
107                 if (followers != null && !followers.isEmpty())
108                 {
109                     double rho;
110                     PerceptionCollectable<PerceivedGtu, LaneBasedGtu> leaders = neighbors.getLeaders(RelativeLane.LEFT);
111                     if (leaders != null && !leaders.isEmpty())
112                     {
113                         PerceivedGtu leader = leaders.first();
114                         Speed vDes = context.getDesiredSpeed();
115                         Speed vGain = context.getParameters().getParameter(VGAIN);
116                         Length x0 = context.getParameters().getParameter(LOOKAHEAD);
117                         rho = Tailgating.socialPressure(vDes, leader.getSpeed(), vGain, leader.getDistance(), x0);
118                     }
119                     else
120                     {
121                         rho = 0.0;
122                     }
123                     PerceivedGtu follower = followers.first();
124                     Speed vGainFollower = follower.getBehavior().getParameters().getParameter(VGAIN);
125                     Length x0Follower = follower.getBehavior().getParameters().getParameter(LOOKAHEAD);
126                     double rhoFollower = Tailgating.socialPressure(follower.getBehavior().getDesiredSpeed(), context.getSpeed(),
127                             vGainFollower, follower.getDistance(), x0Follower);
128                     if (rhoFollower * sigma > rho)
129                     {
130                         dLeft = -rhoFollower * sigma;
131                     }
132                 }
133             }
134         }
135         return new Desire(dLeft, dRight);
136     }
137 
138     @Override
139     public String toString()
140     {
141         return "IncentiveSocioSpeed";
142     }
143 
144 }