package org.opentrafficsim.ahfe; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import java.util.SortedSet; import org.djunits.value.vdouble.scalar.Duration; import org.djunits.value.vdouble.scalar.Length; import org.djunits.value.vdouble.scalar.Time; import org.opentrafficsim.base.TimeStampedObject; import org.opentrafficsim.base.parameters.ParameterException; import org.opentrafficsim.base.parameters.ParameterTypeDuration; import org.opentrafficsim.base.parameters.ParameterTypes; import org.opentrafficsim.base.parameters.Parameters; import org.opentrafficsim.core.gtu.GTUException; import org.opentrafficsim.core.gtu.perception.PerceptionException; import org.opentrafficsim.core.network.LateralDirectionality; import org.opentrafficsim.core.network.NetworkException; import org.opentrafficsim.road.gtu.lane.LaneBasedGTU; import org.opentrafficsim.road.gtu.lane.perception.LanePerception; import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable; import org.opentrafficsim.road.gtu.lane.perception.RelativeLane; import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.DirectNeighborsPerception; import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.HeadwayGtuType; import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.NeighborsPerception; import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTU; import nl.tudelft.simulation.dsol.SimRuntimeException; /** *

* Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See OpenTrafficSim License. *

* @version $Revision$, $LastChangedDate$, by $Author$, initial version 17 feb. 2017
* @author Alexander Verbraeck * @author Peter Knoppers * @author Wouter Schakel */ @Deprecated public abstract class AbstractDelayedNeighborsPerception extends AbstractDelayedPerceptionCategory implements NeighborsPerception { /** */ private static final long serialVersionUID = 20170217L; /** Reaction time parameter type. */ protected static final ParameterTypeDuration TR = ParameterTypes.TR; /** Time step parameter type. */ protected static final ParameterTypeDuration DT = ParameterTypes.DT; /** First update time. */ private Time initialTime = null; /** Wrapped direct perception. */ private final DirectNeighborsPerception direct; /** Reaction time. */ private Duration reactionTime = null; /** Time step of planner. */ private Duration plannerTimeStep = null; /** Remainder between reaction time and planner time step. */ private Duration remainder = null; /** Info type id base for first leaders. */ public static final String FIRSTLEADERS = "firstLeaders"; /** Info type id base for first followers. */ public static final String FIRSTFOLLOWERS = "firstFollower"; /** Info type id base for gtu alongside. */ public static final String GTUALONGSIDE = "gtuAlongside"; /** Info type id base for leaders. */ public static final String LEADERS = "leaders"; /** Info type id base for followers. */ public static final String FOLLOWERS = "followers"; /** Info type id for cross-section. */ public static final NeighborsInfoType> CROSSSECTION = new NeighborsInfoType<>("cross-section"); /** Id for odometer info type. */ public static final NeighborsInfoType ODOMETER = new NeighborsInfoType<>("odometer"); /** Override for left lane change. */ private boolean gtuAlongsideLeftOverride = false; /** Override for right lane change. */ private boolean gtuAlongsideRightOverride = false; /** * Constructor. * @param perception LanePerception; perception */ public AbstractDelayedNeighborsPerception(final LanePerception perception) { super(perception); this.direct = new DirectNeighborsPerception(perception, HeadwayGtuType.COPY); } /** {@inheritDoc} */ @Override public final void updateAll() throws GTUException, NetworkException, ParameterException { if (this.remainder == null) { try { // TODO The reaction time may differ between observed objects and vary over time Parameters params = getPerception().getGtu().getParameters(); this.reactionTime = params.getParameter(TR); this.plannerTimeStep = params.getParameter(DT); double rem; if (this.reactionTime.eq0()) { rem = 0; } else if (this.reactionTime.gt(this.plannerTimeStep)) { rem = this.reactionTime.si % this.plannerTimeStep.si; } else { rem = this.plannerTimeStep.si - this.reactionTime.si; } this.remainder = Duration.instantiateSI(rem); } catch (ParameterException | GTUException exception) { throw new RuntimeException("Exception while setting up delayed neighors perception.", exception); } } // direct perception in first few time steps; build up history Time now = getPerception().getGtu().getSimulator().getSimulatorTime(); if (this.initialTime == null) { this.initialTime = now; } if (now.minus(this.initialTime).le(this.reactionTime)) { updateAllDelayed(); return; } if (this.remainder.eq0()) { // reaction time is multiple of time step, just do it now updateAllDelayed(); } else { // schedule actual update slightly in the future: this will be the snapshot for a future time step Time scheduledTime = now.plus(this.remainder); try { getPerception().getGtu().getSimulator().scheduleEventAbs(scheduledTime, this, this, "updateAllDelayed", null); } catch (SimRuntimeException exception) { throw new RuntimeException("Scheduling perception update in the past.", exception); } } /* * During the reaction time, an instantaneous lane change by a neighbor may be performed, which may cause an * unreasonable lane change of the subject vehicle if it is not considered. Therefore, the 'gtuAlongSide' information is * amended with a current snapshot of the surroundings. If the current first leaders/followers contains a GTU that the * delayed leaders/followers do not contain, and that is within 50m, 'gtuAlongSide' is overruled with 'true', preventing * a lane change. */ if (getPerception().getLaneStructure().getExtendedCrossSection().contains(RelativeLane.LEFT)) { this.gtuAlongsideLeftOverride = newFirstLeaderOrFollower(getFollowers(RelativeLane.LEFT), this.direct.getFirstFollowers(LateralDirectionality.LEFT)) || newFirstLeaderOrFollower(getLeaders(RelativeLane.LEFT), this.direct.getFirstLeaders(LateralDirectionality.LEFT)) || this.direct.isGtuAlongside(LateralDirectionality.LEFT); } if (getPerception().getLaneStructure().getExtendedCrossSection().contains(RelativeLane.RIGHT)) { this.gtuAlongsideRightOverride = newFirstLeaderOrFollower(getFollowers(RelativeLane.RIGHT), this.direct.getFirstFollowers(LateralDirectionality.RIGHT)) || newFirstLeaderOrFollower(getLeaders(RelativeLane.RIGHT), this.direct.getFirstLeaders(LateralDirectionality.RIGHT)) || this.direct.isGtuAlongside(LateralDirectionality.RIGHT); } } /** * Returns whether there is a gtu in the current set that is not present in the delayed set. * @param delayedSet Iterable<? extends HeadwayGTU>; delayed set * @param currentSet Set<? extends HeadwayGTU>; current set * @return whether there is a gtu in the current set that is not present in the delayed set */ private boolean newFirstLeaderOrFollower(final Iterable delayedSet, final Set currentSet) { Set set = new LinkedHashSet<>(); for (HeadwayGTU gtu : delayedSet) { set.add(gtu.getId()); } for (HeadwayGTU gtu : currentSet) { if (!set.contains(gtu.getId()) && gtu.getDistance().si < 50) { return true; } } return false; } /** * Returns whether to override the gtu alongside boolean as true. * @param lat LateralDirectionality; lateral direction * @return whether to override the gtu alongside boolean as true */ public final boolean isGtuAlongsideOverride(final LateralDirectionality lat) { return lat.isLeft() ? this.gtuAlongsideLeftOverride : this.gtuAlongsideRightOverride; } /** * Performs actual update. * @throws ParameterException if parameter is not present or is given a wrong value * @throws NetworkException on error in the network * @throws GTUException if not initialized */ // TODO private when DSOL allows protected void updateAllDelayed() throws GTUException, NetworkException, ParameterException { try { getGtu().getReferencePosition(); } catch (GTUException exception) { // GTU was destroyed return; } this.direct.updateAll(); // below code is a copy of the updateAll() method in the direct perception TODO structure better setInfo(CROSSSECTION, new TimeStampedObject<>(getPerception().getLaneStructure().getExtendedCrossSection(), getTimestamp())); setInfo(ODOMETER, new TimeStampedObject<>(getGtu().getOdometer(), getTimestamp())); } /** * Returns the cross-section on which the most recent observed neighbors were determined. * @return cross-section on which the most recent observed neighbors were determined */ public final SortedSet getDelayedCrossSection() { try { return getInfo(CROSSSECTION).getObject(); } catch (PerceptionException exception) { throw new RuntimeException("Crosssection was not perceived.", exception); } } /** * Delayed information about the type of the neighbors.
* @param data type of info */ public static final class NeighborsInfoType extends DelayedInfoType { /** Map of id's and lane info types. */ private static final Map> LANEINFOTYPES = new LinkedHashMap<>(); /** * Construct new info. * @param id String; id */ public NeighborsInfoType(final String id) { super(id, TR); } /** * Returns a (cached) info type for a sorted set of GTU's. * @param id String; id * @return info type */ @SuppressWarnings("unchecked") public static NeighborsInfoType> getSortedSetType(final String id) { if (!LANEINFOTYPES.containsKey(id)) { LANEINFOTYPES.put(id, new NeighborsInfoType>(id)); } return (NeighborsInfoType>) LANEINFOTYPES.get(id); } /** * Returns a (cached) info type for a sorted set of GTU's. * @param id String; id * @return info type */ @SuppressWarnings("unchecked") public static NeighborsInfoType> getIterableType(final String id) { if (!LANEINFOTYPES.containsKey(id)) { LANEINFOTYPES.put(id, new NeighborsInfoType>(id)); } return (NeighborsInfoType>) LANEINFOTYPES.get(id); } /** * Returns a (cached) info type for a sorted set of GTU's. * @param id String; id * @return info type */ @SuppressWarnings("unchecked") public static NeighborsInfoType getBooleanType(final String id) { if (!LANEINFOTYPES.containsKey(id)) { LANEINFOTYPES.put(id, new NeighborsInfoType>(id)); } return (NeighborsInfoType) LANEINFOTYPES.get(id); } /** {@inheritDoc} */ @Override public String toString() { return "NeighborsInfoType []"; } } }