View Javadoc
1   package org.opentrafficsim.road.gtu.lane.perception.mental;
2   
3   import static org.opentrafficsim.base.parameters.constraint.NumericConstraint.POSITIVE;
4   import static org.opentrafficsim.base.parameters.constraint.NumericConstraint.POSITIVEZERO;
5   
6   import java.util.LinkedHashMap;
7   import java.util.LinkedHashSet;
8   import java.util.Map;
9   import java.util.Set;
10  
11  import org.djutils.exceptions.Throw;
12  import org.djutils.exceptions.Try;
13  import org.djutils.immutablecollections.Immutable;
14  import org.djutils.immutablecollections.ImmutableLinkedHashSet;
15  import org.djutils.immutablecollections.ImmutableSet;
16  import org.opentrafficsim.base.parameters.ParameterException;
17  import org.opentrafficsim.base.parameters.ParameterTypeDouble;
18  import org.opentrafficsim.base.parameters.Parameters;
19  import org.opentrafficsim.core.gtu.GtuException;
20  import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
21  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
22  import org.opentrafficsim.road.gtu.lane.perception.mental.TaskManager.SummativeTaskManager;
23  
24  /**
25   * Task-capability interface in accordance to Fuller (2011). Task demand is the sum of demands described by individual
26   * {@code Task}s. These take exogenous information to describe the workload in fundamental relations. Task demand is divided by
27   * task capability to arrive at a task saturation. Task saturation is input to {@code BehavioralAdaptation}s which alter
28   * parameters describing personal traits, such as desired headway and desired speed. In this way, task demand is kept at an
29   * equilibrium as described by Fuller.
30   * <p>
31   * A {@code BehavioralAdaptation} may also determine what the level of situational awareness is, which includes determining
32   * reaction time. Both situational awareness and reaction time parameters can be used in perception to model deteriorated
33   * perception due to a task demand imbalance.
34   * <p>
35   * Fuller, R., Driver control theory: From task difficulty homeostasis to risk allostasis, in Handbook of Traffic Psychology.
36   * 2011. p. 13-26
37   * <p>
38   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
39   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
40   * </p>
41   * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
42   * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
43   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
44   */
45  public class Fuller implements Mental
46  {
47  
48      // Parameters
49  
50      /** Task capability in nominal task capability units, i.e. mean is 1. */
51      public static final ParameterTypeDouble TC = new ParameterTypeDouble("TC", "Task capability", 1.0, POSITIVE);
52  
53      /** Critical task saturation. */
54      public static final ParameterTypeDouble TS_CRIT =
55              new ParameterTypeDouble("TScrit", "Critical task saturation", 0.8, POSITIVEZERO)
56              {
57                  /** */
58                  private static final long serialVersionUID = 20180403L;
59  
60                  /** {@inheritDoc} */
61                  @Override
62                  public void check(final Double value, final Parameters params) throws ParameterException
63                  {
64                      Double tsMax = params.getParameterOrNull(TS_MAX);
65                      Throw.when(tsMax != null && value > tsMax, ParameterException.class,
66                              "Value for TS_CRIT should not be larger than TS_MAX.");
67                  }
68              };
69  
70      /** Maximum task saturation, pertaining to maximum deterioration. */
71      public static final ParameterTypeDouble TS_MAX =
72              new ParameterTypeDouble("TSmax", "Maximum task saturation", 2.0, POSITIVEZERO)
73              {
74                  /** */
75                  private static final long serialVersionUID = 20180403L;
76  
77                  /** {@inheritDoc} */
78                  @Override
79                  public void check(final Double value, final Parameters params) throws ParameterException
80                  {
81                      Double tsCrit = params.getParameterOrNull(TS_CRIT);
82                      Throw.when(tsCrit != null && value < tsCrit, ParameterException.class,
83                              "Value for TS_MAX should not be smaller than TS_CRIT.");
84                  }
85              };
86  
87      /** Task saturation. */
88      public static final ParameterTypeDouble TS = new ParameterTypeDouble("TS", "Task saturation", 0.0, POSITIVEZERO);
89  
90      // Properties
91  
92      /** Tasks causing task demand. */
93      private final Set<Task> tasks;
94  
95      /** Behavioral adaptations depending on task saturation. */
96      private final Set<BehavioralAdaptation> behavioralAdapatations;
97  
98      /** Task manager. */
99      private final TaskManager taskManager;
100 
101     /** Stored anticipation reliance per task. */
102     private Map<String, Double> anticipationReliances = new LinkedHashMap<>();
103 
104     /** Stored task demand per task. */
105     private Map<String, Double> taskDemands = new LinkedHashMap<>();
106 
107     /**
108      * Constructor with custom situational awareness.
109      * @param tasks Set&lt;? extends Task&gt;; tasks
110      * @param behavioralAdapatations Set&lt;BehavioralAdaptation&gt;; behavioralAdapatations
111      */
112     public Fuller(final Set<? extends Task> tasks, final Set<BehavioralAdaptation> behavioralAdapatations)
113     {
114         this(tasks, behavioralAdapatations, new SummativeTaskManager());
115     }
116 
117     /**
118      * Constructor with custom situational awareness.
119      * @param tasks Set&lt;? extends Task&gt;; tasks
120      * @param behavioralAdapatations Set&lt;BehavioralAdaptation&gt;; behavioralAdapatations
121      * @param taskManager TaskManager; task manager
122      */
123     public Fuller(final Set<? extends Task> tasks, final Set<BehavioralAdaptation> behavioralAdapatations,
124             final TaskManager taskManager)
125     {
126         Throw.whenNull(tasks, "Tasks may not be null.");
127         Throw.whenNull(behavioralAdapatations, "Behavioral adaptations may not be null.");
128         this.tasks = new LinkedHashSet<>();
129         this.tasks.addAll(tasks);
130         this.behavioralAdapatations = behavioralAdapatations;
131         this.taskManager = taskManager;
132     }
133 
134     /**
135      * Adds a task.
136      * @param task Task; task to add
137      */
138     public void addTask(final Task task)
139     {
140         this.tasks.add(task);
141     }
142 
143     /**
144      * Removes a task.
145      * @param task Task; task to remove
146      */
147     public void removeTask(final Task task)
148     {
149         this.tasks.remove(task);
150     }
151 
152     /**
153      * Returns the tasks.
154      * @return ImmutableSet&lt;Task&gt; tasks
155      */
156     public ImmutableSet<Task> getTasks()
157     {
158         return new ImmutableLinkedHashSet<>(this.tasks, Immutable.WRAP);
159     }
160 
161     /** {@inheritDoc} */
162     @Override
163     public void apply(final LanePerception perception) throws ParameterException, GtuException
164     {
165         LaneBasedGtu gtu = Try.assign(() -> perception.getGtu(), "Could not obtain GTU.");
166         Parameters parameters = gtu.getParameters();
167         double taskDemand = 0.0;
168         // a) the fundamental diagrams of task workload are defined in the tasks
169         // b) sum task demand
170         this.taskManager.manage(this.tasks, perception, gtu, parameters);
171         this.anticipationReliances.clear();
172         this.taskDemands.clear();
173         for (Task task : this.tasks)
174         {
175             double ar = task.getAnticipationReliance();
176             double td = task.getTaskDemand();
177             this.anticipationReliances.put(task.getId(), ar);
178             this.taskDemands.put(task.getId(), td);
179             taskDemand += (td - ar);
180         }
181         double taskSaturation = taskDemand / parameters.getParameter(TC);
182         parameters.setParameter(TS, taskSaturation);
183         // c) behavioral adaptation
184         for (BehavioralAdaptation behavioralAdapatation : this.behavioralAdapatations)
185         {
186             behavioralAdapatation.adapt(parameters, taskSaturation);
187         }
188         // d) situational awareness can be implemented by one of the behavioral responses
189         // e) perception errors from situational awareness are included in the perception step
190         // f) reaction time from situational awareness are included in the perception step
191     }
192 
193     /**
194      * Returns the anticipation reliance of the given task id.
195      * @param taskId taskId; task id to return the anticipation reliance for.
196      * @return double; anticipation reliance of given task id, {@code NaN if not present}
197      */
198     public double getAnticipationReliance(final String taskId)
199     {
200         return this.anticipationReliances.getOrDefault(taskId, Double.NaN);
201     }
202 
203     /**
204      * Returns the demand of the given task id.
205      * @param taskId taskId; task id to return the demand for.
206      * @return double; demand of given task id, {@code NaN if not present}
207      */
208     public double getTaskDemand(final String taskId)
209     {
210         return this.taskDemands.getOrDefault(taskId, Double.NaN);
211     }
212 
213     /** {@inheritDoc} */
214     @Override
215     public String toString()
216     {
217         return "Fuller [tasks=" + this.tasks + ", behavioralAdapatations=" + this.behavioralAdapatations + "]";
218     }
219 
220     /**
221      * Behavioral adaptation by changing parameter values.
222      * <p>
223      * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
224      * <br>
225      * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
226      * </p>
227      * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
228      * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
229      * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
230      */
231     @FunctionalInterface
232     public interface BehavioralAdaptation
233     {
234         /**
235          * Adapt to task saturation by changing parameter values.
236          * @param parameters Parameters; parameters
237          * @param taskSaturation double; task saturation
238          * @throws ParameterException if a parameter is missing or out of bounds
239          */
240         void adapt(Parameters parameters, double taskSaturation) throws ParameterException;
241     }
242 
243 }