View Javadoc
1   package org.opentrafficsim.road.gtu.generator;
2   
3   import java.util.HashSet;
4   import java.util.Map;
5   import java.util.Set;
6   import java.util.SortedSet;
7   
8   import org.djunits.value.vdouble.scalar.Duration;
9   import org.djunits.value.vdouble.scalar.Length;
10  import org.djunits.value.vdouble.scalar.Speed;
11  import org.opentrafficsim.core.gtu.GTUDirectionality;
12  import org.opentrafficsim.core.gtu.GTUException;
13  import org.opentrafficsim.core.network.NetworkException;
14  import org.opentrafficsim.road.gtu.generator.LaneBasedGTUGenerator.Placement;
15  import org.opentrafficsim.road.gtu.generator.LaneBasedGTUGenerator.RoomChecker;
16  import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGTUCharacteristics;
17  import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTU;
18  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
19  import org.opentrafficsim.road.network.lane.Lane;
20  
21  import nl.tudelft.simulation.language.Throw;
22  
23  /**
24   * 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
25   * further than the GTU could have traveled at the desired speed during the time since the desired arrival. With multiple
26   * leaders, the leader that causes the most upstream following position is used.
27   * <p>
28   * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
29   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
30   * <p>
31   * @version $Revision$, $LastChangedDate$, by $Author$, initial version 12 jan. 2018 <br>
32   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
33   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
34   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
35   */
36  public class CFRoomChecker implements RoomChecker
37  {
38  
39      /** {@inheritDoc} */
40      @Override
41      public Placement canPlace(final SortedSet<HeadwayGTU> leaders, final LaneBasedGTUCharacteristics characteristics,
42              final Duration since, final Set<DirectedLanePosition> initialPosition) throws NetworkException, GTUException
43      {
44          Speed speedLimit = null;
45          for (DirectedLanePosition lane : initialPosition)
46          {
47              try
48              {
49                  Speed limit = lane.getLane().getSpeedLimit(characteristics.getGTUType());
50                  if (speedLimit == null || limit.gt(speedLimit))
51                  {
52                      speedLimit = limit;
53                  }
54              }
55              catch (@SuppressWarnings("unused") NetworkException exception)
56              {
57                  // ignore
58              }
59          }
60          Throw.when(speedLimit == null, IllegalStateException.class, "No speed limit could be determined for GTUType %s.",
61                  characteristics.getGTUType());
62          Speed desiredSpeed = characteristics.getStrategicalPlannerFactory().peekDesiredSpeed(characteristics.getGTUType(),
63                  speedLimit, characteristics.getMaximumSpeed());
64          desiredSpeed = desiredSpeed != null ? desiredSpeed : speedLimit; // speed limit def.
65          if (leaders.isEmpty())
66          {
67              // no leaders: free
68              return new Placement(desiredSpeed, initialPosition);
69          }
70          Length desiredHeadway =
71                  characteristics.getStrategicalPlannerFactory().peekDesiredHeadway(characteristics.getGTUType(), desiredSpeed);
72          desiredHeadway = desiredHeadway != null ? desiredHeadway : desiredSpeed.multiplyBy(Duration.createSI(1.0)); // 1s def.
73          // loop leaders and determine most downstream location that would be ok
74          Length move = Length.POSITIVE_INFINITY;
75          Speed generationSpeed = desiredSpeed;
76          for (HeadwayGTU leader : leaders)
77          {
78              Speed speed = Speed.min(desiredSpeed, leader.getSpeed());
79              Length headway =
80                      characteristics.getStrategicalPlannerFactory().peekDesiredHeadway(characteristics.getGTUType(), speed);
81              headway = headway != null ? headway : speed.multiplyBy(Duration.createSI(1.0)); // 1s def.
82              double f = this.headwayFactor(desiredSpeed, desiredHeadway, speed, headway, leader.getLength());
83              headway = headway.multiplyBy(f);
84              if (leader.getDistance().lt(headway))
85              {
86                  // not enough space to this leader
87                  return Placement.NO;
88              }
89              Length moveToLeader = leader.getDistance().minus(headway);
90              if (moveToLeader.lt(move))
91              {
92                  move = moveToLeader;
93                  generationSpeed = speed;
94              }
95          }
96          move = Length.min(move, since.multiplyBy(generationSpeed)); // max distance the GTU would have moved until now
97          // move this distance
98          Set<DirectedLanePosition> generationPosition;
99          if (move.eq0() || initialPosition.size() != 1)
100         {
101             generationPosition = initialPosition;
102         }
103         else
104         {
105             generationPosition = new HashSet<>();
106             for (DirectedLanePosition dirPos : initialPosition)
107             {
108                 Lane lane = dirPos.getLane();
109                 GTUDirectionality dir = dirPos.getGtuDirection();
110                 Length position = dirPos.getPosition();
111                 Length canMove = dir.isPlus() ? lane.getLength().minus(position) : position;
112                 while (canMove.lt(move))
113                 {
114                     Map<Lane, GTUDirectionality> down = lane.downstreamLanes(dir, characteristics.getGTUType());
115                     if (down.size() != 1)
116                     {
117                         // split or dead-end, fall back to original position
118                         return new Placement(generationSpeed, initialPosition);
119                     }
120                     else
121                     {
122                         move = move.minus(canMove);
123                         lane = down.keySet().iterator().next();
124                         dir = down.get(lane);
125                         position = dir.isPlus() ? Length.ZERO : lane.getLength();
126                         canMove = lane.getLength();
127                     }
128                 }
129                 position = dir.isPlus() ? position.plus(move) : position.minus(move);
130                 generationPosition.add(new DirectedLanePosition(lane, position, dir));
131             }
132         }
133         return new Placement(generationSpeed, generationPosition);
134     }
135 
136     /**
137      * Returns a situation dependent headway factor to deal with spillback.
138      * @param desiredSpeed Speed; desired speed
139      * @param desiredHeadway Length; desired headway at desired speed
140      * @param generationSpeed Speed; generation speed
141      * @param generationHeadway Length; desired headway at generation speed
142      * @param leaderLength Length; length of the leader
143      * @return situation dependent headway factor to deal with spillback
144      */
145     protected double headwayFactor(final Speed desiredSpeed, final Length desiredHeadway, final Speed generationSpeed,
146             final Length generationHeadway, final Length leaderLength)
147     {
148         return 1.0;
149     }
150 
151 }