View Javadoc
1   package org.opentrafficsim.road.gtu.following;
2   
3   import java.util.Collection;
4   
5   import org.djunits.unit.AccelerationUnit;
6   import org.djunits.unit.LengthUnit;
7   import org.djunits.unit.TimeUnit;
8   import org.opentrafficsim.core.network.NetworkException;
9   import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
10  
11  /**
12   * Code shared between various car following models.
13   * <p>
14   * Copyright (c) 2013-2015 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
15   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
16   * <p>
17   * @version $Revision: 1408 $, $LastChangedDate: 2015-09-24 15:17:25 +0200 (Thu, 24 Sep 2015) $, by $Author: pknoppers $,
18   *          initial version 19 feb. 2015 <br>
19   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
20   * @author <a href="http://Hansvanlint.weblog.tudelft.nl">Hans van Lint</a>
21   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
22   * @author <a href="http://www.citg.tudelft.nl">Guus Tamminga</a>
23   * @author <a href="http://www.citg.tudelft.nl">Yufei Yuan</a>
24   */
25  public abstract class AbstractGTUFollowingModel implements GTUFollowingModel
26  {
27      /** Prohibitive deceleration used to construct the TOODANGEROUS result below. */
28      private static final AccelerationStep PROHIBITIVEACCELERATIONSTEP = new AccelerationStep(new Acceleration.Abs(
29          Double.NEGATIVE_INFINITY, AccelerationUnit.SI), new Time.Abs(Double.NaN, TimeUnit.SI));
30  
31      /** Return value if lane change causes immediate collision. */
32      public static final DualAccelerationStep TOODANGEROUS = new DualAccelerationStep(PROHIBITIVEACCELERATIONSTEP,
33          PROHIBITIVEACCELERATIONSTEP);
34  
35      /** {@inheritDoc} */
36      @Override
37      public final DualAccelerationStep computeAcceleration(final LaneBasedGTU referenceGTU,
38          final Collection<HeadwayGTU> otherGTUs, final Speed.Abs speedLimit) throws NetworkException
39      {
40          Time.Abs when = referenceGTU.getSimulator().getSimulatorTime().getTime();
41          // Find out if there is an immediate collision
42          for (HeadwayGTU headwayGTU : otherGTUs)
43          {
44              if (headwayGTU.getOtherGTU() != referenceGTU && null == headwayGTU.getDistance())
45              {
46                  return TOODANGEROUS;
47              }
48          }
49          AccelerationStep followerAccelerationStep = null;
50          AccelerationStep referenceGTUAccelerationStep = null;
51          GTUFollowingModel gfm = referenceGTU.getGTUFollowingModel();
52          // Find the leader and the follower that cause/experience the least positive (most negative) acceleration.
53          for (HeadwayGTU headwayGTU : otherGTUs)
54          {
55              if (null == headwayGTU.getOtherGTU())
56              {
57                  System.out.println("FollowAcceleration.acceleration: Cannot happen");
58              }
59              if (headwayGTU.getOtherGTU() == referenceGTU)
60              {
61                  continue;
62              }
63              if (headwayGTU.getDistanceSI() < 0)
64              {
65                  // This one is behind
66                  AccelerationStep as =
67                      gfm.computeAcceleration(headwayGTU.getOtherGTU(), referenceGTU.getLongitudinalVelocity(when),
68                          new Length.Rel(-headwayGTU.getDistanceSI(), LengthUnit.SI), speedLimit);
69                  if (null == followerAccelerationStep || as.getAcceleration().lt(followerAccelerationStep.getAcceleration()))
70                  {
71                      // if (as.getAcceleration().getSI() < -gfm.maximumSafeDeceleration().getSI())
72                      // {
73                      // return TOODANGEROUS;
74                      // }
75                      followerAccelerationStep = as;
76                  }
77              }
78              else
79              {
80                  // This one is ahead
81                  AccelerationStep as =
82                      gfm.computeAcceleration(referenceGTU, headwayGTU.getOtherGTU().getLongitudinalVelocity(when), headwayGTU
83                          .getDistance(), speedLimit);
84                  if (null == referenceGTUAccelerationStep
85                      || as.getAcceleration().lt(referenceGTUAccelerationStep.getAcceleration()))
86                  {
87                      referenceGTUAccelerationStep = as;
88                  }
89              }
90          }
91          if (null == followerAccelerationStep)
92          {
93              followerAccelerationStep = gfm.computeAccelerationWithNoLeader(referenceGTU, speedLimit);
94          }
95          if (null == referenceGTUAccelerationStep)
96          {
97              referenceGTUAccelerationStep = gfm.computeAccelerationWithNoLeader(referenceGTU, speedLimit);
98          }
99          return new DualAccelerationStep(referenceGTUAccelerationStep, followerAccelerationStep);
100     }
101 
102     /** {@inheritDoc} */
103     @Override
104     public final AccelerationStep computeAcceleration(final LaneBasedGTU follower, final Speed.Abs leaderSpeed,
105         final Length.Rel headway, final Speed.Abs speedLimit) 
106     {
107         final Time.Abs currentTime = follower.getNextEvaluationTime();
108         final Speed.Abs followerSpeed = follower.getLongitudinalVelocity(currentTime);
109         final Speed.Abs followerMaximumSpeed = follower.getMaximumVelocity();
110         Acceleration.Abs newAcceleration =
111             computeAcceleration(followerSpeed, followerMaximumSpeed, leaderSpeed, headway, speedLimit);
112         Time.Abs nextEvaluationTime = currentTime;
113         nextEvaluationTime = nextEvaluationTime.plus(getStepSize());
114         return new AccelerationStep(newAcceleration, nextEvaluationTime);
115 
116     }
117 
118     /** {@inheritDoc} */
119     @Override
120     public final AccelerationStep computeAccelerationWithNoLeader(final LaneBasedGTU gtu, final Speed.Abs speedLimit)
121         throws NetworkException
122     {
123         Length.Rel stopDistance = new Length.Rel(gtu.getMaximumVelocity().si * gtu.getMaximumVelocity().si 
124                 / (2.0 * maximumSafeDeceleration().si), LengthUnit.SI);
125         return computeAcceleration(gtu, gtu.getLongitudinalVelocity(), stopDistance, speedLimit);
126         /*-
127         return computeAcceleration(gtu, gtu.getLongitudinalVelocity(), Calc.speedSquaredDividedByDoubleAcceleration(gtu
128             .getMaximumVelocity(), maximumSafeDeceleration()), speedLimit);
129             */
130     }
131 
132     /** {@inheritDoc} */
133     @Override
134     public final Length.Rel minimumHeadway(final Speed.Abs followerSpeed, final Speed.Abs leaderSpeed,
135         final Length.Rel precision, final Speed.Abs speedLimit, final Speed.Abs followerMaximumSpeed) 
136     {
137         if (precision.getSI() <= 0)
138         {
139             throw new Error("Precision has bad value (must be > 0; got " + precision + ")");
140         }
141         double maximumDeceleration = -maximumSafeDeceleration().getSI();
142         // Find a decent interval to bisect
143         double minimumSI = 0;
144         double minimumSIDeceleration =
145             computeAcceleration(followerSpeed, followerSpeed, leaderSpeed, new Length.Rel(minimumSI, LengthUnit.SI),
146                 speedLimit).getSI();
147         if (minimumSIDeceleration >= maximumDeceleration)
148         {
149             // Weird... The GTU following model allows zero headway
150             return new Length.Rel(0, LengthUnit.SI);
151         }
152         double maximumSI = 1; // this is - deliberately - way too small
153         double maximumSIDeceleration = Double.NaN;
154         // Double the value of maximumSI until the resulting deceleration is less severe than the maximum
155         for (int step = 0; step < 20; step++)
156         {
157             maximumSIDeceleration =
158                 computeAcceleration(followerSpeed, followerMaximumSpeed, leaderSpeed,
159                     new Length.Rel(maximumSI, LengthUnit.SI), speedLimit).getSI();
160             if (maximumSIDeceleration > maximumDeceleration)
161             {
162                 break;
163             }
164             maximumSI *= 2;
165         }
166         if (maximumSIDeceleration < maximumDeceleration)
167         {
168             throw new Error("Cannot find headway that results in an acceptable deceleration");
169         }
170         // Now bisect until the error is less than the requested precision
171         final int maximumStep = (int) Math.ceil(Math.log((maximumSI - minimumSI) / precision.getSI()) / Math.log(2));
172         for (int step = 0; step < maximumStep; step++)
173         {
174             double midSI = (minimumSI + maximumSI) / 2;
175             double midSIAcceleration =
176                 computeAcceleration(followerSpeed, followerMaximumSpeed, leaderSpeed, new Length.Rel(midSI, LengthUnit.SI),
177                     speedLimit).getSI();
178             if (midSIAcceleration < maximumDeceleration)
179             {
180                 minimumSI = midSI;
181             }
182             else
183             {
184                 maximumSI = midSI;
185             }
186         }
187         Length.Rel result = new Length.Rel((minimumSI + maximumSI) / 2, LengthUnit.SI);
188         computeAcceleration(followerSpeed, followerMaximumSpeed, leaderSpeed, new Length.Rel(result.getSI(), LengthUnit.SI),
189             speedLimit).getSI();
190         return result;
191     }
192 }