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