View Javadoc
1   package org.opentrafficsim.road.gtu.perception.mental.channel;
2   
3   import java.util.Iterator;
4   import java.util.NoSuchElementException;
5   import java.util.Set;
6   import java.util.function.Function;
7   
8   import org.djunits.value.vdouble.scalar.Duration;
9   import org.opentrafficsim.base.DistancedObject;
10  import org.opentrafficsim.base.OtsRuntimeException;
11  import org.opentrafficsim.base.parameters.ParameterTypeDuration;
12  import org.opentrafficsim.core.gtu.perception.EgoPerception;
13  import org.opentrafficsim.road.gtu.LaneBasedGtu;
14  import org.opentrafficsim.road.gtu.perception.LanePerception;
15  import org.opentrafficsim.road.gtu.perception.RelativeLane;
16  import org.opentrafficsim.road.gtu.perception.categories.neighbors.NeighborsPerception;
17  import org.opentrafficsim.road.gtu.perception.mental.AbstractTask;
18  import org.opentrafficsim.road.gtu.perception.mental.ar.ArTaskCarFollowingExp;
19  
20  /**
21   * Task demand for car-following. This is defined as {@code exp(-T/h)} where {@code T} is the time headway to the leader and
22   * {@code h} is the car-following task parameter that scales it.
23   * <p>
24   * Copyright (c) 2024-2026 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 Wouter Schakel
28   */
29  public class ChannelTaskCarFollowing extends AbstractTask implements ChannelTask
30  {
31  
32      /** Car-following task parameter. */
33      public static final ParameterTypeDuration HEXP = ArTaskCarFollowingExp.HEXP;
34  
35      /** Singleton instance. */
36      private static final ChannelTaskCarFollowing DEFAULT = new ChannelTaskCarFollowing();
37  
38      /** Default set that is returned by the supplier. */
39      private static final Set<ChannelTask> SET = Set.of(DEFAULT);
40  
41      /** Standard supplier that supplies a single instance of the car-following task. */
42      public static final Function<LanePerception, Set<ChannelTask>> SUPPLIER = (p) -> SET;
43  
44      /** Leader supplier. */
45      private final Function<LanePerception, DistancedObject<LaneBasedGtu>> leaderSupplier;
46  
47      /**
48       * Constructor that will use the first leader from NeighborsPerception in the current lane.
49       */
50      public ChannelTaskCarFollowing()
51      {
52          this((perception) ->
53          {
54              NeighborsPerception neighbors = perception.getPerceptionCategoryOptional(NeighborsPerception.class)
55                      .orElseThrow(() -> new NoSuchElementException("NeighborsPerception not present."));
56              Iterator<DistancedObject<LaneBasedGtu>> leader =
57                      neighbors.getLeaders(RelativeLane.CURRENT).underlyingWithDistance();
58              if (!leader.hasNext())
59              {
60                  return null;
61              }
62              return leader.next();
63          });
64      }
65  
66      /**
67       * Constructor that provides a supplier for a leader that follows a non-default logic.
68       * @param leaderSupplier leader supplier
69       */
70      public ChannelTaskCarFollowing(final Function<LanePerception, DistancedObject<LaneBasedGtu>> leaderSupplier)
71      {
72          super("car-following (front)");
73          this.leaderSupplier = leaderSupplier;
74      }
75  
76      @Override
77      public String getId()
78      {
79          return "car-following (front)";
80      }
81  
82      @Override
83      public Object getChannel()
84      {
85          return FRONT;
86      }
87  
88      @Override
89      public double calculateTaskDemand(final LanePerception perception)
90      {
91          DistancedObject<LaneBasedGtu> leader = this.leaderSupplier.apply(perception);
92          if (leader == null)
93          {
94              return 0.0;
95          }
96          EgoPerception<?, ?> ego = perception.getPerceptionCategoryOptional(EgoPerception.class)
97                  .orElseThrow(() -> new NoSuchElementException("EgoPerception not present."));
98          Duration headway = leader.distance().divide(ego.getSpeed());
99          Duration h = perception.getGtu().getParameters().getOptionalParameter(HEXP)
100                 .orElseThrow(() -> new OtsRuntimeException("Parameter h_exp not present."));
101         return headway.si <= 0.0 ? 0.999 : Math.exp(-headway.si / h.si);
102     }
103 
104 }