1 package org.opentrafficsim.road.gtu.strategical.od;
2
3 import org.djunits.unit.FrequencyUnit;
4 import org.djunits.unit.TimeUnit;
5 import org.djunits.value.ValueRuntimeException;
6 import org.djunits.value.vdouble.scalar.Frequency;
7 import org.djunits.value.vdouble.scalar.Time;
8 import org.djunits.value.vdouble.vector.FrequencyVector;
9 import org.djunits.value.vdouble.vector.TimeVector;
10
11 /**
12 * Interpolation of demand.
13 * <p>
14 * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
15 * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
16 * <p>
17 * @version $Revision$, $LastChangedDate$, by $Author$, initial version Sep 15, 2016 <br>
18 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
19 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
20 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
21 */
22 public enum Interpolation
23 {
24
25 /** Stepwise interpolation of demand. */
26 STEPWISE
27 {
28 /** {@inheritDoc} */
29 @Override
30 Frequency interpolate(final Frequency frequency0, final Time time0, final Frequency frequency1, final Time time1,
31 final Time time)
32 {
33 return frequency0;
34 }
35
36 /** {@inheritDoc} */
37 @Override
38 int integrate(final Frequency frequency0, final Time time0, final Frequency frequency1, final Time time1)
39 {
40 return (int) (frequency0.getInUnit(FrequencyUnit.PER_HOUR)
41 * (time1.getInUnit(TimeUnit.BASE_HOUR) - time0.getInUnit(TimeUnit.BASE_HOUR)));
42 }
43 },
44
45 /** Linear interpolation of demand. */
46 LINEAR
47 {
48 /** {@inheritDoc} */
49 @Override
50 Frequency interpolate(final Frequency frequency0, final Time time0, final Frequency frequency1, final Time time1,
51 final Time time)
52 {
53 return Frequency.interpolate(frequency0, frequency1, (time.si - time0.si) / (time1.si - time0.si));
54 }
55
56 /** {@inheritDoc} */
57 @Override
58 int integrate(final Frequency frequency0, final Time time0, final Frequency frequency1, final Time time1)
59 {
60 return (int) (0.5 * (frequency0.getInUnit(FrequencyUnit.PER_HOUR) + frequency1.getInUnit(FrequencyUnit.PER_HOUR))
61 * (time1.getInUnit(TimeUnit.BASE_HOUR) - time0.getInUnit(TimeUnit.BASE_HOUR)));
62 }
63 };
64
65 /**
66 * Interpolate between given frequencies.
67 * @param frequency0 Frequency; frequency at {@code time0}
68 * @param time0 Time; time of {@code frequency0} (≤ {@code time})
69 * @param frequency1 Frequency; frequency at {@code time1}
70 * @param time1 Time; time of {@code frequency1} (> {@code time})
71 * @param time Time; {@code time0} ≤ {@code time} < {@code time1}
72 * @return interpolated frequency
73 */
74 abstract Frequency interpolate(Frequency frequency0, Time time0, Frequency frequency1, Time time1, Time time);
75
76 /**
77 * Integrates to the number of trips in given period.
78 * @param frequency0 Frequency; frequency at {@code time0}
79 * @param time0 Time; time of {@code frequency0} (≤ {@code time})
80 * @param frequency1 Frequency; frequency at {@code time1}
81 * @param time1 Time; time of {@code frequency1} (> {@code time})
82 * @return number of trips in given period
83 */
84 abstract int integrate(Frequency frequency0, Time time0, Frequency frequency1, Time time1);
85
86 /**
87 * @return whether this is step-wise interpolation
88 */
89 public boolean isStepWise()
90 {
91 return this.equals(STEPWISE);
92 }
93
94 /**
95 * @return whether this is linear interpolation
96 */
97 public boolean isLinear()
98 {
99 return this.equals(LINEAR);
100 }
101
102 /**
103 * Returns interpolated value from array at given time. If time is outside of the vector range, 0 is returned.
104 * @param time Time; time to determine the frequency at
105 * @param demandVector FrequencyVector; demand vector
106 * @param timeVector TimeVector; time vector
107 * @param sliceStart boolean; whether the time is at the start of an arbitrary time slice
108 * @return interpolated value from array at given time, or 0 when time is outside of range
109 */
110 public final Frequency interpolateVector(final Time time, final FrequencyVector demandVector, final TimeVector timeVector,
111 final boolean sliceStart)
112 {
113 try
114 {
115 // empty data or before start or after end, return 0
116 // case 1: t < t(0)
117 // case 2: sliceEnd & t == t(0), i.e. end of no-demand time before time array
118 // case 3: sliceStart & t == t(end), i.e. start of no-demand time after time array
119 // case 4: t > t(end)
120 if (timeVector.size() == 0 || (sliceStart ? time.lt(timeVector.get(0)) : time.le(timeVector.get(0))) || (sliceStart
121 ? time.ge(timeVector.get(timeVector.size() - 1)) : time.gt(timeVector.get(timeVector.size() - 1))))
122 {
123 return new Frequency(0.0, FrequencyUnit.PER_HOUR); // Frequency.ZERO give "Hz" which is not nice for flow
124 }
125 // interpolate
126 for (int i = 0; i < timeVector.size() - 1; i++)
127 {
128 // cases where we can take the slice from i to i+1
129 // case 1: sliceStart & t(i+1) > t [edge case: t(i) = t]
130 // case 2: sliceEnd & t(i+1) >= t [edge case: t(i+1) = t]
131 if (sliceStart ? timeVector.get(i + 1).gt(time) : timeVector.get(i + 1).ge(time))
132 {
133 return interpolate(demandVector.get(i), timeVector.get(i), demandVector.get(i + 1), timeVector.get(i + 1),
134 time);
135 }
136 }
137 }
138 catch (ValueRuntimeException ve)
139 {
140 // should not happen, vector lengths are checked when given is input
141 throw new RuntimeException("Index out of bounds.", ve);
142 }
143 // should not happen
144 throw new RuntimeException("Demand interpolation failed.");
145 }
146
147 }