LmrsUtil.java

  1. package org.opentrafficsim.road.gtu.lane.tactical.util.lmrs;

  2. import java.util.Iterator;
  3. import java.util.LinkedHashSet;
  4. import java.util.Map;
  5. import java.util.SortedSet;

  6. import org.djunits.value.vdouble.scalar.Acceleration;
  7. import org.djunits.value.vdouble.scalar.Duration;
  8. import org.djunits.value.vdouble.scalar.Length;
  9. import org.djunits.value.vdouble.scalar.Speed;
  10. import org.djunits.value.vdouble.scalar.Time;
  11. import org.opentrafficsim.base.parameters.ParameterException;
  12. import org.opentrafficsim.base.parameters.ParameterTypeAcceleration;
  13. import org.opentrafficsim.base.parameters.ParameterTypeDuration;
  14. import org.opentrafficsim.base.parameters.ParameterTypes;
  15. import org.opentrafficsim.base.parameters.Parameters;
  16. import org.opentrafficsim.core.gtu.GTUException;
  17. import org.opentrafficsim.core.gtu.Try;
  18. import org.opentrafficsim.core.gtu.TurnIndicatorIntent;
  19. import org.opentrafficsim.core.gtu.perception.EgoPerception;
  20. import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
  21. import org.opentrafficsim.core.network.LateralDirectionality;
  22. import org.opentrafficsim.core.network.NetworkException;
  23. import org.opentrafficsim.road.gtu.animation.Synchronizable.State;
  24. import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
  25. import org.opentrafficsim.road.gtu.lane.perception.InfrastructureLaneChangeInfo;
  26. import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
  27. import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable;
  28. import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
  29. import org.opentrafficsim.road.gtu.lane.perception.categories.InfrastructurePerception;
  30. import org.opentrafficsim.road.gtu.lane.perception.categories.IntersectionPerception;
  31. import org.opentrafficsim.road.gtu.lane.perception.categories.NeighborsPerception;
  32. import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayConflict;
  33. import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTU;
  34. import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayTrafficLight;
  35. import org.opentrafficsim.road.gtu.lane.plan.operational.LaneChange;
  36. import org.opentrafficsim.road.gtu.lane.plan.operational.SimpleOperationalPlan;
  37. import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
  38. import org.opentrafficsim.road.gtu.lane.tactical.util.CarFollowingUtil;
  39. import org.opentrafficsim.road.network.speed.SpeedLimitInfo;
  40. import org.opentrafficsim.road.network.speed.SpeedLimitProspect;

  41. /**
  42.  * <p>
  43.  * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  44.  * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
  45.  * <p>
  46.  * @version $Revision$, $LastChangedDate$, by $Author$, initial version Jul 26, 2016 <br>
  47.  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  48.  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  49.  * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
  50.  */
  51. public final class LmrsUtil implements LmrsParameters
  52. {

  53.     /** Fixed model time step. */
  54.     public static final ParameterTypeDuration DT = ParameterTypes.DT;

  55.     /** Minimum car-following headway. */
  56.     public static final ParameterTypeDuration TMIN = ParameterTypes.TMIN;

  57.     /** Current car-following headway. */
  58.     public static final ParameterTypeDuration T = ParameterTypes.T;

  59.     /** Maximum car-following headway. */
  60.     public static final ParameterTypeDuration TMAX = ParameterTypes.TMAX;

  61.     /** Headway relaxation time. */
  62.     public static final ParameterTypeDuration TAU = ParameterTypes.TAU;

  63.     /** Maximum critical deceleration, e.g. stop/go at traffic light. */
  64.     public static final ParameterTypeAcceleration BCRIT = ParameterTypes.BCRIT;

  65.     /**
  66.      * Do not instantiate.
  67.      */
  68.     private LmrsUtil()
  69.     {
  70.         //
  71.     }

  72.     /**
  73.      * Determines a simple representation of an operational plan.
  74.      * @param gtu gtu
  75.      * @param startTime start time
  76.      * @param carFollowingModel car-following model
  77.      * @param laneChange lane change status
  78.      * @param lmrsData LMRS data
  79.      * @param perception perception
  80.      * @param mandatoryIncentives set of mandatory lane change incentives
  81.      * @param voluntaryIncentives set of voluntary lane change incentives
  82.      * @return simple operational plan
  83.      * @throws GTUException gtu exception
  84.      * @throws NetworkException network exception
  85.      * @throws ParameterException parameter exception
  86.      * @throws OperationalPlanException operational plan exception
  87.      */
  88.     @SuppressWarnings("checkstyle:parameternumber")
  89.     public static SimpleOperationalPlan determinePlan(final LaneBasedGTU gtu, final Time startTime,
  90.             final CarFollowingModel carFollowingModel, final LaneChange laneChange, final LmrsData lmrsData,
  91.             final LanePerception perception, final LinkedHashSet<MandatoryIncentive> mandatoryIncentives,
  92.             final LinkedHashSet<VoluntaryIncentive> voluntaryIncentives)
  93.             throws GTUException, NetworkException, ParameterException, OperationalPlanException
  94.     {

  95.         // obtain objects to get info
  96.         InfrastructurePerception infra = perception.getPerceptionCategory(InfrastructurePerception.class);
  97.         SpeedLimitProspect slp = infra.getSpeedLimitProspect(RelativeLane.CURRENT);
  98.         SpeedLimitInfo sli = slp.getSpeedLimitInfo(Length.ZERO);
  99.         Parameters params = gtu.getParameters();
  100.         EgoPerception ego = perception.getPerceptionCategory(EgoPerception.class);
  101.         Speed speed = ego.getSpeed();
  102.         NeighborsPerception neighbors = perception.getPerceptionCategory(NeighborsPerception.class);
  103.         PerceptionCollectable<HeadwayGTU, LaneBasedGTU> leaders = neighbors.getLeaders(RelativeLane.CURRENT);

  104.         // regular car-following
  105.         lmrsData.getTailGating().tailgate(perception, params);
  106.         if (!leaders.isEmpty() && lmrsData.isNewLeader(leaders.first()))
  107.         {
  108.             initHeadwayRelaxation(params, leaders.first());
  109.         }
  110.         Acceleration a = gtu.getCarFollowingAcceleration();

  111.         // during a lane change, both leaders are followed
  112.         LateralDirectionality initiatedLaneChange;
  113.         TurnIndicatorIntent turnIndicatorStatus = TurnIndicatorIntent.NONE;
  114.         if (laneChange.isChangingLane())
  115.         {
  116.             RelativeLane secondLane = laneChange.getSecondLane(gtu);
  117.             initiatedLaneChange = LateralDirectionality.NONE;
  118.             PerceptionCollectable<HeadwayGTU, LaneBasedGTU> secondLeaders = neighbors.getLeaders(secondLane);
  119.             Acceleration aSecond = carFollowingModel.followingAcceleration(params, speed, sli, secondLeaders);
  120.             if (!secondLeaders.isEmpty() && lmrsData.isNewLeader(secondLeaders.first()))
  121.             {
  122.                 initHeadwayRelaxation(params, secondLeaders.first());
  123.             }
  124.             a = Acceleration.min(a, aSecond);
  125.         }
  126.         else
  127.         {

  128.             // determine lane change desire based on incentives
  129.             Desire desire = getLaneChangeDesire(params, perception, carFollowingModel, mandatoryIncentives, voluntaryIncentives,
  130.                     lmrsData.desireMap);
  131.            
  132.             // lane change decision
  133.             double dFree = params.getParameter(DFREE);
  134.             initiatedLaneChange = LateralDirectionality.NONE;
  135.             turnIndicatorStatus = TurnIndicatorIntent.NONE;
  136.             if (desire.leftIsLargerOrEqual() && desire.getLeft() >= dFree)
  137.             {
  138.                 if (acceptLaneChange(perception, params, sli, carFollowingModel, desire.getLeft(), speed, a,
  139.                         LateralDirectionality.LEFT, lmrsData.getGapAcceptance()))
  140.                 {
  141.                     // change left
  142.                     initiatedLaneChange = LateralDirectionality.LEFT;
  143.                     turnIndicatorStatus = TurnIndicatorIntent.LEFT;
  144.                     params.setParameter(DLC, desire.getLeft());
  145.                     setDesiredHeadway(params, desire.getLeft());
  146.                     leaders = neighbors.getLeaders(RelativeLane.LEFT);
  147.                     if (!leaders.isEmpty())
  148.                     {
  149.                         // don't respond on its lane change desire, but remember it such that it isn't a new leader in the next
  150.                         // step
  151.                         lmrsData.isNewLeader(leaders.first());
  152.                     }
  153.                     a = Acceleration.min(a, carFollowingModel.followingAcceleration(params, speed, sli,
  154.                             neighbors.getLeaders(RelativeLane.LEFT)));
  155.                 }
  156.             }
  157.             else if (!desire.leftIsLargerOrEqual() && desire.getRight() >= dFree)
  158.             {
  159.                 if (acceptLaneChange(perception, params, sli, carFollowingModel, desire.getRight(), speed, a,
  160.                         LateralDirectionality.RIGHT, lmrsData.getGapAcceptance()))
  161.                 {
  162.                     // change right
  163.                     initiatedLaneChange = LateralDirectionality.RIGHT;
  164.                     turnIndicatorStatus = TurnIndicatorIntent.RIGHT;
  165.                     params.setParameter(DLC, desire.getRight());
  166.                     setDesiredHeadway(params, desire.getRight());
  167.                     leaders = neighbors.getLeaders(RelativeLane.RIGHT);
  168.                     if (!leaders.isEmpty())
  169.                     {
  170.                         // don't respond on its lane change desire, but remember it such that it isn't a new leader in the next
  171.                         // step
  172.                         lmrsData.isNewLeader(leaders.first());
  173.                     }
  174.                     a = Acceleration.min(a, carFollowingModel.followingAcceleration(params, speed, sli,
  175.                             neighbors.getLeaders(RelativeLane.RIGHT)));
  176.                 }
  177.             }
  178.             if (!initiatedLaneChange.isNone())
  179.             {
  180.                 SortedSet<InfrastructureLaneChangeInfo> set = infra.getInfrastructureLaneChangeInfo(RelativeLane.CURRENT);
  181.                 if (!set.isEmpty())
  182.                 {
  183.                     Length boundary = null;
  184.                     for (InfrastructureLaneChangeInfo info : set)
  185.                     {
  186.                         int n = info.getRequiredNumberOfLaneChanges();
  187.                         if (n > 1)
  188.                         {
  189.                             Length thisBoundary = info.getRemainingDistance()
  190.                                     .minus(Synchronization.requiredBufferSpace(speed, info.getRequiredNumberOfLaneChanges(),
  191.                                             params.getParameter(ParameterTypes.LOOKAHEAD),
  192.                                             params.getParameter(ParameterTypes.T0), params.getParameter(ParameterTypes.LCDUR),
  193.                                             params.getParameter(DCOOP)));
  194.                             if (thisBoundary.le0())
  195.                             {
  196.                                 thisBoundary = info.getRemainingDistance().divideBy(info.getRequiredNumberOfLaneChanges());
  197.                             }
  198.                             boundary = boundary == null || thisBoundary.si < boundary.si ? thisBoundary : boundary;
  199.                         }
  200.                     }
  201.                     laneChange.setBoundary(boundary);
  202.                 }
  203.             }

  204.             // take action if we cannot change lane
  205.             Acceleration aSync;
  206.             if (initiatedLaneChange.equals(LateralDirectionality.NONE))
  207.             {

  208.                 // synchronize
  209.                 double dSync = params.getParameter(DSYNC);
  210.                 if (desire.leftIsLargerOrEqual() && desire.getLeft() >= dSync)
  211.                 {
  212.                     State state;
  213.                     if (desire.getLeft() >= params.getParameter(DCOOP))
  214.                     {
  215.                         // switch on left indicator
  216.                         turnIndicatorStatus = TurnIndicatorIntent.LEFT;
  217.                         state = State.INDICATING;
  218.                     }
  219.                     else
  220.                     {
  221.                         state = State.SYNCHRONIZING;
  222.                     }
  223.                     aSync = lmrsData.getSynchronization().synchronize(perception, params, sli, carFollowingModel,
  224.                             desire.getLeft(), LateralDirectionality.LEFT, lmrsData);
  225.                     a = applyAcceleration(a, aSync, lmrsData, state);
  226.                 }
  227.                 else if (!desire.leftIsLargerOrEqual() && desire.getRight() >= dSync)
  228.                 {
  229.                     State state;
  230.                     if (desire.getRight() >= params.getParameter(DCOOP))
  231.                     {
  232.                         // switch on right indicator
  233.                         turnIndicatorStatus = TurnIndicatorIntent.RIGHT;
  234.                         state = State.INDICATING;
  235.                     }
  236.                     else
  237.                     {
  238.                         state = State.SYNCHRONIZING;
  239.                     }
  240.                     aSync = lmrsData.getSynchronization().synchronize(perception, params, sli, carFollowingModel,
  241.                             desire.getRight(), LateralDirectionality.RIGHT, lmrsData);
  242.                     a = applyAcceleration(a, aSync, lmrsData, state);
  243.                 }
  244.                 else
  245.                 {
  246.                     lmrsData.synchronizationState = State.NONE;
  247.                 }
  248.                 params.setParameter(DLEFT, desire.getLeft());
  249.                 params.setParameter(DRIGHT, desire.getRight());
  250.             }
  251.             else
  252.             {
  253.                 params.setParameter(DLEFT, 0.0);
  254.                 params.setParameter(DRIGHT, 0.0);
  255.                 lmrsData.synchronizationState = State.NONE;
  256.             }

  257.             // cooperate
  258.             aSync = lmrsData.getCooperation().cooperate(perception, params, sli, carFollowingModel, LateralDirectionality.LEFT,
  259.                     desire);
  260.             a = applyAcceleration(a, aSync, lmrsData, State.COOPERATING);
  261.             aSync = lmrsData.getCooperation().cooperate(perception, params, sli, carFollowingModel, LateralDirectionality.RIGHT,
  262.                     desire);
  263.             a = applyAcceleration(a, aSync, lmrsData, State.COOPERATING);

  264.             // relaxation
  265.             exponentialHeadwayRelaxation(params);

  266.         }
  267.         lmrsData.finalizeStep();

  268.         SimpleOperationalPlan simplePlan = new SimpleOperationalPlan(a, params.getParameter(DT), initiatedLaneChange);
  269.         if (turnIndicatorStatus.isLeft())
  270.         {
  271.             simplePlan.setIndicatorIntentLeft();
  272.         }
  273.         else if (turnIndicatorStatus.isRight())
  274.         {
  275.             simplePlan.setIndicatorIntentRight();
  276.         }
  277.         return simplePlan;

  278.     }

  279.     /**
  280.      * Minimizes the acceleration and sets the synchronization state if applicable.
  281.      * @param a Acceleration; previous acceleration
  282.      * @param aNew Acceleration; new acceleration
  283.      * @param lmrsData LmrsData; lmrs data
  284.      * @param state State; synchronization state
  285.      * @return Acceleration; minimized acceleration
  286.      */
  287.     private static Acceleration applyAcceleration(final Acceleration a, final Acceleration aNew, final LmrsData lmrsData,
  288.             final State state)
  289.     {
  290.         if (a.si < aNew.si)
  291.         {
  292.             return a;
  293.         }
  294.         lmrsData.synchronizationState = state;
  295.         return aNew;
  296.     }

  297.     /**
  298.      * Sets the headway as a response to a new leader.
  299.      * @param params parameters
  300.      * @param leader leader
  301.      * @throws ParameterException if DLC is not present
  302.      */
  303.     private static void initHeadwayRelaxation(final Parameters params, final HeadwayGTU leader) throws ParameterException
  304.     {
  305.         Double dlc = leader.getParameters().getParameterOrNull(DLC);
  306.         if (dlc != null)
  307.         {
  308.             setDesiredHeadway(params, dlc);
  309.         }
  310.         // else could not be perceived
  311.     }

  312.     /**
  313.      * Updates the desired headway following an exponential shape approximated with fixed time step <tt>DT</tt>.
  314.      * @param params parameters
  315.      * @throws ParameterException in case of a parameter exception
  316.      */
  317.     private static void exponentialHeadwayRelaxation(final Parameters params) throws ParameterException
  318.     {
  319.         double ratio = params.getParameter(DT).si / params.getParameter(TAU).si;
  320.         params.setParameter(T,
  321.                 Duration.interpolate(params.getParameter(T), params.getParameter(TMAX), ratio <= 1.0 ? ratio : 1.0));
  322.     }

  323.     /**
  324.      * Determines lane change desire for the given RSU. Mandatory desire is deduced as the maximum of a set of mandatory
  325.      * incentives, while voluntary desires are added. Depending on the level of mandatory lane change desire, voluntary desire
  326.      * may be included partially. If both are positive or negative, voluntary desire is fully included. Otherwise, voluntary
  327.      * desire is less considered within the range dSync &lt; |mandatory| &lt; dCoop. The absolute value is used as large
  328.      * negative mandatory desire may also dominate voluntary desire.
  329.      * @param parameters parameters
  330.      * @param perception perception
  331.      * @param carFollowingModel car-following model
  332.      * @param mandatoryIncentives mandatory incentives
  333.      * @param voluntaryIncentives voluntary incentives
  334.      * @param desireMap map where calculated desires are stored in
  335.      * @return lane change desire for gtu
  336.      * @throws ParameterException if a parameter is not defined
  337.      * @throws GTUException if there is no mandatory incentive, the model requires at least one
  338.      * @throws OperationalPlanException perception exception
  339.      */
  340.     public static Desire getLaneChangeDesire(final Parameters parameters, final LanePerception perception,
  341.             final CarFollowingModel carFollowingModel, final LinkedHashSet<MandatoryIncentive> mandatoryIncentives,
  342.             final LinkedHashSet<VoluntaryIncentive> voluntaryIncentives,
  343.             final Map<Class<? extends Incentive>, Desire> desireMap)
  344.             throws ParameterException, GTUException, OperationalPlanException
  345.     {

  346.         double dSync = parameters.getParameter(DSYNC);
  347.         double dCoop = parameters.getParameter(DCOOP);

  348.         // Mandatory desire
  349.         double dLeftMandatory = 0.0;
  350.         double dRightMandatory = 0.0;
  351.         Desire mandatoryDesire = new Desire(dLeftMandatory, dRightMandatory);
  352.         for (MandatoryIncentive incentive : mandatoryIncentives)
  353.         {
  354.             Desire d = incentive.determineDesire(parameters, perception, carFollowingModel, mandatoryDesire);
  355.             desireMap.put(incentive.getClass(), d);
  356.             dLeftMandatory = Math.abs(d.getLeft()) > Math.abs(dLeftMandatory) ? d.getLeft() : dLeftMandatory;
  357.             dRightMandatory = Math.abs(d.getRight()) > Math.abs(dRightMandatory) ? d.getRight() : dRightMandatory;
  358.             mandatoryDesire = new Desire(dLeftMandatory, dRightMandatory);
  359.         }

  360.         // Voluntary desire
  361.         double dLeftVoluntary = 0;
  362.         double dRightVoluntary = 0;
  363.         Desire voluntaryDesire = new Desire(dLeftVoluntary, dRightVoluntary);
  364.         for (VoluntaryIncentive incentive : voluntaryIncentives)
  365.         {
  366.             Desire d = incentive.determineDesire(parameters, perception, carFollowingModel, mandatoryDesire, voluntaryDesire);
  367.             desireMap.put(incentive.getClass(), d);
  368.             dLeftVoluntary += d.getLeft();
  369.             dRightVoluntary += d.getRight();
  370.             voluntaryDesire = new Desire(dLeftVoluntary, dRightVoluntary);
  371.         }

  372.         // Total desire
  373.         double thetaLeft = 0;
  374.         double dLeftMandatoryAbs = Math.abs(dLeftMandatory);
  375.         double dRightMandatoryAbs = Math.abs(dRightMandatory);
  376.         if (dLeftMandatoryAbs <= dSync || dLeftMandatory * dLeftVoluntary >= 0)
  377.         {
  378.             // low mandatory desire, or same sign
  379.             thetaLeft = 1;
  380.         }
  381.         else if (dSync < dLeftMandatoryAbs && dLeftMandatoryAbs < dCoop && dLeftMandatory * dLeftVoluntary < 0)
  382.         {
  383.             // linear from 1 at dSync to 0 at dCoop
  384.             thetaLeft = (dCoop - dLeftMandatoryAbs) / (dCoop - dSync);
  385.         }
  386.         double thetaRight = 0;
  387.         if (dRightMandatoryAbs <= dSync || dRightMandatory * dRightVoluntary >= 0)
  388.         {
  389.             // low mandatory desire, or same sign
  390.             thetaRight = 1;
  391.         }
  392.         else if (dSync < dRightMandatoryAbs && dRightMandatoryAbs < dCoop && dRightMandatory * dRightVoluntary < 0)
  393.         {
  394.             // linear from 1 at dSync to 0 at dCoop
  395.             thetaRight = (dCoop - dRightMandatoryAbs) / (dCoop - dSync);
  396.         }
  397.         return new Desire(dLeftMandatory + thetaLeft * dLeftVoluntary, dRightMandatory + thetaRight * dRightVoluntary);

  398.     }

  399.     /**
  400.      * Determine whether a lane change is acceptable (gap, lane markings, etc.).
  401.      * @param perception perception
  402.      * @param params parameters
  403.      * @param sli speed limit info
  404.      * @param cfm car-following model
  405.      * @param desire level of lane change desire
  406.      * @param ownSpeed own speed
  407.      * @param ownAcceleration current car-following acceleration
  408.      * @param lat lateral direction for synchronization
  409.      * @param gapAcceptance gap-acceptance model
  410.      * @return whether a gap is acceptable
  411.      * @throws ParameterException if a parameter is not defined
  412.      * @throws OperationalPlanException perception exception
  413.      */
  414.     static boolean acceptLaneChange(final LanePerception perception, final Parameters params, final SpeedLimitInfo sli,
  415.             final CarFollowingModel cfm, final double desire, final Speed ownSpeed, final Acceleration ownAcceleration,
  416.             final LateralDirectionality lat, final GapAcceptance gapAcceptance)
  417.             throws ParameterException, OperationalPlanException
  418.     {

  419.         // beyond start distance
  420.         boolean beyond = Try.assign(() -> perception.getGtu().laneChangeAllowed(), "Cannot obtain GTU.");
  421.         if (!beyond)
  422.         {
  423.             return false;
  424.         }

  425.         // legal?
  426.         InfrastructurePerception infra = perception.getPerceptionCategory(InfrastructurePerception.class);
  427.         if (infra.getLegalLaneChangePossibility(RelativeLane.CURRENT, lat).si <= 0.0)
  428.         {
  429.             return false;
  430.         }

  431.         // other causes for deceleration
  432.         IntersectionPerception intersection = perception.getPerceptionCategoryOrNull(IntersectionPerception.class);
  433.         if (intersection != null)
  434.         {
  435.             // conflicts alongside?
  436.             if ((lat.isLeft() && intersection.isAlongsideConflictLeft())
  437.                     || (lat.isRight() && intersection.isAlongsideConflictRight()))
  438.             {
  439.                 return false;
  440.             }
  441.             if (quickIntersectionScan(params, sli, cfm, ownSpeed, lat, intersection).lt(params.getParameter(BCRIT).neg()))
  442.             {
  443.                 return false;
  444.             }
  445.         }

  446.         // safe regarding neighbors?
  447.         return gapAcceptance.acceptGap(perception, params, sli, cfm, desire, ownSpeed, ownAcceleration, lat);
  448.     }

  449.     /**
  450.      * Returns a quickly determined acceleration to consider on an adjacent lane, following from conflicts and traffic lights.
  451.      * @param params parameters
  452.      * @param sli speed limit info
  453.      * @param cfm car-following model
  454.      * @param ownSpeed own speed
  455.      * @param lat lateral direction for synchronization
  456.      * @param intersection intersection perception
  457.      * @return a quickly determined acceleration to consider on an adjacent lane, following from conflicts and traffic lights
  458.      * @throws ParameterException if a parameter is not defined
  459.      */
  460.     private static Acceleration quickIntersectionScan(final Parameters params, final SpeedLimitInfo sli,
  461.             final CarFollowingModel cfm, final Speed ownSpeed, final LateralDirectionality lat,
  462.             final IntersectionPerception intersection) throws ParameterException
  463.     {
  464.         Acceleration a = Acceleration.POSITIVE_INFINITY;
  465.         if (intersection != null)
  466.         {
  467.             RelativeLane lane = lat.isRight() ? RelativeLane.RIGHT : RelativeLane.LEFT;
  468.             Iterable<HeadwayConflict> iterable = intersection.getConflicts(lane);
  469.             if (iterable != null)
  470.             {
  471.                 Iterator<HeadwayConflict> conflicts = iterable.iterator();
  472.                 if (conflicts.hasNext())
  473.                 {
  474.                     a = Acceleration.min(a, CarFollowingUtil.followSingleLeader(cfm, params, ownSpeed, sli,
  475.                             conflicts.next().getDistance(), Speed.ZERO));
  476.                 }
  477.                 Iterator<HeadwayTrafficLight> trafficLights = intersection.getTrafficLights(lane).iterator();
  478.                 if (trafficLights.hasNext())
  479.                 {
  480.                     HeadwayTrafficLight trafficLight = trafficLights.next();
  481.                     if (trafficLight.getTrafficLightColor().isRedOrYellow())
  482.                     {
  483.                         a = Acceleration.min(a, CarFollowingUtil.followSingleLeader(cfm, params, ownSpeed, sli,
  484.                                 trafficLight.getDistance(), Speed.ZERO));
  485.                     }
  486.                 }
  487.             }
  488.         }
  489.         return a;
  490.     }

  491.     /**
  492.      * Sets value for T depending on level of lane change desire.
  493.      * @param params parameters
  494.      * @param desire lane change desire
  495.      * @throws ParameterException if T, TMIN or TMAX is not in the parameters
  496.      */
  497.     static void setDesiredHeadway(final Parameters params, final double desire) throws ParameterException
  498.     {
  499.         double limitedDesire = desire < 0 ? 0 : desire > 1 ? 1 : desire;
  500.         double tDes = limitedDesire * params.getParameter(TMIN).si + (1 - limitedDesire) * params.getParameter(TMAX).si;
  501.         double t = params.getParameter(T).si;
  502.         params.setParameterResettable(T, Duration.createSI(tDes < t ? tDes : t));
  503.     }

  504.     /**
  505.      * Resets value for T depending on level of lane change desire.
  506.      * @param params parameters
  507.      * @throws ParameterException if T is not in the parameters
  508.      */
  509.     static void resetDesiredHeadway(final Parameters params) throws ParameterException
  510.     {
  511.         params.resetParameter(T);
  512.     }

  513.     /**
  514.      * Determine acceleration from car-following with desire-adjusted headway.
  515.      * @param distance distance from follower to leader
  516.      * @param followerSpeed speed of follower
  517.      * @param leaderSpeed speed of leader
  518.      * @param desire level of lane change desire
  519.      * @param params parameters
  520.      * @param sli speed limit info
  521.      * @param cfm car-following model
  522.      * @return acceleration from car-following
  523.      * @throws ParameterException if a parameter is not defined
  524.      */
  525.     public static Acceleration singleAcceleration(final Length distance, final Speed followerSpeed, final Speed leaderSpeed,
  526.             final double desire, final Parameters params, final SpeedLimitInfo sli, final CarFollowingModel cfm)
  527.             throws ParameterException
  528.     {
  529.         // set T
  530.         setDesiredHeadway(params, desire);
  531.         // calculate acceleration
  532.         Acceleration a = CarFollowingUtil.followSingleLeader(cfm, params, followerSpeed, sli, distance, leaderSpeed);
  533.         // reset T
  534.         resetDesiredHeadway(params);
  535.         return a;
  536.     }

  537. }