View Javadoc
1   package org.opentrafficsim.road.gtu.lane.tactical.lmrs;
2   
3   import org.djunits.value.vdouble.scalar.Length;
4   import org.djunits.value.vdouble.scalar.Speed;
5   import org.djunits.value.vdouble.scalar.Time;
6   import org.djutils.draw.point.OrientedPoint2d;
7   import org.djutils.exceptions.Try;
8   import org.opentrafficsim.base.parameters.ParameterException;
9   import org.opentrafficsim.base.parameters.ParameterTypes;
10  import org.opentrafficsim.base.parameters.Parameters;
11  import org.opentrafficsim.core.gtu.GtuException;
12  import org.opentrafficsim.core.gtu.perception.EgoPerception;
13  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlan;
14  import org.opentrafficsim.core.network.NetworkException;
15  import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
16  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
17  import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
18  import org.opentrafficsim.road.gtu.lane.perception.categories.InfrastructurePerception;
19  import org.opentrafficsim.road.gtu.lane.plan.operational.LaneChange;
20  import org.opentrafficsim.road.gtu.lane.plan.operational.LaneOperationalPlanBuilder;
21  import org.opentrafficsim.road.gtu.lane.plan.operational.SimpleOperationalPlan;
22  import org.opentrafficsim.road.gtu.lane.tactical.Blockable;
23  import org.opentrafficsim.road.gtu.lane.tactical.DesireBased;
24  import org.opentrafficsim.road.gtu.lane.tactical.Synchronizable;
25  import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
26  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Cooperation;
27  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Desire;
28  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.GapAcceptance;
29  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Incentive;
30  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsData;
31  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsParameters;
32  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsUtil;
33  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Synchronization;
34  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Tailgating;
35  import org.opentrafficsim.road.network.speed.SpeedLimitInfo;
36  import org.opentrafficsim.road.network.speed.SpeedLimitProspect;
37  
38  /**
39   * Implementation of the LMRS (Lane change Model with Relaxation and Synchronization). See Schakel, W.J., Knoop, V.L., and Van
40   * Arem, B. (2012), <a href="http://victorknoop.eu/research/papers/TRB2012_LMRS_reviewed.pdf">LMRS: Integrated Lane Change Model
41   * with Relaxation and Synchronization</a>, Transportation Research Records: Journal of the Transportation Research Board, No.
42   * 2316, pp. 47-57. Note in the official versions of TRB and TRR some errors appeared due to the typesetting of the papers (not
43   * in the preprint provided here). A list of errata for the official versions is found
44   * <a href="http://victorknoop.eu/research/papers/Erratum_LMRS.pdf">here</a>.
45   * <p>
46   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
47   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
48   * </p>
49   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
50   */
51  public class Lmrs extends AbstractIncentivesTacticalPlanner implements DesireBased, Synchronizable, Blockable
52  {
53  
54      /** Serialization id. */
55      private static final long serialVersionUID = 20160300L;
56  
57      /** Lane change status. */
58      private final LaneChange laneChange;
59  
60      /** LMRS data. */
61      private final LmrsData lmrsData;
62  
63      /**
64       * Constructor setting the car-following model.
65       * @param carFollowingModel Car-following model.
66       * @param gtu GTU
67       * @param lanePerception perception
68       * @param synchronization type of synchronization
69       * @param cooperation type of cooperation
70       * @param gapAcceptance gap-acceptance
71       * @param tailgating tail gating
72       */
73      public Lmrs(final CarFollowingModel carFollowingModel, final LaneBasedGtu gtu, final LanePerception lanePerception,
74              final Synchronization synchronization, final Cooperation cooperation, final GapAcceptance gapAcceptance,
75              final Tailgating tailgating)
76      {
77          super(carFollowingModel, gtu, lanePerception);
78          this.laneChange = Try.assign(() -> new LaneChange(gtu), "Parameter LCDUR is required.", GtuException.class);
79          this.lmrsData = new LmrsData(synchronization, cooperation, gapAcceptance, tailgating);
80      }
81  
82      @Override
83      public final OperationalPlan generateOperationalPlan(final Time startTime, final OrientedPoint2d locationAtStartTime)
84              throws GtuException, NetworkException, ParameterException
85      {
86          // obtain objects to get info
87          SpeedLimitProspect slp = getPerception().getPerceptionCategory(InfrastructurePerception.class)
88                  .getSpeedLimitProspect(RelativeLane.CURRENT);
89          SpeedLimitInfo sli = slp.getSpeedLimitInfo(Length.ZERO);
90          Parameters params = getGtu().getParameters();
91  
92          // LMRS
93          SimpleOperationalPlan simplePlan = LmrsUtil.determinePlan(getGtu(), startTime, getCarFollowingModel(), this.laneChange,
94                  this.lmrsData, getPerception(), getMandatoryIncentives(), getVoluntaryIncentives());
95  
96          // Lower acceleration from additional sources, consider adjacent lane when changing lane or synchronizing
97          Speed speed = getPerception().getPerceptionCategory(EgoPerception.class).getSpeed();
98          RelativeLane[] lanes;
99          double dLeft = params.getParameterOrNull(LmrsParameters.DLEFT);
100         double dRight = params.getParameterOrNull(LmrsParameters.DRIGHT);
101         double dSync = params.getParameterOrNull(LmrsParameters.DSYNC);
102         if (this.laneChange.isChangingLane())
103         {
104             lanes = new RelativeLane[] {RelativeLane.CURRENT, this.laneChange.getSecondLane(getGtu())};
105         }
106         else if (dLeft >= dSync && dLeft >= dRight)
107         {
108             lanes = new RelativeLane[] {RelativeLane.CURRENT, RelativeLane.LEFT};
109         }
110         else if (dRight >= dSync)
111         {
112             lanes = new RelativeLane[] {RelativeLane.CURRENT, RelativeLane.RIGHT};
113         }
114         else
115         {
116             lanes = new RelativeLane[] {RelativeLane.CURRENT};
117         }
118         for (RelativeLane lane : lanes)
119         {
120             if (getPerception().getLaneStructure().getRootCrossSection().contains(lane))
121             {
122                 // On the current lane, consider all incentives. On adjacent lanes only consider incentives beyond the distance
123                 // over
124                 // which a lane change is not yet possible, i.e. the merge distance.
125                 // TODO: consider route in incentives (only if not on current lane?)
126                 Length mergeDistance = lane.isCurrent() ? Length.ZERO
127                         : Synchronization.getMergeDistance(getPerception(), lane.getLateralDirectionality());
128                 for (AccelerationIncentive incentive : getAccelerationIncentives())
129                 {
130                     incentive.accelerate(simplePlan, lane, mergeDistance, getGtu(), getPerception(), getCarFollowingModel(),
131                             speed, params, sli);
132                 }
133             }
134         }
135 
136         if (simplePlan.isLaneChange())
137         {
138             this.laneChange.setDesiredLaneChangeDuration(getGtu().getParameters().getParameter(ParameterTypes.LCDUR));
139             // adjust lane based data in perception
140         }
141 
142         // set turn indicator
143         simplePlan.setTurnIndicator(getGtu());
144 
145         // create plan
146         return LaneOperationalPlanBuilder.buildPlanFromSimplePlan(getGtu(), startTime, simplePlan, this.laneChange);
147 
148     }
149 
150     @Override
151     public final Desire getLatestDesire(final Class<? extends Incentive> incentiveClass)
152     {
153         return this.lmrsData.getLatestDesire(incentiveClass);
154     }
155 
156     @Override
157     public Synchronizable.State getSynchronizationState()
158     {
159         return this.lmrsData.getSynchronizationState();
160     }
161 
162     @Override
163     public boolean isBlocking()
164     {
165         for (AccelerationIncentive acc : getAccelerationIncentives())
166         {
167             if (acc instanceof AccelerationConflicts)
168             {
169                 return ((AccelerationConflicts) acc).isBlocking();
170             }
171         }
172         return false;
173     }
174 
175     @Override
176     public final String toString()
177     {
178         return "LMRS [mandatoryIncentives=" + getMandatoryIncentives() + ", voluntaryIncentives=" + getVoluntaryIncentives()
179                 + ", accelerationIncentives = " + getAccelerationIncentives() + "]";
180     }
181 
182 }