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://github.com/peter-knoppers">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                  @Override
61                  public void check(final Double value, final Parameters params) throws ParameterException
62                  {
63                      Double tsMax = params.getParameterOrNull(TS_MAX);
64                      Throw.when(tsMax != null && value > tsMax, ParameterException.class,
65                              "Value for TS_CRIT should not be larger than TS_MAX.");
66                  }
67              };
68  
69      /** Maximum task saturation, pertaining to maximum deterioration. */
70      public static final ParameterTypeDouble TS_MAX =
71              new ParameterTypeDouble("TSmax", "Maximum task saturation", 2.0, POSITIVEZERO)
72              {
73                  /** */
74                  private static final long serialVersionUID = 20180403L;
75  
76                  @Override
77                  public void check(final Double value, final Parameters params) throws ParameterException
78                  {
79                      Double tsCrit = params.getParameterOrNull(TS_CRIT);
80                      Throw.when(tsCrit != null && value < tsCrit, ParameterException.class,
81                              "Value for TS_MAX should not be smaller than TS_CRIT.");
82                  }
83              };
84  
85      /** Task saturation. */
86      public static final ParameterTypeDouble TS = new ParameterTypeDouble("TS", "Task saturation", 0.0, POSITIVEZERO);
87  
88      // Properties
89  
90      /** Tasks causing task demand. */
91      private final Set<Task> tasks;
92  
93      /** Behavioral adaptations depending on task saturation. */
94      private final Set<BehavioralAdaptation> behavioralAdapatations;
95  
96      /** Task manager. */
97      private final TaskManager taskManager;
98  
99      /** Stored anticipation reliance per task. */
100     private Map<String, Double> anticipationReliances = new LinkedHashMap<>();
101 
102     /** Stored task demand per task. */
103     private Map<String, Double> taskDemands = new LinkedHashMap<>();
104 
105     /**
106      * Constructor with custom situational awareness.
107      * @param tasks tasks
108      * @param behavioralAdapatations behavioralAdapatations
109      */
110     public Fuller(final Set<? extends Task> tasks, final Set<BehavioralAdaptation> behavioralAdapatations)
111     {
112         this(tasks, behavioralAdapatations, new SummativeTaskManager());
113     }
114 
115     /**
116      * Constructor with custom situational awareness.
117      * @param tasks tasks
118      * @param behavioralAdapatations behavioralAdapatations
119      * @param taskManager task manager
120      */
121     public Fuller(final Set<? extends Task> tasks, final Set<BehavioralAdaptation> behavioralAdapatations,
122             final TaskManager taskManager)
123     {
124         Throw.whenNull(tasks, "Tasks may not be null.");
125         Throw.whenNull(behavioralAdapatations, "Behavioral adaptations may not be null.");
126         this.tasks = new LinkedHashSet<>();
127         this.tasks.addAll(tasks);
128         this.behavioralAdapatations = behavioralAdapatations;
129         this.taskManager = taskManager;
130     }
131 
132     /**
133      * Adds a task.
134      * @param task task to add
135      */
136     public void addTask(final Task task)
137     {
138         this.tasks.add(task);
139     }
140 
141     /**
142      * Removes a task.
143      * @param task task to remove
144      */
145     public void removeTask(final Task task)
146     {
147         this.tasks.remove(task);
148     }
149 
150     /**
151      * Returns the tasks.
152      * @return ImmutableSet&lt;Task&gt; tasks
153      */
154     public ImmutableSet<Task> getTasks()
155     {
156         return new ImmutableLinkedHashSet<>(this.tasks, Immutable.WRAP);
157     }
158 
159     @Override
160     public void apply(final LanePerception perception) throws ParameterException, GtuException
161     {
162         LaneBasedGtu gtu = Try.assign(() -> perception.getGtu(), "Could not obtain GTU.");
163         Parameters parameters = gtu.getParameters();
164         double taskDemand = 0.0;
165         // a) the fundamental diagrams of task workload are defined in the tasks
166         // b) sum task demand
167         this.taskManager.manage(this.tasks, perception, gtu, parameters);
168         this.anticipationReliances.clear();
169         this.taskDemands.clear();
170         for (Task task : this.tasks)
171         {
172             double ar = task.getAnticipationReliance();
173             double td = task.getTaskDemand();
174             this.anticipationReliances.put(task.getId(), ar);
175             this.taskDemands.put(task.getId(), td);
176             taskDemand += (td - ar);
177         }
178         double taskSaturation = taskDemand / parameters.getParameter(TC);
179         parameters.setParameter(TS, taskSaturation);
180         // c) behavioral adaptation
181         for (BehavioralAdaptation behavioralAdapatation : this.behavioralAdapatations)
182         {
183             behavioralAdapatation.adapt(parameters, taskSaturation);
184         }
185         // d) situational awareness can be implemented by one of the behavioral responses
186         // e) perception errors from situational awareness are included in the perception step
187         // f) reaction time from situational awareness are included in the perception step
188     }
189 
190     /**
191      * Returns the anticipation reliance of the given task id.
192      * @param taskId task id to return the anticipation reliance for.
193      * @return anticipation reliance of given task id, {@code NaN if not present}
194      */
195     public double getAnticipationReliance(final String taskId)
196     {
197         return this.anticipationReliances.getOrDefault(taskId, Double.NaN);
198     }
199 
200     /**
201      * Returns the demand of the given task id.
202      * @param taskId task id to return the demand for.
203      * @return demand of given task id, {@code NaN if not present}
204      */
205     public double getTaskDemand(final String taskId)
206     {
207         return this.taskDemands.getOrDefault(taskId, Double.NaN);
208     }
209 
210     @Override
211     public String toString()
212     {
213         return "Fuller [tasks=" + this.tasks + ", behavioralAdapatations=" + this.behavioralAdapatations + "]";
214     }
215 
216     /**
217      * Behavioral adaptation by changing parameter values.
218      * <p>
219      * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
220      * <br>
221      * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
222      * </p>
223      * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
224      * @author <a href="https://github.com/peter-knoppers">Peter Knoppers</a>
225      * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
226      */
227     @FunctionalInterface
228     public interface BehavioralAdaptation
229     {
230         /**
231          * Adapt to task saturation by changing parameter values.
232          * @param parameters parameters
233          * @param taskSaturation task saturation
234          * @throws ParameterException if a parameter is missing or out of bounds
235          */
236         void adapt(Parameters parameters, double taskSaturation) throws ParameterException;
237     }
238 
239 }