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