View Javadoc
1   package org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil;
2   
3   import java.util.Collection;
4   import java.util.Map;
5   
6   import org.djunits.unit.AccelerationUnit;
7   import org.djunits.value.vdouble.scalar.Acceleration;
8   import org.djunits.value.vdouble.scalar.Length;
9   import org.djunits.value.vdouble.scalar.Speed;
10  import org.djunits.value.vdouble.scalar.base.DoubleScalar;
11  import org.opentrafficsim.base.parameters.ParameterException;
12  import org.opentrafficsim.base.parameters.ParameterTypeAcceleration;
13  import org.opentrafficsim.base.parameters.ParameterTypeLength;
14  import org.opentrafficsim.base.parameters.ParameterTypes;
15  import org.opentrafficsim.core.gtu.GtuException;
16  import org.opentrafficsim.core.gtu.RelativePosition;
17  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
18  import org.opentrafficsim.core.network.LateralDirectionality;
19  import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
20  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
21  import org.opentrafficsim.road.gtu.lane.perception.categories.DefaultSimplePerception;
22  import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
23  import org.opentrafficsim.road.gtu.lane.tactical.AbstractLaneBasedTacticalPlanner;
24  import org.opentrafficsim.road.gtu.lane.tactical.following.AbstractGtuFollowingModelMobil;
25  import org.opentrafficsim.road.gtu.lane.tactical.following.DualAccelerationStep;
26  import org.opentrafficsim.road.gtu.lane.tactical.following.GtuFollowingModelOld;
27  import org.opentrafficsim.road.network.lane.Lane;
28  
29  /**
30   * Common code for a family of lane change models like in M. Treiber and A. Kesting <i>Traffic Flow Dynamics</i>,
31   * Springer-Verlag Berlin Heidelberg 2013, pp 239-244.
32   * <p>
33   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
34   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
35   * </p>
36   * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
37   */
38  public abstract class AbstractLaneChangeModel implements LaneChangeModel
39  {
40  
41      /** Look ahead parameter type. */
42      protected static final ParameterTypeLength LOOKAHEAD = ParameterTypes.LOOKAHEAD;
43  
44      /** Comfortable deceleration parameter type. */
45      protected static final ParameterTypeAcceleration B = ParameterTypes.B;
46  
47      /** Attempt to overcome rounding errors. */
48      private static Acceleration extraThreshold = new Acceleration(0.000001, AccelerationUnit.SI);
49  
50      /** {@inheritDoc} */
51      @SuppressWarnings("checkstyle:parameternumber")
52      @Override
53      public final LaneMovementStep computeLaneChangeAndAcceleration(final LaneBasedGtu gtu,
54              final Collection<Headway> sameLaneGTUs, final Collection<Headway> preferredLaneGTUs,
55              final Collection<Headway> nonPreferredLaneGTUs, final Speed speedLimit,
56              final Acceleration preferredLaneRouteIncentive, final Acceleration laneChangeThreshold,
57              final Acceleration nonPreferredLaneRouteIncentive) throws ParameterException, OperationalPlanException
58      {
59          try
60          {
61              LanePerception perception = gtu.getTacticalPlanner().getPerception();
62              Length headway = gtu.getParameters().getParameter(LOOKAHEAD);
63              Map<Lane, Length> positions = gtu.positions(RelativePosition.REFERENCE_POSITION);
64              Lane lane = positions.keySet().iterator().next();
65              Length longitudinalPosition = positions.get(lane);
66              // TODO make this driving side dependent; i.e. implement a general way to figure out on which side of the
67              // road cars are supposed to drive
68              final LateralDirectionality preferred = LateralDirectionality.RIGHT;
69              final LateralDirectionality nonPreferred = LateralDirectionality.LEFT;
70              DefaultSimplePerception simplePerception = perception.getPerceptionCategory(DefaultSimplePerception.class);
71              simplePerception.updateAccessibleAdjacentLanes();
72              Lane nonPreferredLane = simplePerception.bestAccessibleAdjacentLane(lane, nonPreferred, longitudinalPosition);
73              Lane preferredLane = simplePerception.bestAccessibleAdjacentLane(lane, preferred, longitudinalPosition);
74              AbstractLaneBasedTacticalPlanner albtp = (AbstractLaneBasedTacticalPlanner) gtu.getTacticalPlanner();
75              if (null == albtp)
76              {
77                  throw new NullPointerException(gtu + " returns null for its tactical planner");
78              }
79              GtuFollowingModelOld gtuFollowingModel = (GtuFollowingModelOld) albtp.getCarFollowingModel();
80              if (null == gtuFollowingModel)
81              {
82                  throw new NullPointerException(gtu + " has null GtuFollowingModel");
83              }
84              DualAccelerationStep straightAccelerationSteps =
85                      gtuFollowingModel.computeDualAccelerationStep(gtu, sameLaneGTUs, headway, speedLimit);
86              if (straightAccelerationSteps.getLeaderAcceleration().getSI() < -9999)
87              {
88                  System.out.println("Problem");
89                  gtuFollowingModel.computeDualAccelerationStep(gtu, sameLaneGTUs, headway, speedLimit);
90              }
91              Acceleration straightA = applyDriverPersonality(straightAccelerationSteps).plus(laneChangeThreshold);
92              DualAccelerationStep nonPreferredAccelerationSteps = null == nonPreferredLane ? null
93                      : gtuFollowingModel.computeDualAccelerationStep(gtu, nonPreferredLaneGTUs, headway, speedLimit);
94              if (null != nonPreferredAccelerationSteps && nonPreferredAccelerationSteps.getFollowerAcceleration()
95                      .getSI() < -gtu.getParameters().getParameter(B).getSI())
96              {
97                  nonPreferredAccelerationSteps = AbstractGtuFollowingModelMobil.TOODANGEROUS;
98              }
99              Acceleration nonPreferredA =
100                     null == nonPreferredLane ? null : applyDriverPersonality(nonPreferredAccelerationSteps);
101             DualAccelerationStep preferredAccelerationSteps = null == preferredLane ? null
102                     : gtuFollowingModel.computeDualAccelerationStep(gtu, preferredLaneGTUs, headway, speedLimit);
103             if (null != preferredAccelerationSteps && preferredAccelerationSteps.getFollowerAcceleration()
104                     .getSI() < -gtu.getParameters().getParameter(B).getSI())
105             {
106                 preferredAccelerationSteps = AbstractGtuFollowingModelMobil.TOODANGEROUS;
107             }
108             Acceleration preferredA = null == preferredLane ? null : applyDriverPersonality(preferredAccelerationSteps);
109             if (null == preferredA)
110             {
111                 // Lane change to the preferred lane is not possible
112                 if (null == nonPreferredA)
113                 {
114                     // No lane change possible; this is definitely the easy case
115                     return new LaneMovementStep(straightAccelerationSteps.getLeaderAccelerationStep(), null);
116                 }
117                 else
118                 {
119                     // Merge to nonPreferredLane is possible; merge to preferredLane is NOT possible
120                     if (DoubleScalar.plus(nonPreferredA, nonPreferredLaneRouteIncentive).gt(straightA.plus(extraThreshold)))
121                     {
122                         // Merge to the nonPreferred lane; i.e. start an overtaking procedure
123                         return new LaneMovementStep(nonPreferredAccelerationSteps.getLeaderAccelerationStep(), nonPreferred);
124                     }
125                     else
126                     {
127                         // Stay in the current lane
128                         return new LaneMovementStep(straightAccelerationSteps.getLeaderAccelerationStep(), null);
129                     }
130                 }
131             }
132             // A merge to the preferredLane is possible
133             if (null == nonPreferredA)
134             {
135                 // Merge to preferredLane is possible; merge to nonPreferred lane is NOT possible
136                 if (DoubleScalar.plus(preferredA, preferredLaneRouteIncentive).plus(extraThreshold).ge(straightA))
137                 {
138                     // Merge to the preferred lane; i.e. finish (or cancel) an overtaking procedure
139                     return new LaneMovementStep(preferredAccelerationSteps.getLeaderAccelerationStep(), preferred);
140                 }
141                 else
142                 {
143                     // Stay in current lane
144                     return new LaneMovementStep(straightAccelerationSteps.getLeaderAccelerationStep(), null);
145                 }
146             }
147             // All merges are possible
148             Acceleration preferredAttractiveness =
149                     preferredA.plus(preferredLaneRouteIncentive).minus(straightA).plus(extraThreshold);
150             Acceleration nonPreferredAttractiveness =
151                     nonPreferredA.plus(nonPreferredLaneRouteIncentive).minus(straightA).minus(extraThreshold);
152             if (preferredAttractiveness.getSI() < 0 && nonPreferredAttractiveness.getSI() <= 0)
153             {
154                 // Stay in current lane
155                 return new LaneMovementStep(straightAccelerationSteps.getLeaderAccelerationStep(), null);
156 
157             }
158             if (preferredAttractiveness.getSI() >= 0 && preferredAttractiveness.gt(nonPreferredAttractiveness))
159             {
160                 // Merge to the preferred lane; i.e. finish (or cancel) an overtaking procedure
161                 return new LaneMovementStep(preferredAccelerationSteps.getLeaderAccelerationStep(), preferred);
162             }
163             // Merge to the adjacent nonPreferred lane; i.e. start an overtaking procedure
164             return new LaneMovementStep(nonPreferredAccelerationSteps.getLeaderAccelerationStep(), nonPreferred);
165         }
166         catch (GtuException exception)
167         {
168             throw new RuntimeException(exception);
169         }
170     }
171 
172     /**
173      * Return the weighted acceleration as described by the personality. This incorporates the personality of the driver to the
174      * lane change decisions.
175      * @param accelerationSteps DualAccelerationStep; the DualAccelerationStep that contains the AccelerationStep that the
176      *            reference GTU will make and the AccelerationStep that the (new) follower GTU will make
177      * @return Acceleration; the acceleration that the personality of the driver uses (in a comparison to a similarly computed
178      *         acceleration in the non-, or different-lane-changed state) to decide if a lane change should be performed
179      */
180     public abstract Acceleration applyDriverPersonality(DualAccelerationStep accelerationSteps);
181 
182 }