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://github.com/peter-knoppers">Peter Knoppers</a>
29   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
30   */
31  public class CfRoomChecker implements RoomChecker
32  {
33  
34      @Override
35      public Placement canPlace(final SortedSet<HeadwayGtu> leaders, final LaneBasedGtuCharacteristics characteristics,
36              final Duration since, final LanePosition initialPosition) throws NetworkException, GtuException
37      {
38          Speed speedLimit = initialPosition.lane().getSpeedLimit(characteristics.getGtuType());
39          Throw.when(speedLimit == null, IllegalStateException.class, "No speed limit could be determined for GtuType %s.",
40                  characteristics.getGtuType());
41          Speed desiredSpeed = characteristics.getStrategicalPlannerFactory().peekDesiredSpeed(characteristics.getGtuType(),
42                  speedLimit, characteristics.getMaximumSpeed());
43          desiredSpeed = desiredSpeed != null ? desiredSpeed : speedLimit; // speed limit def.
44          if (leaders.isEmpty())
45          {
46              // no leaders: free
47              return new Placement(desiredSpeed, initialPosition);
48          }
49          Length desiredHeadway =
50                  characteristics.getStrategicalPlannerFactory().peekDesiredHeadway(characteristics.getGtuType(), desiredSpeed);
51          desiredHeadway = desiredHeadway != null ? desiredHeadway : desiredSpeed.times(Duration.instantiateSI(1.0)); // 1s def.
52          // loop leaders and determine most downstream location that would be ok
53          Length move = Length.POSITIVE_INFINITY;
54          Speed generationSpeed = desiredSpeed;
55          for (HeadwayGtu leader : leaders)
56          {
57              Speed speed = Speed.min(desiredSpeed, leader.getSpeed());
58              Length headway =
59                      characteristics.getStrategicalPlannerFactory().peekDesiredHeadway(characteristics.getGtuType(), speed);
60              headway = headway != null ? headway : speed.times(Duration.instantiateSI(1.0)); // 1s def.
61              double f = this.headwayFactor(desiredSpeed, desiredHeadway, speed, headway, leader.getLength());
62              headway = headway.times(f);
63              if (leader.getDistance().lt(headway))
64              {
65                  // not enough space to this leader
66                  return Placement.NO;
67              }
68              Length moveToLeader = leader.getDistance().minus(headway);
69              if (moveToLeader.lt(move))
70              {
71                  move = moveToLeader;
72                  generationSpeed = speed;
73              }
74          }
75          move = Length.min(move, since.times(generationSpeed)); // max distance the GTU would have moved until now
76          // move this distance
77          LanePosition generationPosition;
78          if (move.eq0())
79          {
80              generationPosition = initialPosition;
81          }
82          else
83          {
84              Lane lane = initialPosition.lane();
85              Length position = initialPosition.position();
86              Length canMove = lane.getLength().minus(position);
87              while (canMove.lt(move))
88              {
89                  Set<Lane> down = lane.nextLanes(characteristics.getGtuType());
90                  if (down.size() != 1)
91                  {
92                      // split or dead-end, fall back to original position
93                      return new Placement(generationSpeed, initialPosition);
94                  }
95                  else
96                  {
97                      move = move.minus(canMove);
98                      lane = down.iterator().next();
99                      position = Length.ZERO;
100                     canMove = lane.getLength();
101                 }
102             }
103             position = position.plus(move);
104             generationPosition = new LanePosition(lane, position);
105         }
106         return new Placement(generationSpeed, generationPosition);
107     }
108 
109     /**
110      * Returns a situation dependent headway factor to deal with spillback.
111      * @param desiredSpeed desired speed
112      * @param desiredHeadway desired headway at desired speed
113      * @param generationSpeed generation speed
114      * @param generationHeadway desired headway at generation speed
115      * @param leaderLength length of the leader
116      * @return situation dependent headway factor to deal with spillback
117      */
118     protected double headwayFactor(final Speed desiredSpeed, final Length desiredHeadway, final Speed generationSpeed,
119             final Length generationHeadway, final Length leaderLength)
120     {
121         return 1.0;
122     }
123 
124 }