AbstractDelayedNeighborsPerception.java

  1. package org.opentrafficsim.road.gtu.lane.perception.categories;

  2. import java.util.HashMap;
  3. import java.util.HashSet;
  4. import java.util.Map;
  5. import java.util.Set;
  6. import java.util.SortedSet;

  7. import org.djunits.value.vdouble.scalar.Duration;
  8. import org.djunits.value.vdouble.scalar.Length;
  9. import org.djunits.value.vdouble.scalar.Time;
  10. import org.opentrafficsim.base.TimeStampedObject;
  11. import org.opentrafficsim.base.parameters.ParameterException;
  12. import org.opentrafficsim.base.parameters.ParameterTypeDuration;
  13. import org.opentrafficsim.base.parameters.ParameterTypes;
  14. import org.opentrafficsim.base.parameters.Parameters;
  15. import org.opentrafficsim.core.gtu.GTUException;
  16. import org.opentrafficsim.core.gtu.perception.PerceptionException;
  17. import org.opentrafficsim.core.network.LateralDirectionality;
  18. import org.opentrafficsim.core.network.NetworkException;
  19. import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
  20. import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
  21. import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable;
  22. import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
  23. import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTU;

  24. import nl.tudelft.simulation.dsol.SimRuntimeException;

  25. /**
  26.  * <p>
  27.  * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  28.  * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
  29.  * <p>
  30.  * @version $Revision$, $LastChangedDate$, by $Author$, initial version 17 feb. 2017 <br>
  31.  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  32.  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  33.  * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
  34.  */
  35. public abstract class AbstractDelayedNeighborsPerception extends AbstractDelayedPerceptionCategory
  36.         implements NeighborsPerception
  37. {

  38.     /** */
  39.     private static final long serialVersionUID = 20170217L;

  40.     /** Reaction time parameter type. */
  41.     protected static final ParameterTypeDuration TR = ParameterTypes.TR;

  42.     /** Time step parameter type. */
  43.     protected static final ParameterTypeDuration DT = ParameterTypes.DT;

  44.     /** First update time. */
  45.     private Time initialTime = null;

  46.     /** Wrapped direct perception. */
  47.     private final DirectNeighborsPerception direct;

  48.     /** Reaction time. */
  49.     private Duration reactionTime = null;

  50.     /** Time step of planner. */
  51.     private Duration plannerTimeStep = null;

  52.     /** Remainder between reaction time and planner time step. */
  53.     private Duration remainder = null;

  54.     /** Info type id base for first leaders. */
  55.     public static final String FIRSTLEADERS = "firstLeaders";

  56.     /** Info type id base for first followers. */
  57.     public static final String FIRSTFOLLOWERS = "firstFollower";

  58.     /** Info type id base for gtu alongside. */
  59.     public static final String GTUALONGSIDE = "gtuAlongside";

  60.     /** Info type id base for leaders. */
  61.     public static final String LEADERS = "leaders";

  62.     /** Info type id base for followers. */
  63.     public static final String FOLLOWERS = "followers";

  64.     /** Info type id for cross-section. */
  65.     public static final NeighborsInfoType<SortedSet<RelativeLane>> CROSSSECTION = new NeighborsInfoType<>("cross-section");

  66.     /** Id for odometer info type. */
  67.     public static final NeighborsInfoType<Length> ODOMETER = new NeighborsInfoType<>("odometer");

  68.     /** Override for left lane change. */
  69.     private boolean gtuAlongsideLeftOverride = false;

  70.     /** Override for right lane change. */
  71.     private boolean gtuAlongsideRightOverride = false;

  72.     /**
  73.      * Constructor.
  74.      * @param perception perception
  75.      */
  76.     public AbstractDelayedNeighborsPerception(final LanePerception perception)
  77.     {
  78.         super(perception);
  79.         this.direct = new DirectNeighborsPerception(perception, HeadwayGtuType.COPY);
  80.     }

  81.     /** {@inheritDoc} */
  82.     @Override
  83.     public final void updateAll() throws GTUException, NetworkException, ParameterException
  84.     {

  85.         if (this.remainder == null)
  86.         {
  87.             try
  88.             {
  89.                 // TODO The reaction time may differ between observed objects and vary over time
  90.                 Parameters params = getPerception().getGtu().getParameters();
  91.                 this.reactionTime = params.getParameter(TR);
  92.                 this.plannerTimeStep = params.getParameter(DT);
  93.                 double rem;
  94.                 if (this.reactionTime.eq0())
  95.                 {
  96.                     rem = 0;
  97.                 }
  98.                 else if (this.reactionTime.gt(this.plannerTimeStep))
  99.                 {
  100.                     rem = this.reactionTime.si % this.plannerTimeStep.si;
  101.                 }
  102.                 else
  103.                 {
  104.                     rem = this.plannerTimeStep.si - this.reactionTime.si;
  105.                 }
  106.                 this.remainder = Duration.createSI(rem);
  107.             }
  108.             catch (ParameterException | GTUException exception)
  109.             {
  110.                 throw new RuntimeException("Exception while setting up delayed neighors perception.", exception);
  111.             }
  112.         }

  113.         // direct perception in first few time steps; build up history
  114.         Time now = getPerception().getGtu().getSimulator().getSimulatorTime();
  115.         if (this.initialTime == null)
  116.         {
  117.             this.initialTime = now;
  118.         }
  119.         if (now.minus(this.initialTime).le(this.reactionTime))
  120.         {
  121.             updateAllDelayed();
  122.             return;
  123.         }

  124.         if (this.remainder.eq0())
  125.         {
  126.             // reaction time is multiple of time step, just do it now
  127.             updateAllDelayed();
  128.         }
  129.         else
  130.         {
  131.             // schedule actual update slightly in the future: this will be the snapshot for a future time step
  132.             Time scheduledTime = now.plus(this.remainder);
  133.             try
  134.             {
  135.                 getPerception().getGtu().getSimulator().scheduleEventAbs(scheduledTime, this, this, "updateAllDelayed", null);
  136.             }
  137.             catch (SimRuntimeException exception)
  138.             {
  139.                 throw new RuntimeException("Scheduling perception update in the past.", exception);
  140.             }
  141.         }

  142.         /*
  143.          * During the reaction time, an instantaneous lane change by a neighbor may be performed, which may cause an
  144.          * unreasonable lane change of the subject vehicle if it is not considered. Therefore, the 'gtuAlongSide' information is
  145.          * amended with a current snapshot of the surroundings. If the current first leaders/followers contains a GTU that the
  146.          * delayed leaders/followers do not contain, and that is within 50m, 'gtuAlongSide' is overruled with 'true', preventing
  147.          * a lane change.
  148.          */
  149.         if (getPerception().getLaneStructure().getExtendedCrossSection().contains(RelativeLane.LEFT))
  150.         {
  151.             this.direct.updateFirstFollowers(LateralDirectionality.LEFT);
  152.             this.direct.updateFirstLeaders(LateralDirectionality.LEFT);
  153.             this.direct.updateGtuAlongside(LateralDirectionality.LEFT);
  154.             this.gtuAlongsideLeftOverride = newFirstLeaderOrFollower(getFollowers(RelativeLane.LEFT),
  155.                     this.direct.getFirstFollowers(LateralDirectionality.LEFT))
  156.                     || newFirstLeaderOrFollower(getLeaders(RelativeLane.LEFT),
  157.                             this.direct.getFirstLeaders(LateralDirectionality.LEFT))
  158.                     || this.direct.isGtuAlongside(LateralDirectionality.LEFT);
  159.         }
  160.         if (getPerception().getLaneStructure().getExtendedCrossSection().contains(RelativeLane.RIGHT))
  161.         {
  162.             this.direct.updateFirstFollowers(LateralDirectionality.RIGHT);
  163.             this.direct.updateFirstLeaders(LateralDirectionality.RIGHT);
  164.             this.direct.updateGtuAlongside(LateralDirectionality.RIGHT);
  165.             this.gtuAlongsideRightOverride = newFirstLeaderOrFollower(getFollowers(RelativeLane.RIGHT),
  166.                     this.direct.getFirstFollowers(LateralDirectionality.RIGHT))
  167.                     || newFirstLeaderOrFollower(getLeaders(RelativeLane.RIGHT),
  168.                             this.direct.getFirstLeaders(LateralDirectionality.RIGHT))
  169.                     || this.direct.isGtuAlongside(LateralDirectionality.RIGHT);
  170.         }

  171.     }

  172.     /**
  173.      * Returns whether there is a gtu in the current set that is not present in the delayed set.
  174.      * @param delayedSet delayed set
  175.      * @param currentSet current set
  176.      * @return whether there is a gtu in the current set that is not present in the delayed set
  177.      */
  178.     private boolean newFirstLeaderOrFollower(final Iterable<? extends HeadwayGTU> delayedSet,
  179.             final Set<? extends HeadwayGTU> currentSet)
  180.     {
  181.         Set<String> set = new HashSet<>();
  182.         for (HeadwayGTU gtu : delayedSet)
  183.         {
  184.             set.add(gtu.getId());
  185.         }
  186.         for (HeadwayGTU gtu : currentSet)
  187.         {
  188.             if (!set.contains(gtu.getId()) && gtu.getDistance().si < 50)
  189.             {
  190.                 return true;
  191.             }
  192.         }
  193.         return false;
  194.     }

  195.     /**
  196.      * Returns whether to override the gtu alongside boolean as true.
  197.      * @param lat lateral direction
  198.      * @return whether to override the gtu alongside boolean as true
  199.      */
  200.     public final boolean isGtuAlongsideOverride(final LateralDirectionality lat)
  201.     {
  202.         return lat.isLeft() ? this.gtuAlongsideLeftOverride : this.gtuAlongsideRightOverride;
  203.     }

  204.     /**
  205.      * Performs actual update.
  206.      * @throws ParameterException if parameter is not present or is given a wrong value
  207.      * @throws NetworkException on error in the network
  208.      * @throws GTUException if not initialized
  209.      */
  210.     // TODO private when DSOL allows
  211.     protected void updateAllDelayed() throws GTUException, NetworkException, ParameterException
  212.     {

  213.         try
  214.         {
  215.             getGtu().getReferencePosition();
  216.         }
  217.         catch (@SuppressWarnings("unused") GTUException exception)
  218.         {
  219.             // GTU was destroyed
  220.             return;
  221.         }

  222.         this.direct.updateAll();
  223.         // below code is a copy of the updateAll() method in the direct perception TODO structure better
  224.         if (getPerception().getLaneStructure().getExtendedCrossSection().contains(RelativeLane.LEFT))
  225.         {
  226.             updateFirstLeaders(LateralDirectionality.LEFT);
  227.             updateFirstFollowers(LateralDirectionality.LEFT);
  228.             updateGtuAlongside(LateralDirectionality.LEFT);
  229.         }
  230.         if (getPerception().getLaneStructure().getExtendedCrossSection().contains(RelativeLane.RIGHT))
  231.         {
  232.             updateFirstLeaders(LateralDirectionality.RIGHT);
  233.             updateFirstFollowers(LateralDirectionality.RIGHT);
  234.             updateGtuAlongside(LateralDirectionality.RIGHT);
  235.         }
  236.         for (RelativeLane lane : getPerception().getLaneStructure().getExtendedCrossSection())
  237.         {
  238.             updateLeaders(lane);
  239.             updateFollowers(lane);
  240.         }
  241.         setInfo(CROSSSECTION, new TimeStampedObject<>(getPerception().getLaneStructure().getExtendedCrossSection(), getTimestamp()));
  242.         setInfo(ODOMETER, new TimeStampedObject<>(getGtu().getOdometer(), getTimestamp()));
  243.     }

  244.     /** {@inheritDoc} */
  245.     @Override
  246.     public final void updateFirstLeaders(final LateralDirectionality lat)
  247.             throws ParameterException, GTUException, NetworkException
  248.     {
  249.         setInfo(NeighborsInfoType.getSortedSetType(FIRSTLEADERS), new RelativeLane(lat, 1),
  250.                 this.direct.getTimeStampedFirstLeaders(lat));
  251.     }

  252.     /** {@inheritDoc} */
  253.     @Override
  254.     public final void updateFirstFollowers(final LateralDirectionality lat)
  255.             throws GTUException, ParameterException, NetworkException
  256.     {
  257.         setInfo(NeighborsInfoType.getSortedSetType(FIRSTFOLLOWERS), new RelativeLane(lat, 1),
  258.                 this.direct.getTimeStampedFirstFollowers(lat));
  259.     }

  260.     /** {@inheritDoc} */
  261.     @Override
  262.     public final void updateGtuAlongside(final LateralDirectionality lat) throws GTUException, ParameterException
  263.     {
  264.         setInfo(NeighborsInfoType.getBooleanType(GTUALONGSIDE), new RelativeLane(lat, 1),
  265.                 this.direct.isGtuAlongsideTimeStamped(lat));
  266.     }

  267.     /** {@inheritDoc} */
  268.     @Override
  269.     public final void updateLeaders(final RelativeLane lane) throws ParameterException, GTUException, NetworkException
  270.     {
  271.         setInfo(NeighborsInfoType.getIterableType(LEADERS), lane, this.direct.getTimeStampedLeaders(lane));
  272.     }

  273.     /** {@inheritDoc} */
  274.     @Override
  275.     public final void updateFollowers(final RelativeLane lane) throws GTUException, NetworkException, ParameterException
  276.     {
  277.         setInfo(NeighborsInfoType.getIterableType(FOLLOWERS), lane, this.direct.getTimeStampedFollowers(lane));
  278.     }

  279.     /**
  280.      * Returns the cross-section on which the most recent observed neighbors were determined.
  281.      * @return cross-section on which the most recent observed neighbors were determined
  282.      */
  283.     public final SortedSet<RelativeLane> getDelayedCrossSection()
  284.     {
  285.         try
  286.         {
  287.             return getInfo(CROSSSECTION).getObject();
  288.         }
  289.         catch (PerceptionException exception)
  290.         {
  291.             throw new RuntimeException("Crosssection was not perceived.", exception);
  292.         }
  293.     }

  294.     /**
  295.      * Delayed information about the type of the neighbors. <br>
  296.      * @param <T> data type of info
  297.      */
  298.     public static final class NeighborsInfoType<T> extends DelayedInfoType<T>
  299.     {

  300.         /** Map of id's and lane info types. */
  301.         private static final Map<String, NeighborsInfoType<?>> LANEINFOTYPES = new HashMap<>();

  302.         /**
  303.          * Construct new info.
  304.          * @param id id
  305.          */
  306.         public NeighborsInfoType(final String id)
  307.         {
  308.             super(id, TR);
  309.         }

  310.         /**
  311.          * Returns a (cached) info type for a sorted set of GTU's.
  312.          * @param id id
  313.          * @return info type
  314.          */
  315.         @SuppressWarnings("unchecked")
  316.         public static NeighborsInfoType<SortedSet<HeadwayGTU>> getSortedSetType(final String id)
  317.         {
  318.             if (!LANEINFOTYPES.containsKey(id))
  319.             {
  320.                 LANEINFOTYPES.put(id, new NeighborsInfoType<SortedSet<HeadwayGTU>>(id));
  321.             }
  322.             return (NeighborsInfoType<SortedSet<HeadwayGTU>>) LANEINFOTYPES.get(id);
  323.         }

  324.         /**
  325.          * Returns a (cached) info type for a sorted set of GTU's.
  326.          * @param id id
  327.          * @return info type
  328.          */
  329.         @SuppressWarnings("unchecked")
  330.         public static NeighborsInfoType<PerceptionCollectable<HeadwayGTU, LaneBasedGTU>> getIterableType(final String id)
  331.         {
  332.             if (!LANEINFOTYPES.containsKey(id))
  333.             {
  334.                 LANEINFOTYPES.put(id, new NeighborsInfoType<SortedSet<HeadwayGTU>>(id));
  335.             }
  336.             return (NeighborsInfoType<PerceptionCollectable<HeadwayGTU, LaneBasedGTU>>) LANEINFOTYPES.get(id);
  337.         }

  338.         /**
  339.          * Returns a (cached) info type for a sorted set of GTU's.
  340.          * @param id id
  341.          * @return info type
  342.          */
  343.         @SuppressWarnings("unchecked")
  344.         public static NeighborsInfoType<Boolean> getBooleanType(final String id)
  345.         {
  346.             if (!LANEINFOTYPES.containsKey(id))
  347.             {
  348.                 LANEINFOTYPES.put(id, new NeighborsInfoType<SortedSet<HeadwayGTU>>(id));
  349.             }
  350.             return (NeighborsInfoType<Boolean>) LANEINFOTYPES.get(id);
  351.         }

  352.         /** {@inheritDoc} */
  353.         @Override
  354.         public String toString()
  355.         {
  356.             return "NeighborsInfoType []";
  357.         }

  358.     }

  359. }