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