1 package org.opentrafficsim.road.network.factory.xml.demand;
2
3 import java.io.Serializable;
4 import java.util.ArrayList;
5 import java.util.LinkedHashSet;
6 import java.util.List;
7
8 import org.djunits.unit.FrequencyUnit;
9 import org.djunits.unit.TimeUnit;
10 import org.djunits.value.StorageType;
11 import org.djunits.value.vdouble.scalar.Time;
12 import org.djunits.value.vdouble.vector.FrequencyVector;
13 import org.djunits.value.vdouble.vector.TimeVector;
14 import org.opentrafficsim.core.gtu.Try;
15 import org.opentrafficsim.core.network.factory.xml.units.DurationUnits;
16 import org.opentrafficsim.core.network.factory.xml.units.TimeUnits;
17 import org.opentrafficsim.road.gtu.strategical.od.Category;
18 import org.opentrafficsim.road.gtu.strategical.od.Interpolation;
19 import org.opentrafficsim.road.network.factory.xml.XMLParser;
20 import org.opentrafficsim.road.network.factory.xml.XmlParserException;
21 import org.w3c.dom.NamedNodeMap;
22 import org.w3c.dom.Node;
23 import org.w3c.dom.NodeList;
24
25 import nl.tudelft.simulation.language.Throw;
26
27
28
29
30
31
32
33
34
35
36
37
38
39 public class DemandTag implements Serializable
40 {
41
42
43 private static final long serialVersionUID = 20180525L;
44
45
46 private final static FrequencyUnit UNIT = FrequencyUnit.PER_HOUR;
47
48
49 org.opentrafficsim.core.network.Node origin;
50
51
52 org.opentrafficsim.core.network.Node destination;
53
54
55 Interpolation interpolation;
56
57
58 Category category;
59
60
61 String categoryName;
62
63
64 DemandType demandType = null;
65
66
67 TimeVector timeVector;
68
69
70 FrequencyVector demandVector;
71
72
73 Double factor;
74
75
76 double[] factors;
77
78
79
80
81
82
83
84 static void parse(final NodeList nodeList, final XmlOdParser parser) throws XmlParserException
85 {
86 for (Node node : XMLParser.getNodesSorted(nodeList, "DEMAND", "ORIGIN", "DESTINATION", "CATEGORY"))
87 {
88 NamedNodeMap attributes = node.getAttributes();
89 DemandTag tag = new DemandTag();
90
91 Node originNode = attributes.getNamedItem("ORIGIN");
92 Throw.when(originNode == null, XmlParserException.class, "Missing ORIGIN attribute in DEMAND tag.");
93 String originId = originNode.getNodeValue().trim();
94 tag.origin = parser.network.getNode(originId);
95 Throw.when(tag.origin == null, XmlParserException.class, "Origin %s is not available.", originId);
96
97 Node destinationNode = attributes.getNamedItem("DESTINATION");
98 Throw.when(destinationNode == null, XmlParserException.class, "Missing DESTINATION attribute in DEMAND tag.");
99 String destinationId = destinationNode.getNodeValue().trim();
100 tag.destination = parser.network.getNode(destinationId);
101 Throw.when(tag.destination == null, XmlParserException.class, "Destination %s is not available.", destinationId);
102
103 Node interpolationNode = attributes.getNamedItem("INTERPOLATION");
104 if (interpolationNode != null)
105 {
106 String interpolation = interpolationNode.getNodeValue().trim();
107 try
108 {
109 tag.interpolation = Interpolation.valueOf(interpolation);
110 }
111 catch (IllegalArgumentException exception)
112 {
113 throw new XmlParserException("INTERPOLATION " + interpolation + " does not exist.", exception);
114 }
115 }
116
117 Node factorNode = attributes.getNamedItem("FACTOR");
118 if (factorNode != null)
119 {
120 tag.factor = parseFactor(factorNode.getNodeValue().trim());
121 }
122
123 Node categoryNode = attributes.getNamedItem("CATEGORY");
124 if (categoryNode != null)
125 {
126 String categoryName = categoryNode.getNodeValue().trim();
127 Throw.when(!parser.categories.containsKey(categoryName), XmlParserException.class,
128 "Category %s is not available.", categoryName);
129 tag.category = parser.categories.get(categoryName).getCategory(parser.categorization);
130 tag.factor = XmlOdParser.nullMultiply(tag.factor, parser.categories.get(categoryName).factor);
131 }
132
133 NodeList childList = node.getChildNodes();
134 List<Double> timeList = new ArrayList<>();
135 List<Double> valueList = new ArrayList<>();
136 List<Node> demandNodes = XMLParser.getNodes(childList, "LEVEL");
137 Throw.when(categoryNode == null && demandNodes.isEmpty(), XmlParserException.class,
138 "DEMAND without CATEGORY attribute should contain demand data.");
139 if (demandNodes.size() == 0)
140 {
141 tag.demandType = DemandType.FACTOR;
142 }
143 for (Node level : demandNodes)
144 {
145 if (tag.demandType == null)
146 {
147 tag.demandType = DemandType.fromLevelNode(level);
148 Throw.when(
149 categoryNode == null && !tag.demandType.equals(DemandType.FREQUENCIES)
150 && !tag.demandType.equals(DemandType.TIMED_FREQUENCIES),
151 XmlParserException.class,
152 "DEMAND without CATEGORY attribute should contain non-factoral demand data.");
153 }
154 NamedNodeMap levelAttributes = level.getAttributes();
155 if (tag.demandType.equals(DemandType.TIMED_FACTORS) || tag.demandType.equals(DemandType.TIMED_FREQUENCIES))
156 {
157 Node timeNode = levelAttributes.getNamedItem("TIME");
158 Throw.when(timeNode == null, XmlParserException.class, "A LEVEL tag is missing attribute TIME.");
159 String timeString = timeNode.getNodeValue().trim();
160 Time time = Try.assign(() -> TimeUnits.parseTime(timeString), XmlParserException.class,
161 "Unable to parse %s as time.", timeString);
162 timeList.add(time.si);
163 }
164 Node valueNode = levelAttributes.getNamedItem("VALUE");
165 Throw.when(valueNode == null, XmlParserException.class, "A LEVEL tag is missing attribute VALUE.");
166 if (tag.demandType.equals(DemandType.TIMED_FACTORS) || tag.demandType.equals(DemandType.FACTORS))
167 {
168 valueList.add(parseFactor(valueNode.getNodeValue().trim()));
169 }
170 if (tag.demandType.equals(DemandType.TIMED_FREQUENCIES) || tag.demandType.equals(DemandType.FREQUENCIES))
171 {
172 String valueString = valueNode.getNodeValue().trim().toLowerCase();
173 valueList.add(Try.assign(() -> DurationUnits.parseFrequency(valueString.replace("veh", "")).getInUnit(UNIT),
174 "Unable to parse %s as frequency.", valueString));
175 }
176 }
177
178 if (tag.demandType.equals(DemandType.TIMED_FACTORS) || tag.demandType.equals(DemandType.TIMED_FREQUENCIES))
179 {
180 tag.timeVector = Try.assign(
181 () -> new TimeVector(timeList.stream().mapToDouble(d -> d).toArray(), TimeUnit.BASE, StorageType.DENSE),
182 "Unexpected exception while converting list of time values to an array.");
183 }
184
185 if (tag.demandType.equals(DemandType.TIMED_FACTORS) || tag.demandType.equals(DemandType.FACTORS))
186 {
187 tag.factors = valueList.stream().mapToDouble(d -> d).toArray();
188 }
189 else if (tag.demandType.equals(DemandType.TIMED_FREQUENCIES) || tag.demandType.equals(DemandType.FREQUENCIES))
190 {
191 tag.demandVector = Try.assign(
192 () -> new FrequencyVector(valueList.stream().mapToDouble(d -> d).toArray(), UNIT, StorageType.DENSE),
193 "Unexpected exception while converting list of time values to an array.");
194 }
195
196 parser.demand.getValue(() -> new LinkedHashSet<>(), tag.origin, tag.destination).add(tag);
197 }
198 }
199
200
201
202
203
204
205
206 public static double parseFactor(final String value) throws XmlParserException
207 {
208 double f;
209 if (value.endsWith("%"))
210 {
211 f = Double.parseDouble(value.substring(0, value.length() - 1).trim()) / 100.0;
212 }
213 else
214 {
215 f = Double.parseDouble(value);
216 }
217 Throw.when(f < 0.0, XmlParserException.class, "Factor %d is not positive.", f);
218 return f;
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234 public enum DemandType
235 {
236
237 FACTOR,
238
239
240 FACTORS,
241
242
243 TIMED_FACTORS,
244
245
246 FREQUENCIES,
247
248
249 TIMED_FREQUENCIES;
250
251
252
253
254
255
256
257 public static DemandType fromLevelNode(final Node level) throws XmlParserException
258 {
259 NamedNodeMap attributes = level.getAttributes();
260 Node timeNode = attributes.getNamedItem("TIME");
261 Node valueNode = attributes.getNamedItem("VALUE");
262 Throw.when(valueNode == null, XmlParserException.class, "LEVEL tag in DEMAND is missing attribute VALUE.");
263 boolean frequency = valueNode.getNodeValue().trim().toLowerCase().contains("veh");
264 if (timeNode != null)
265 {
266 if (frequency)
267 {
268 return TIMED_FREQUENCIES;
269 }
270 return TIMED_FACTORS;
271 }
272 if (frequency)
273 {
274 return FREQUENCIES;
275 }
276 return FACTORS;
277 }
278
279 }
280
281 }