View Javadoc
1   package org.opentrafficsim.road.gtu.generator;
2   
3   import java.util.Set;
4   import java.util.SortedSet;
5   
6   import org.djunits.value.vdouble.scalar.Duration;
7   import org.djunits.value.vdouble.scalar.Length;
8   import org.djunits.value.vdouble.scalar.Speed;
9   import org.djutils.exceptions.Throw;
10  import org.opentrafficsim.core.gtu.GtuException;
11  import org.opentrafficsim.core.network.NetworkException;
12  import org.opentrafficsim.road.gtu.generator.LaneBasedGtuGenerator.Placement;
13  import org.opentrafficsim.road.gtu.generator.LaneBasedGtuGenerator.RoomChecker;
14  import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGtuCharacteristics;
15  import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGtu;
16  import org.opentrafficsim.road.network.lane.Lane;
17  import org.opentrafficsim.road.network.lane.LanePosition;
18  
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-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
25   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
26   * </p>
27   * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
28   * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
29   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
30   */
31  public class CfRoomChecker implements RoomChecker
32  {
33  
34      /** {@inheritDoc} */
35      @Override
36      public Placement canPlace(final SortedSet<HeadwayGtu> leaders, final LaneBasedGtuCharacteristics characteristics,
37              final Duration since, final LanePosition initialPosition) throws NetworkException, GtuException
38      {
39          Speed speedLimit = initialPosition.lane().getSpeedLimit(characteristics.getGtuType());
40          Throw.when(speedLimit == null, IllegalStateException.class, "No speed limit could be determined for GtuType %s.",
41                  characteristics.getGtuType());
42          Speed desiredSpeed = characteristics.getStrategicalPlannerFactory().peekDesiredSpeed(characteristics.getGtuType(),
43                  speedLimit, characteristics.getMaximumSpeed());
44          desiredSpeed = desiredSpeed != null ? desiredSpeed : speedLimit; // speed limit def.
45          if (leaders.isEmpty())
46          {
47              // no leaders: free
48              return new Placement(desiredSpeed, initialPosition);
49          }
50          Length desiredHeadway =
51                  characteristics.getStrategicalPlannerFactory().peekDesiredHeadway(characteristics.getGtuType(), desiredSpeed);
52          desiredHeadway = desiredHeadway != null ? desiredHeadway : desiredSpeed.times(Duration.instantiateSI(1.0)); // 1s def.
53          // loop leaders and determine most downstream location that would be ok
54          Length move = Length.POSITIVE_INFINITY;
55          Speed generationSpeed = desiredSpeed;
56          for (HeadwayGtu leader : leaders)
57          {
58              Speed speed = Speed.min(desiredSpeed, leader.getSpeed());
59              Length headway =
60                      characteristics.getStrategicalPlannerFactory().peekDesiredHeadway(characteristics.getGtuType(), speed);
61              headway = headway != null ? headway : speed.times(Duration.instantiateSI(1.0)); // 1s def.
62              double f = this.headwayFactor(desiredSpeed, desiredHeadway, speed, headway, leader.getLength());
63              headway = headway.times(f);
64              if (leader.getDistance().lt(headway))
65              {
66                  // not enough space to this leader
67                  return Placement.NO;
68              }
69              Length moveToLeader = leader.getDistance().minus(headway);
70              if (moveToLeader.lt(move))
71              {
72                  move = moveToLeader;
73                  generationSpeed = speed;
74              }
75          }
76          move = Length.min(move, since.times(generationSpeed)); // max distance the GTU would have moved until now
77          // move this distance
78          LanePosition generationPosition;
79          if (move.eq0())
80          {
81              generationPosition = initialPosition;
82          }
83          else
84          {
85              Lane lane = initialPosition.lane();
86              Length position = initialPosition.position();
87              Length canMove = lane.getLength().minus(position);
88              while (canMove.lt(move))
89              {
90                  Set<Lane> down = lane.nextLanes(characteristics.getGtuType());
91                  if (down.size() != 1)
92                  {
93                      // split or dead-end, fall back to original position
94                      return new Placement(generationSpeed, initialPosition);
95                  }
96                  else
97                  {
98                      move = move.minus(canMove);
99                      lane = down.iterator().next();
100                     position = Length.ZERO;
101                     canMove = lane.getLength();
102                 }
103             }
104             position = position.plus(move);
105             generationPosition = new LanePosition(lane, position);
106         }
107         return new Placement(generationSpeed, generationPosition);
108     }
109 
110     /**
111      * Returns a situation dependent headway factor to deal with spillback.
112      * @param desiredSpeed Speed; desired speed
113      * @param desiredHeadway Length; desired headway at desired speed
114      * @param generationSpeed Speed; generation speed
115      * @param generationHeadway Length; desired headway at generation speed
116      * @param leaderLength Length; length of the leader
117      * @return situation dependent headway factor to deal with spillback
118      */
119     protected double headwayFactor(final Speed desiredSpeed, final Length desiredHeadway, final Speed generationSpeed,
120             final Length generationHeadway, final Length leaderLength)
121     {
122         return 1.0;
123     }
124 
125 }