1 package org.opentrafficsim.road.od;
2
3 import java.util.LinkedHashMap;
4 import java.util.Map;
5
6 import org.djunits.value.vdouble.scalar.Frequency;
7 import org.djunits.value.vdouble.scalar.Length;
8 import org.djutils.exceptions.Throw;
9 import org.opentrafficsim.core.gtu.GtuErrorHandler;
10 import org.opentrafficsim.core.gtu.GtuType;
11 import org.opentrafficsim.core.idgenerator.IdGenerator;
12 import org.opentrafficsim.core.network.LinkType;
13 import org.opentrafficsim.core.network.Node;
14 import org.opentrafficsim.road.gtu.generator.CfBaRoomChecker;
15 import org.opentrafficsim.road.gtu.generator.GeneratorPositions.LaneBiases;
16 import org.opentrafficsim.road.gtu.generator.LaneBasedGtuGenerator.RoomChecker;
17 import org.opentrafficsim.road.gtu.generator.MarkovCorrelation;
18 import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGtuCharacteristicsGeneratorOd;
19 import org.opentrafficsim.road.gtu.generator.headway.ArrivalsHeadwayGenerator.HeadwayDistribution;
20 import org.opentrafficsim.road.network.lane.Lane;
21
22 /**
23 * Options for vehicle generation based on an OD matrix.
24 * <p>
25 * Copyright (c) 2013-2023 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
26 * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
27 * </p>
28 * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
29 * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
30 * @author <a href="https://dittlab.tudelft.nl">Wouter Schakel</a>
31 */
32 public class OdOptions
33 {
34 /** Headway randomization option. */
35 public static final Option<HeadwayDistribution> HEADWAY_DIST =
36 new Option<>("headway distribution", HeadwayDistribution.EXPONENTIAL);
37
38 /** ID generator option. */
39 public static final Option<IdGenerator> GTU_ID = new Option<>("gtu id", new IdGenerator(""));
40
41 /** GTU characteristics generator option. */
42 public static final Option<LaneBasedGtuCharacteristicsGeneratorOd> GTU_TYPE = new Option<>("gtu type", null);
43
44 /** Room checker option. */
45 public static final Option<RoomChecker> ROOM_CHECKER = new Option<>("room checker", new CfBaRoomChecker());
46
47 /** Markov chain for GTU type option. */
48 public static final Option<MarkovCorrelation<GtuType, Frequency>> MARKOV = new Option<>("markov", null);
49
50 /** Initial distance over which lane changes shouldn't be performed option. */
51 public static final Option<Length> NO_LC_DIST = new Option<>("no lc distance", null);
52
53 /** Whether to perform instantaneous lane changes. */
54 public static final Option<Boolean> INSTANT_LC = new Option<>("instant lc", false);
55
56 /** Error handler when GTU exceptions occur. */
57 public static final Option<GtuErrorHandler> ERROR_HANDLER = new Option<>("error handler", GtuErrorHandler.THROW);
58
59 /** Lane bias. Default is none, i.e. uniform distribution over lanes for all GTU types. */
60 public static final Option<LaneBiases> LANE_BIAS = new Option<>("lane bias", new LaneBiases());
61
62 /** Options overall. */
63 private OptionSet<Void> options = new OptionSet<>();
64
65 /** Options per lane. */
66 private OptionSet<Lane> laneOptions = new OptionSet<>();
67
68 /** Options per node. */
69 private OptionSet<Node> nodeOptions = new OptionSet<>();
70
71 /** Options per road type. */
72 private OptionSet<LinkType> linkTypeOptions = new OptionSet<>();
73
74 /**
75 * Set option value.
76 * @param option Option<K>; option
77 * @param value K; option value
78 * @param <K> value type
79 * @return this option set
80 */
81 public final <K> OdOptions set(final Option<K> option, final K value)
82 {
83 this.options.set(null, option, value);
84 return this;
85 }
86
87 /**
88 * Set option value for lane.
89 * @param lane Lane; lane
90 * @param option Option<K>; option
91 * @param value K; option value
92 * @param <K> value type
93 * @return this option set
94 */
95 public final <K> OdOptions set(final Lane lane, final Option<K> option, final K value)
96 {
97 this.laneOptions.set(lane, option, value);
98 return this;
99 }
100
101 /**
102 * Set option value for node.
103 * @param node Node; node
104 * @param option Option<K>; option
105 * @param value K; option value
106 * @param <K> value type
107 * @return this option set
108 */
109 public final <K> OdOptions set(final Node node, final Option<K> option, final K value)
110 {
111 this.nodeOptions.set(node, option, value);
112 return this;
113 }
114
115 /**
116 * Set option value for link type.
117 * @param linkType LinkType; link type
118 * @param option Option<K>; option
119 * @param value K; option value
120 * @param <K> value type
121 * @return this option set
122 */
123 public final <K> OdOptions set(final LinkType linkType, final Option<K> option, final K value)
124 {
125 this.linkTypeOptions.set(linkType, option, value);
126 return this;
127 }
128
129 /**
130 * Get option value. If a value is specified for a specific category, it is returned. The following order is used:
131 * <ul>
132 * <li>{@code Lane}</li>
133 * <li>{@code Node} (origin)</li>
134 * <li>{@code LinkType}</li>
135 * <li>None (global option value)</li>
136 * <li>Default option value</li>
137 * </ul>
138 * @param option Option<K>; option
139 * @param lane Lane; lane to obtain specific option value, may be null
140 * @param node Node; node to obtain specific option value, may be null
141 * @param linkType LinkType; link type to obtain specific option value, may be null
142 * @param <K> value type
143 * @return K; option value
144 */
145 public final <K> K get(final Option<K> option, final Lane lane, final Node node, final LinkType linkType)
146 {
147 Throw.whenNull(option, "Option may not be null.");
148 K value = this.laneOptions.get(lane, option);
149 if (value != null)
150 {
151 return value;
152 }
153 value = this.nodeOptions.get(node, option);
154 if (value != null)
155 {
156 return value;
157 }
158 value = this.linkTypeOptions.get(linkType, option);
159 if (value != null)
160 {
161 return value;
162 }
163 value = this.options.get(null, option);
164 if (value != null)
165 {
166 return value;
167 }
168 return option.getDefaultValue();
169 }
170
171 /**
172 * Utility class to store options.
173 * <p>
174 * Copyright (c) 2013-2023 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
175 * <br>
176 * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
177 * </p>
178 * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
179 * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
180 * @author <a href="https://dittlab.tudelft.nl">Wouter Schakel</a>
181 * @param <K> option value type
182 */
183 public static final class Option<K>
184 {
185
186 /** Id. */
187 private final String id;
188
189 /** Default value. */
190 private final K defaultValue;
191
192 /**
193 * Constructor.
194 * @param id String; id
195 * @param defaultValue K; default value
196 */
197 Option(final String id, final K defaultValue)
198 {
199 this.id = id;
200 this.defaultValue = defaultValue;
201 }
202
203 /**
204 * Returns the default value.
205 * @return default value
206 */
207 public K getDefaultValue()
208 {
209 return this.defaultValue;
210 }
211
212 /** {@inheritDoc} */
213 @Override
214 public int hashCode()
215 {
216 final int prime = 31;
217 int result = 1;
218 result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
219 return result;
220 }
221
222 /** {@inheritDoc} */
223 @Override
224 public boolean equals(final Object obj)
225 {
226 if (this == obj)
227 {
228 return true;
229 }
230 if (obj == null)
231 {
232 return false;
233 }
234 if (getClass() != obj.getClass())
235 {
236 return false;
237 }
238 Option<?> other = (Option<?>) obj;
239 if (this.id == null)
240 {
241 if (other.id != null)
242 {
243 return false;
244 }
245 }
246 else if (!this.id.equals(other.id))
247 {
248 return false;
249 }
250 return true;
251 }
252
253 /** {@inheritDoc} */
254 @Override
255 public String toString()
256 {
257 return "Option [id=" + this.id + "]";
258 }
259
260 }
261
262 /**
263 * Single set of options for a certain category, i.e. lane, node, link type or null (i.e. global).
264 * <p>
265 * Copyright (c) 2013-2023 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
266 * <br>
267 * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
268 * </p>
269 * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
270 * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
271 * @author <a href="https://dittlab.tudelft.nl">Wouter Schakel</a>
272 * @param <C> category type, i.e. {@code Lane}, {@code Node}, {@code LinkType} or {@code Void} (i.e. global).
273 */
274 private class OptionSet<C>
275 {
276
277 /** Options. */
278 private Map<C, Map<Option<?>, Object>> optionsSet = new LinkedHashMap<>();
279
280 /**
281 * Constructor.
282 */
283 OptionSet()
284 {
285 //
286 }
287
288 /**
289 * Set value in option set.
290 * @param category C; category
291 * @param option Option<K>; option
292 * @param value K; value
293 * @param <K> option value type
294 */
295 public <K> void set(final C category, final Option<K> option, final K value)
296 {
297 Map<Option<?>, Object> map = this.optionsSet.get(category);
298 if (map == null)
299 {
300 map = new LinkedHashMap<>();
301 this.optionsSet.put(category, map);
302 }
303 map.put(option, value);
304 }
305
306 /**
307 * Returns the option value for the category.
308 * @param category C; category
309 * @param option Option<K>; option
310 * @return option value for the category
311 * @param <K> value type
312 */
313 @SuppressWarnings("unchecked")
314 public <K> K get(final C category, final Option<K> option)
315 {
316 if (!this.optionsSet.containsKey(category))
317 {
318 return null;
319 }
320 return (K) this.optionsSet.get(category).get(option);
321 }
322
323 }
324
325 }