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