1 package org.opentrafficsim.road.gtu.perception.mental.channel;
2
3 import java.util.Collection;
4 import java.util.LinkedHashMap;
5 import java.util.LinkedHashSet;
6 import java.util.Map;
7 import java.util.Map.Entry;
8 import java.util.Optional;
9 import java.util.Set;
10 import java.util.function.Function;
11
12 import org.djunits.value.vdouble.scalar.Duration;
13 import org.djutils.exceptions.Throw;
14 import org.djutils.immutablecollections.Immutable;
15 import org.djutils.immutablecollections.ImmutableLinkedHashSet;
16 import org.djutils.immutablecollections.ImmutableSet;
17 import org.opentrafficsim.base.logger.Logger;
18 import org.opentrafficsim.base.parameters.ParameterException;
19 import org.opentrafficsim.base.parameters.ParameterTypeDouble;
20 import org.opentrafficsim.base.parameters.ParameterTypeDuration;
21 import org.opentrafficsim.base.parameters.Parameters;
22 import org.opentrafficsim.base.parameters.constraint.DualBound;
23 import org.opentrafficsim.base.parameters.constraint.NumericConstraint;
24 import org.opentrafficsim.road.gtu.perception.LanePerception;
25 import org.opentrafficsim.road.gtu.perception.mental.BehavioralAdaptation;
26 import org.opentrafficsim.road.gtu.perception.mental.FactorEstimation;
27 import org.opentrafficsim.road.gtu.perception.mental.Fuller;
28 import org.opentrafficsim.road.gtu.perception.mental.Task;
29
30
31
32
33
34
35
36
37
38
39
40
41
42 public class ChannelFuller extends Fuller implements ChannelMental
43 {
44
45
46 public static final ParameterTypeDouble TC = Fuller.TC;
47
48
49 public static final ParameterTypeDouble TS = Fuller.TS;
50
51
52 public static final ParameterTypeDouble OVER_EST = Fuller.OVER_EST;
53
54
55 public static final ParameterTypeDouble EST_FACTOR = FactorEstimation.EST_FACTOR;
56
57
58 public static final ParameterTypeDouble ATT =
59 new ParameterTypeDouble("ATT", "Attention (maximum of all channels).", 0.0, DualBound.UNITINTERVAL);
60
61
62 public static final ParameterTypeDuration TAU_MIN = new ParameterTypeDuration("tau_min", "Minimum perception delay",
63 Duration.ofSI(0.32), NumericConstraint.POSITIVEZERO)
64 {
65
66 @Override
67 public void check(final Duration value, final Parameters params) throws ParameterException
68 {
69 Throw.when(params.contains(TAU_MAX) && params.getParameter(TAU_MAX).lt(value), ParameterException.class,
70 "Value of tau_max less smaller than tau_min.");
71
72 }
73 };
74
75
76 public static final ParameterTypeDuration TAU_MAX = new ParameterTypeDuration("tau_max", "Maximum perception delay",
77 Duration.ofSI(0.32 + 0.87), NumericConstraint.POSITIVE)
78 {
79
80 @Override
81 public void check(final Duration value, final Parameters params) throws ParameterException
82 {
83 Throw.when(params.contains(TAU_MIN) && params.getParameter(TAU_MIN).gt(value), ParameterException.class,
84 "Value of tau_min is greater than tau_max.");
85 }
86 };
87
88
89 private Set<Function<LanePerception, Set<ChannelTask>>> taskSuppliers = new LinkedHashSet<>();
90
91
92 private Set<ChannelTask> tasks;
93
94
95 private Map<String, ChannelTask> taskMap;
96
97
98 private Map<Object, Object> channelMapping = new LinkedHashMap<>();
99
100
101 private Map<Object, Duration> perceptionDelay = new LinkedHashMap<>();
102
103
104 private Map<Object, Double> attention = new LinkedHashMap<>();
105
106
107
108
109
110
111 public ChannelFuller(final Collection<Function<LanePerception, Set<ChannelTask>>> taskSuppliers,
112 final Set<BehavioralAdaptation> behavioralAdapatations)
113 {
114 super(behavioralAdapatations);
115 this.taskSuppliers.addAll(taskSuppliers);
116 }
117
118 @Override
119 protected double getTotalTaskDemand(final LanePerception perception) throws ParameterException
120 {
121
122 this.channelMapping.clear();
123
124
125 Map<Object, Double> channelTaskDemand = new LinkedHashMap<>();
126 Set<ChannelTask> gatheredTasks = new LinkedHashSet<>();
127 Map<String, ChannelTask> gatheredTaskMap = new LinkedHashMap<>();
128 for (Function<LanePerception, Set<ChannelTask>> taskFunction : this.taskSuppliers)
129 {
130 for (ChannelTask task : taskFunction.apply(perception))
131 {
132 double td = task.getTaskDemand(perception);
133 if (td >= 1.0)
134 {
135 td = 0.999;
136 Logger.ots().warn("Task {} produced task demand that is greater than, or equal to, 1.0.", task.getId());
137 }
138 channelTaskDemand.merge(task.getChannel(), td, Math::max);
139 gatheredTasks.add(task);
140 gatheredTaskMap.put(task.getId(), task);
141 }
142 }
143 this.tasks = gatheredTasks;
144 this.taskMap = gatheredTaskMap;
145
146
147 double[] tdArray = new double[channelTaskDemand.size()];
148 int index = 0;
149 double sumTaskDemand = 0.0;
150 Map<Object, Integer> channelIndex = new LinkedHashMap<>();
151 for (Entry<Object, Double> entry : channelTaskDemand.entrySet())
152 {
153 channelIndex.put(entry.getKey(), index);
154 double td = entry.getValue();
155 tdArray[index] = td;
156 sumTaskDemand += td;
157 index++;
158 }
159 AttentionMatrix matrix = new AttentionMatrix(tdArray);
160
161
162 double maxAttention = 0.0;
163 this.perceptionDelay.clear();
164 this.attention.clear();
165 Parameters parameters = perception.getGtu().getParameters();
166 Duration tauMin = parameters.getParameter(TAU_MIN);
167 Duration tauMax = parameters.getParameter(TAU_MAX);
168 double tc = parameters.getParameter(TC);
169 for (Entry<Object, Integer> entry : channelIndex.entrySet())
170 {
171 index = entry.getValue();
172 this.perceptionDelay.put(entry.getKey(),
173 Duration.interpolate(tauMin, tauMax, matrix.getDeterioration(index)).divide(tc));
174 double att = matrix.getAttention(index);
175 maxAttention = Double.max(maxAttention, att);
176 this.attention.put(entry.getKey(), att);
177 }
178
179
180 double ts = sumTaskDemand / tc;
181 parameters.setClaimedParameter(EST_FACTOR, Math.pow(Math.max(ts, 1.0), parameters.getParameter(OVER_EST)), this);
182 parameters.setClaimedParameter(ATT, maxAttention, this);
183 return sumTaskDemand;
184
185
186
187 }
188
189 @Override
190 public ImmutableSet<ChannelTask> getTasks()
191 {
192 return new ImmutableLinkedHashSet<ChannelTask>(this.tasks, Immutable.WRAP);
193 }
194
195 @Override
196 public Optional<Task> getTask(final String taskId)
197 {
198 return Optional.ofNullable(this.taskMap.get(taskId));
199 }
200
201
202
203
204
205 public void addTaskSupplier(final Function<LanePerception, Set<ChannelTask>> taskSupplier)
206 {
207 this.taskSuppliers.add(taskSupplier);
208 }
209
210
211
212
213
214 public void removeTaskSupplier(final Function<LanePerception, Set<ChannelTask>> taskSupplier)
215 {
216 this.taskSuppliers.remove(taskSupplier);
217 }
218
219 @Override
220 public Duration getPerceptionDelay(final Object obj)
221 {
222 return this.perceptionDelay.get(getChannel(obj));
223 }
224
225 @Override
226 public double getAttention(final Object obj)
227 {
228 return this.attention.get(getChannel(obj));
229 }
230
231 @Override
232 public void mapToChannel(final Object obj, final Object channel)
233 {
234 this.channelMapping.put(obj, channel);
235 }
236
237
238
239
240
241
242
243 private Object getChannel(final Object obj)
244 {
245 if (this.channelMapping.containsKey(obj))
246 {
247 return this.channelMapping.get(obj);
248 }
249 Throw.when(!this.perceptionDelay.containsKey(obj), IllegalArgumentException.class, "Channel %s is not present.", obj);
250 return obj;
251 }
252
253
254
255
256
257 public Set<Object> getChannels()
258 {
259 return new LinkedHashSet<>(this.attention.keySet());
260 }
261
262 }