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