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