View Javadoc
1   package org.opentrafficsim.road.gtu.generator;
2   
3   import java.util.LinkedHashSet;
4   import java.util.Set;
5   import java.util.SortedSet;
6   
7   import org.djunits.value.vdouble.scalar.Duration;
8   import org.djunits.value.vdouble.scalar.Length;
9   import org.djunits.value.vdouble.scalar.Speed;
10  import org.djutils.exceptions.Throw;
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.Lane;
18  import org.opentrafficsim.road.network.lane.LanePosition;
19  
20  /**
21   * 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
22   * further than the GTU could have traveled at the desired speed during the time since the desired arrival. With multiple
23   * leaders, the leader that causes the most upstream following position is used.
24   * <p>
25   * Copyright (c) 2013-2023 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
26   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
27   * </p>
28   * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
29   * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
30   * @author <a href="https://dittlab.tudelft.nl">Wouter Schakel</a>
31   */
32  public class CfRoomChecker implements RoomChecker
33  {
34  
35      /** {@inheritDoc} */
36      @Override
37      public Placement canPlace(final SortedSet<HeadwayGtu> leaders, final LaneBasedGtuCharacteristics characteristics,
38              final Duration since, final Set<LanePosition> initialPosition) throws NetworkException, GtuException
39      {
40          Speed speedLimit = null;
41          for (LanePosition lane : initialPosition)
42          {
43              try
44              {
45                  Speed limit = lane.getLane().getSpeedLimit(characteristics.getGtuType());
46                  if (speedLimit == null || limit.gt(speedLimit))
47                  {
48                      speedLimit = limit;
49                  }
50              }
51              catch (NetworkException exception)
52              {
53                  // ignore
54              }
55          }
56          Throw.when(speedLimit == null, IllegalStateException.class, "No speed limit could be determined for GtuType %s.",
57                  characteristics.getGtuType());
58          Speed desiredSpeed = characteristics.getStrategicalPlannerFactory().peekDesiredSpeed(characteristics.getGtuType(),
59                  speedLimit, characteristics.getMaximumSpeed());
60          desiredSpeed = desiredSpeed != null ? desiredSpeed : speedLimit; // speed limit def.
61          if (leaders.isEmpty())
62          {
63              // no leaders: free
64              return new Placement(desiredSpeed, initialPosition);
65          }
66          Length desiredHeadway =
67                  characteristics.getStrategicalPlannerFactory().peekDesiredHeadway(characteristics.getGtuType(), desiredSpeed);
68          desiredHeadway = desiredHeadway != null ? desiredHeadway : desiredSpeed.times(Duration.instantiateSI(1.0)); // 1s def.
69          // loop leaders and determine most downstream location that would be ok
70          Length move = Length.POSITIVE_INFINITY;
71          Speed generationSpeed = desiredSpeed;
72          for (HeadwayGtu leader : leaders)
73          {
74              Speed speed = Speed.min(desiredSpeed, leader.getSpeed());
75              Length headway =
76                      characteristics.getStrategicalPlannerFactory().peekDesiredHeadway(characteristics.getGtuType(), speed);
77              headway = headway != null ? headway : speed.times(Duration.instantiateSI(1.0)); // 1s def.
78              double f = this.headwayFactor(desiredSpeed, desiredHeadway, speed, headway, leader.getLength());
79              headway = headway.times(f);
80              if (leader.getDistance().lt(headway))
81              {
82                  // not enough space to this leader
83                  return Placement.NO;
84              }
85              Length moveToLeader = leader.getDistance().minus(headway);
86              if (moveToLeader.lt(move))
87              {
88                  move = moveToLeader;
89                  generationSpeed = speed;
90              }
91          }
92          move = Length.min(move, since.times(generationSpeed)); // max distance the GTU would have moved until now
93          // move this distance
94          Set<LanePosition> generationPosition;
95          if (move.eq0() || initialPosition.size() != 1)
96          {
97              generationPosition = initialPosition;
98          }
99          else
100         {
101             generationPosition = new LinkedHashSet<>();
102             for (LanePosition lanePos : initialPosition)
103             {
104                 Lane lane = lanePos.getLane();
105                 Length position = lanePos.getPosition();
106                 Length canMove = lane.getLength().minus(position);
107                 while (canMove.lt(move))
108                 {
109                     Set<Lane> down = lane.nextLanes(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.iterator().next();
119                         position = Length.ZERO;
120                         canMove = lane.getLength();
121                     }
122                 }
123                 position = position.plus(move);
124                 generationPosition.add(new LanePosition(lane, position));
125             }
126         }
127         return new Placement(generationSpeed, generationPosition);
128     }
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 
145 }