1 package org.opentrafficsim.road.od;
2
3 import java.util.Iterator;
4 import java.util.LinkedHashMap;
5 import java.util.Map;
6 import java.util.TreeMap;
7
8 import org.djunits.unit.DurationUnit;
9 import org.djunits.value.ValueRuntimeException;
10 import org.djunits.value.vdouble.scalar.Duration;
11 import org.djunits.value.vdouble.vector.DurationVector;
12 import org.djutils.exceptions.Throw;
13 import org.opentrafficsim.base.OtsRuntimeException;
14 import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
15 import org.opentrafficsim.core.gtu.GtuType;
16 import org.opentrafficsim.core.math.Draw;
17 import org.opentrafficsim.core.network.Link;
18 import org.opentrafficsim.core.network.Node;
19 import org.opentrafficsim.road.network.lane.CrossSectionLink;
20
21 import nl.tudelft.simulation.jstats.streams.StreamInterface;
22
23
24
25
26
27
28
29
30
31
32
33 public class SplitFraction
34 {
35
36
37 private final Node node;
38
39
40 private final Interpolation interpolation;
41
42
43 private final StreamInterface random;
44
45
46 private final OtsSimulatorInterface simulator;
47
48
49 private final Map<GtuType, Map<Link, Map<Duration, Double>>> fractions = new LinkedHashMap<>();
50
51
52
53
54
55
56
57
58 public SplitFraction(final Node node, final Interpolation interpolation, final StreamInterface random,
59 final OtsSimulatorInterface simulator)
60 {
61 this.node = node;
62 this.interpolation = interpolation;
63 this.random = random;
64 this.simulator = simulator;
65 }
66
67
68
69
70
71
72
73 public void addFraction(final Link link, final GtuType gtuType, final double fraction)
74 {
75 double[] fracs = new double[2];
76 fracs[0] = fraction;
77 fracs[1] = fraction;
78 DurationVector time;
79 try
80 {
81 double[] t = new double[2];
82 t[1] = Double.MAX_VALUE;
83 time = new DurationVector(t, DurationUnit.SI);
84 }
85 catch (ValueRuntimeException exception)
86 {
87
88 throw new OtsRuntimeException("Input null while creating duration vector.", exception);
89 }
90 addFraction(link, gtuType, time, fracs);
91 }
92
93
94
95
96
97
98
99
100 public void addFraction(final Link link, final GtuType gtuType, final DurationVector time, final double[] fraction)
101 {
102 Throw.when(time.size() != fraction.length, IllegalArgumentException.class,
103 "Time vector and fraction array require equal length.");
104 Throw.when(!this.node.getLinks().contains(link), IllegalArgumentException.class, "Link %s is not connected to node %s.",
105 link, this.node);
106 for (double f : fraction)
107 {
108 Throw.when(f < 0.0, IllegalArgumentException.class, "Fraction should be larger than 0.0.");
109 }
110 if (this.fractions.containsKey(gtuType))
111 {
112 this.fractions.put(gtuType, new LinkedHashMap<>());
113 }
114 this.fractions.get(gtuType).put(link, new TreeMap<>());
115 for (int i = 0; i <= time.size(); i++)
116 {
117 try
118 {
119 this.fractions.get(gtuType).get(link).put(time.get(i), fraction[i]);
120 }
121 catch (ValueRuntimeException exception)
122 {
123
124 throw new OtsRuntimeException("Index out of range.", exception);
125 }
126 }
127 }
128
129
130
131
132
133
134
135 public Link draw(final GtuType gtuType)
136 {
137 for (GtuType gtu : this.fractions.keySet())
138 {
139 if (gtuType.isOfType(gtu))
140 {
141 Map<Link, Double> currentFractions = new LinkedHashMap<>();
142 double t = this.simulator.getSimulatorTime().si;
143 for (Link link : this.fractions.get(gtu).keySet())
144 {
145 Iterator<Duration> iterator = this.fractions.get(gtu).get(link).keySet().iterator();
146 Duration prev = iterator.next();
147 while (iterator.hasNext())
148 {
149 Duration next = iterator.next();
150 if (prev.si <= t && t < next.si)
151 {
152
153 double f;
154 if (this.interpolation.equals(Interpolation.STEPWISE))
155 {
156 f = this.fractions.get(gtuType).get(link).get(prev);
157 }
158 else
159 {
160 double r = (t - prev.si) / (next.si - prev.si);
161 f = (1 - r) * this.fractions.get(gtuType).get(link).get(prev)
162 + r * this.fractions.get(gtuType).get(link).get(next);
163 }
164 currentFractions.put(link, f);
165 break;
166 }
167 }
168 }
169 return Draw.drawWeighted(currentFractions, this.random);
170 }
171 }
172
173 boolean fractionAdded = false;
174 for (Link link : this.node.getLinks())
175 {
176 if ((link.getStartNode().equals(this.node)))
177 {
178 if (link instanceof CrossSectionLink)
179 {
180 int n = ((CrossSectionLink) link).getLanes().size();
181 if (n > 0)
182 {
183 fractionAdded = true;
184 addFraction(link, gtuType, n);
185 }
186 }
187 else
188 {
189 fractionAdded = true;
190 addFraction(link, gtuType, 1.0);
191 }
192 }
193 }
194 Throw.when(!fractionAdded, UnsupportedOperationException.class,
195 "Split fraction on node %s cannot be derived for gtuType %s as there are no outgoing links.", this.node,
196 gtuType);
197
198 return draw(gtuType);
199 }
200
201 @Override
202 public int hashCode()
203 {
204 final int prime = 31;
205 int result = 1;
206 result = prime * result + ((this.fractions == null) ? 0 : this.fractions.hashCode());
207 result = prime * result + ((this.node == null) ? 0 : this.node.hashCode());
208 return result;
209 }
210
211 @Override
212 public boolean equals(final Object obj)
213 {
214 if (this == obj)
215 {
216 return true;
217 }
218 if (obj == null)
219 {
220 return false;
221 }
222 if (getClass() != obj.getClass())
223 {
224 return false;
225 }
226 SplitFraction other = (SplitFraction) obj;
227 if (this.fractions == null)
228 {
229 if (other.fractions != null)
230 {
231 return false;
232 }
233 }
234 else if (!this.fractions.equals(other.fractions))
235 {
236 return false;
237 }
238 if (this.node == null)
239 {
240 if (other.node != null)
241 {
242 return false;
243 }
244 }
245 else if (!this.node.equals(other.node))
246 {
247 return false;
248 }
249 return true;
250 }
251
252 @Override
253 public String toString()
254 {
255 return "SplitFraction [node=" + this.node + ", fractions=" + this.fractions + "]";
256 }
257
258 }