CFRoomChecker.java

  1. package org.opentrafficsim.road.gtu.generator;

  2. import java.util.LinkedHashSet;
  3. import java.util.Set;
  4. import java.util.SortedSet;

  5. import org.djunits.value.vdouble.scalar.Duration;
  6. import org.djunits.value.vdouble.scalar.Length;
  7. import org.djunits.value.vdouble.scalar.Speed;
  8. import org.djutils.exceptions.Throw;
  9. import org.djutils.immutablecollections.ImmutableMap;
  10. import org.opentrafficsim.core.gtu.GTUDirectionality;
  11. import org.opentrafficsim.core.gtu.GTUException;
  12. import org.opentrafficsim.core.network.NetworkException;
  13. import org.opentrafficsim.road.gtu.generator.LaneBasedGTUGenerator.Placement;
  14. import org.opentrafficsim.road.gtu.generator.LaneBasedGTUGenerator.RoomChecker;
  15. import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGTUCharacteristics;
  16. import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTU;
  17. import org.opentrafficsim.road.network.lane.DirectedLanePosition;
  18. import org.opentrafficsim.road.network.lane.Lane;

  19. /**
  20.  * This class places GTU's behind the leader at the desired headway (i.e. CF, car-following) and the speed of the leader, but no
  21.  * further than the GTU could have traveled at the desired speed during the time since the desired arrival. With multiple
  22.  * leaders, the leader that causes the most upstream following position is used.
  23.  * <p>
  24.  * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  25.  * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
  26.  * <p>
  27.  * @version $Revision$, $LastChangedDate$, by $Author$, initial version 12 jan. 2018 <br>
  28.  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  29.  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  30.  * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
  31.  */
  32. public class CFRoomChecker implements RoomChecker
  33. {

  34.     /** {@inheritDoc} */
  35.     @Override
  36.     public Placement canPlace(final SortedSet<HeadwayGTU> leaders, final LaneBasedGTUCharacteristics characteristics,
  37.             final Duration since, final Set<DirectedLanePosition> initialPosition) throws NetworkException, GTUException
  38.     {
  39.         Speed speedLimit = null;
  40.         for (DirectedLanePosition lane : initialPosition)
  41.         {
  42.             try
  43.             {
  44.                 Speed limit = lane.getLane().getSpeedLimit(characteristics.getGTUType());
  45.                 if (speedLimit == null || limit.gt(speedLimit))
  46.                 {
  47.                     speedLimit = limit;
  48.                 }
  49.             }
  50.             catch (NetworkException exception)
  51.             {
  52.                 // ignore
  53.             }
  54.         }
  55.         Throw.when(speedLimit == null, IllegalStateException.class, "No speed limit could be determined for GTUType %s.",
  56.                 characteristics.getGTUType());
  57.         Speed desiredSpeed = characteristics.getStrategicalPlannerFactory().peekDesiredSpeed(characteristics.getGTUType(),
  58.                 speedLimit, characteristics.getMaximumSpeed());
  59.         desiredSpeed = desiredSpeed != null ? desiredSpeed : speedLimit; // speed limit def.
  60.         if (leaders.isEmpty())
  61.         {
  62.             // no leaders: free
  63.             return new Placement(desiredSpeed, initialPosition);
  64.         }
  65.         Length desiredHeadway =
  66.                 characteristics.getStrategicalPlannerFactory().peekDesiredHeadway(characteristics.getGTUType(), desiredSpeed);
  67.         desiredHeadway = desiredHeadway != null ? desiredHeadway : desiredSpeed.times(Duration.instantiateSI(1.0)); // 1s def.
  68.         // loop leaders and determine most downstream location that would be ok
  69.         Length move = Length.POSITIVE_INFINITY;
  70.         Speed generationSpeed = desiredSpeed;
  71.         for (HeadwayGTU leader : leaders)
  72.         {
  73.             Speed speed = Speed.min(desiredSpeed, leader.getSpeed());
  74.             Length headway =
  75.                     characteristics.getStrategicalPlannerFactory().peekDesiredHeadway(characteristics.getGTUType(), speed);
  76.             headway = headway != null ? headway : speed.times(Duration.instantiateSI(1.0)); // 1s def.
  77.             double f = this.headwayFactor(desiredSpeed, desiredHeadway, speed, headway, leader.getLength());
  78.             headway = headway.times(f);
  79.             if (leader.getDistance().lt(headway))
  80.             {
  81.                 // not enough space to this leader
  82.                 return Placement.NO;
  83.             }
  84.             Length moveToLeader = leader.getDistance().minus(headway);
  85.             if (moveToLeader.lt(move))
  86.             {
  87.                 move = moveToLeader;
  88.                 generationSpeed = speed;
  89.             }
  90.         }
  91.         move = Length.min(move, since.times(generationSpeed)); // max distance the GTU would have moved until now
  92.         // move this distance
  93.         Set<DirectedLanePosition> generationPosition;
  94.         if (move.eq0() || initialPosition.size() != 1)
  95.         {
  96.             generationPosition = initialPosition;
  97.         }
  98.         else
  99.         {
  100.             generationPosition = new LinkedHashSet<>();
  101.             for (DirectedLanePosition dirPos : initialPosition)
  102.             {
  103.                 Lane lane = dirPos.getLane();
  104.                 GTUDirectionality dir = dirPos.getGtuDirection();
  105.                 Length position = dirPos.getPosition();
  106.                 Length canMove = dir.isPlus() ? lane.getLength().minus(position) : position;
  107.                 while (canMove.lt(move))
  108.                 {
  109.                     ImmutableMap<Lane, GTUDirectionality> down = lane.downstreamLanes(dir, characteristics.getGTUType());
  110.                     if (down.size() != 1)
  111.                     {
  112.                         // split or dead-end, fall back to original position
  113.                         return new Placement(generationSpeed, initialPosition);
  114.                     }
  115.                     else
  116.                     {
  117.                         move = move.minus(canMove);
  118.                         lane = down.keySet().iterator().next();
  119.                         dir = down.get(lane);
  120.                         position = dir.isPlus() ? Length.ZERO : lane.getLength();
  121.                         canMove = lane.getLength();
  122.                     }
  123.                 }
  124.                 position = dir.isPlus() ? position.plus(move) : position.minus(move);
  125.                 generationPosition.add(new DirectedLanePosition(lane, position, dir));
  126.             }
  127.         }
  128.         return new Placement(generationSpeed, generationPosition);
  129.     }

  130.     /**
  131.      * Returns a situation dependent headway factor to deal with spillback.
  132.      * @param desiredSpeed Speed; desired speed
  133.      * @param desiredHeadway Length; desired headway at desired speed
  134.      * @param generationSpeed Speed; generation speed
  135.      * @param generationHeadway Length; desired headway at generation speed
  136.      * @param leaderLength Length; length of the leader
  137.      * @return situation dependent headway factor to deal with spillback
  138.      */
  139.     protected double headwayFactor(final Speed desiredSpeed, final Length desiredHeadway, final Speed generationSpeed,
  140.             final Length generationHeadway, final Length leaderLength)
  141.     {
  142.         return 1.0;
  143.     }

  144. }