View Javadoc
1   package org.opentrafficsim.road.gtu.lane.tactical.lmrs;
2   
3   import java.util.SortedSet;
4   
5   import org.djunits.value.vdouble.scalar.Length;
6   import org.djunits.value.vdouble.scalar.Speed;
7   import org.opentrafficsim.base.parameters.ParameterException;
8   import org.opentrafficsim.base.parameters.ParameterTypeDuration;
9   import org.opentrafficsim.base.parameters.ParameterTypeLength;
10  import org.opentrafficsim.base.parameters.ParameterTypes;
11  import org.opentrafficsim.base.parameters.Parameters;
12  import org.opentrafficsim.core.gtu.Stateless;
13  import org.opentrafficsim.core.gtu.perception.EgoPerception;
14  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
15  import org.opentrafficsim.core.network.LateralDirectionality;
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.tactical.following.CarFollowingModel;
20  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Desire;
21  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.MandatoryIncentive;
22  import org.opentrafficsim.road.network.LaneChangeInfo;
23  
24  /**
25   * Determines desire by assessing the number of required lane change to be performed and the distance within which these have to
26   * be performed. Desire starts to increase from 0 linearly over a distance of x0 per required lane change, or per v*t0 per
27   * required lane change. For v>x0/t0 this gives that remaining time is critical, while for v<x0/t0 remaining space is
28   * critical. The desire is set towards the adjacent lane with a better situation. Negative desire towards the other lane, the
29   * extent of which pertains to the other adjacent lane, is also set.
30   * <p>
31   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
32   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
33   * </p>
34   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
35   */
36  public final class IncentiveRoute implements MandatoryIncentive, Stateless<IncentiveRoute>
37  {
38  
39      /** Look ahead parameter type. */
40      protected static final ParameterTypeLength LOOKAHEAD = ParameterTypes.LOOKAHEAD;
41  
42      /** Look-ahead time for mandatory lane changes parameter type. */
43      public static final ParameterTypeDuration T0 = ParameterTypes.T0;
44  
45      /** Singleton instance. */
46      public static final IncentiveRoute SINGLETON = new IncentiveRoute();
47  
48      @Override
49      public IncentiveRoute get()
50      {
51          return SINGLETON;
52      }
53  
54      /**
55       * Constructor.
56       */
57      private IncentiveRoute()
58      {
59          //
60      }
61  
62      @Override
63      public Desire determineDesire(final Parameters parameters, final LanePerception perception,
64              final CarFollowingModel carFollowingModel, final Desire mandatoryDesire)
65              throws ParameterException, OperationalPlanException
66      {
67          Speed speed = perception.getPerceptionCategory(EgoPerception.class).getSpeed();
68          InfrastructurePerception infra = perception.getPerceptionCategory(InfrastructurePerception.class);
69  
70          // desire to leave current lane
71          SortedSet<LaneChangeInfo> currentInfo = infra.getLegalLaneChangeInfo(RelativeLane.CURRENT);
72          Length currentFirst = currentInfo.isEmpty() || currentInfo.first().numberOfLaneChanges() == 0 ? Length.POSITIVE_INFINITY
73                  : currentInfo.first().remainingDistance();
74          double dCurr = getDesireToLeave(parameters, infra, RelativeLane.CURRENT, speed);
75          double dLeft = 0;
76          if (perception.getLaneStructure().exists(RelativeLane.LEFT)
77                  && infra.getLegalLaneChangePossibility(RelativeLane.CURRENT, LateralDirectionality.LEFT).neg().lt(currentFirst))
78          {
79              // desire to leave left lane
80              dLeft = getDesireToLeave(parameters, infra, RelativeLane.LEFT, speed);
81              // desire to leave from current to left lane
82              dLeft = dLeft < dCurr ? dCurr : dLeft > dCurr ? -dLeft : 0;
83          }
84          double dRigh = 0;
85          if (perception.getLaneStructure().exists(RelativeLane.RIGHT) && infra
86                  .getLegalLaneChangePossibility(RelativeLane.CURRENT, LateralDirectionality.RIGHT).neg().lt(currentFirst))
87          {
88              // desire to leave right lane
89              dRigh = getDesireToLeave(parameters, infra, RelativeLane.RIGHT, speed);
90              // desire to leave from current to right lane
91              dRigh = dRigh < dCurr ? dCurr : dRigh > dCurr ? -dRigh : 0;
92          }
93          return new Desire(dLeft, dRigh);
94      }
95  
96      /**
97       * Calculates desire to leave a lane.
98       * @param params parameters
99       * @param infra infrastructure perception
100      * @param lane relative lane to evaluate
101      * @param speed speed
102      * @return desire to leave a lane
103      * @throws ParameterException in case of a parameter exception
104      * @throws OperationalPlanException in case of perception exceptions
105      */
106     private static double getDesireToLeave(final Parameters params, final InfrastructurePerception infra,
107             final RelativeLane lane, final Speed speed) throws ParameterException, OperationalPlanException
108     {
109         double dOut = 0.0;
110         if (infra.getCrossSection().contains(lane))
111         {
112             for (LaneChangeInfo info : infra.getLegalLaneChangeInfo(lane))
113             {
114                 double d = info.remainingDistance().lt0() ? info.numberOfLaneChanges()
115                         : getDesireToLeave(params, info.remainingDistance(), info.numberOfLaneChanges(), speed);
116                 dOut = d > dOut ? d : dOut;
117             }
118         }
119         return dOut;
120     }
121 
122     /**
123      * Calculates desire to leave a lane for a single infrastructure info.
124      * @param params parameters
125      * @param x remaining distance for lane changes
126      * @param n number of required lane changes
127      * @param v current speed
128      * @return desire to leave a lane for a single infrastructure info
129      * @throws ParameterException in case of a parameter exception
130      */
131     public static double getDesireToLeave(final Parameters params, final Length x, final int n, final Speed v)
132             throws ParameterException
133     {
134         double d1 = 1 - x.si / (n * params.getParameter(LOOKAHEAD).si);
135         double d2 = 1 - (x.si / v.si) / (n * params.getParameter(T0).si);
136         d1 = d2 > d1 ? d2 : d1;
137         return d1 < 0 ? 0 : d1;
138     }
139 
140     @Override
141     public String toString()
142     {
143         return "IncentiveRoute";
144     }
145 
146 }