View Javadoc
1   package org.opentrafficsim.road.gtu.lane.tactical.lmrs;
2   
3   import java.util.Set;
4   
5   import org.djunits.value.vdouble.scalar.Acceleration;
6   import org.djunits.value.vdouble.scalar.Length;
7   import org.djunits.value.vdouble.scalar.Speed;
8   import org.opentrafficsim.core.gtu.behavioralcharacteristics.BehavioralCharacteristics;
9   import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterException;
10  import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypes;
11  import org.opentrafficsim.core.gtu.perception.EgoPerception;
12  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
13  import org.opentrafficsim.core.network.LateralDirectionality;
14  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
15  import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
16  import org.opentrafficsim.road.gtu.lane.perception.categories.InfrastructurePerception;
17  import org.opentrafficsim.road.gtu.lane.perception.categories.NeighborsPerception;
18  import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTU;
19  import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
20  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Desire;
21  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsParameters;
22  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsUtil;
23  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.VoluntaryIncentive;
24  import org.opentrafficsim.road.network.speed.SpeedLimitInfo;
25  
26  /**
27   * Determines lane change desire for courtesy lane changes, which are performed to supply space for other drivers. In case
28   * drivers in adjacent lanes have desire to change to the current lane, the driver has desire to change to the other adjacent
29   * lane. The level of desire depends on lane change courtesy, as well as the distance of the leading vehicle for which desire
30   * exists. This desire exists for only a single vehicle, i.e. the one giving maximum desire. A negative desire may also result
31   * for leaders in the 2nd adjacent lane desiring to change to the 1st adjacent lane. By not changing to the 1st adjacent lane,
32   * room is reserved for the leader on the 2nd adjacent lane.
33   * <p>
34   * Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
35   * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
36   * <p>
37   * @version $Revision$, $LastChangedDate$, by $Author$, initial version Apr 13, 2016 <br>
38   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
39   */
40  public class IncentiveCourtesy implements VoluntaryIncentive, LmrsParameters
41  {
42  
43      /** {@inheritDoc} */
44      @Override
45      public final Desire determineDesire(final BehavioralCharacteristics behavioralCharacteristics,
46              final LanePerception perception, final CarFollowingModel carFollowingModel, final Desire mandatoryDesire,
47              final Desire voluntaryDesire) throws ParameterException, OperationalPlanException
48      {
49  
50          double dLeftYes = 0;
51          double dRightYes = 0;
52          double dLeftNo = 0;
53          double dRightNo = 0;
54          double courtesy = behavioralCharacteristics.getParameter(COURTESY);
55          Acceleration b = behavioralCharacteristics.getParameter(ParameterTypes.B);
56          NeighborsPerception neighbors = perception.getPerceptionCategory(NeighborsPerception.class);
57          Speed ownSpeed = perception.getPerceptionCategory(EgoPerception.class).getSpeed();
58          InfrastructurePerception infra = perception.getPerceptionCategory(InfrastructurePerception.class);
59          SpeedLimitInfo sli = infra.getSpeedLimitProspect(RelativeLane.CURRENT).getSpeedLimitInfo(Length.ZERO);
60          boolean leftLane = infra.getLegalLaneChangePossibility(RelativeLane.CURRENT, LateralDirectionality.LEFT).si > 0.0;
61          boolean rightLane = infra.getLegalLaneChangePossibility(RelativeLane.CURRENT, LateralDirectionality.RIGHT).si > 0.0;
62          for (LateralDirectionality dir : new LateralDirectionality[] { LateralDirectionality.LEFT,
63                  LateralDirectionality.RIGHT })
64          {
65              Set<HeadwayGTU> leaders = neighbors.getLeaders(new RelativeLane(dir, 1));
66              if (leaders != null)
67              {
68                  for (HeadwayGTU leader : leaders)
69                  {
70                      BehavioralCharacteristics bc = leader.getBehavioralCharacteristics();
71                      double desire = dir.isLeft() ? bc.getParameter(DRIGHT) : bc.getParameter(DLEFT);
72                      if (desire > 0)
73                      {
74                          Acceleration a = LmrsUtil.singleAcceleration(leader.getDistance(), ownSpeed, leader.getSpeed(), desire,
75                                  bc, sli, carFollowingModel);
76                          if (a.lt0())
77                          {
78                              double d = desire * Math.min(-a.si / b.si, 1.0);
79                              if (dir.isLeft() && rightLane)
80                              {
81                                  // leader in left lane wants to change right, so we change right
82                                  dRightYes = dRightYes > d ? dRightYes : d;
83                              }
84                              else if (leftLane)
85                              {
86                                  // leader in right lane wants to change left, so we change left
87                                  dLeftYes = dLeftYes > d ? dLeftYes : d;
88                              }
89                          }
90                      }
91                  }
92              }
93              // consider close followers on 2 lanes away
94              Set<HeadwayGTU> followers = neighbors.getFollowers(new RelativeLane(dir, 2));
95              if (followers != null)
96              {
97                  for (HeadwayGTU follower : followers)
98                  {
99                      BehavioralCharacteristics bc = follower.getBehavioralCharacteristics();
100                     double desire = dir.isLeft() ? bc.getParameter(DRIGHT) : bc.getParameter(DLEFT);
101                     Acceleration a = follower.getDistance().lt0() ? b.neg()
102                             : LmrsUtil.singleAcceleration(follower.getDistance(), follower.getSpeed(), ownSpeed, desire, bc,
103                                     follower.getSpeedLimitInfo(), follower.getCarFollowingModel());
104                     if (a.lt0())
105                     {
106                         if (desire > 0)
107                         {
108                             double d = desire * Math.min(-a.si / b.si, 1.0);
109                             if (dir.isLeft() && leftLane)
110                             {
111                                 // follower in second left lane wants to change right, so we do not change left
112                                 dLeftNo = dLeftNo > desire ? dLeftNo : d;
113                             }
114                             else if (rightLane)
115                             {
116                                 // follower in second right lane wants to change left, so we do not change right
117                                 dRightNo = dRightNo > desire ? dRightNo : d;
118                             }
119                         }
120                     }
121                     else
122                     {
123                         // ignore further followers
124                         break;
125                     }
126                 }
127             }
128             leaders = neighbors.getLeaders(new RelativeLane(dir, 2));
129             if (leaders != null)
130             {
131                 for (HeadwayGTU leader : leaders)
132                 {
133                     BehavioralCharacteristics bc = leader.getBehavioralCharacteristics();
134                     double desire = dir.isLeft() ? bc.getParameter(DRIGHT) : bc.getParameter(DLEFT);
135                     if (desire > 0)
136                     {
137                         Acceleration a = LmrsUtil.singleAcceleration(leader.getDistance(), ownSpeed, leader.getSpeed(), desire,
138                                 bc, sli, carFollowingModel);
139                         if (a.lt0())
140                         {
141                             double d = desire * Math.min(-a.si / b.si, 1.0); // (1 - leader.getDistance().si / x0.si) * desire;
142                             if (dir.isLeft() && leftLane)
143                             {
144                                 // leader in second left lane wants to change right, so we do not change left
145                                 dLeftNo = dLeftNo > d ? dLeftNo : d;
146                             }
147                             else if (rightLane)
148                             {
149                                 // leader in second right lane wants to change left, so we do not change right
150                                 dRightNo = dRightNo > d ? dRightNo : d;
151                             }
152                         }
153                     }
154                 }
155             }
156         }
157         // note: noLeft and noRight weighted with 1 always
158         dLeftYes *= courtesy;
159         dRightYes *= courtesy;
160         return new Desire(dLeftYes - dLeftNo, dRightYes - dRightNo);
161 
162     }
163 
164     /** {@inheritDoc} */
165     @Override
166     public final String toString()
167     {
168         return "IncentiveCourtesy";
169     }
170 
171 }