View Javadoc
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.ValueException;
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-2019 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} (&le; {@code time})
69       * @param frequency1 Frequency; frequency at {@code time1}
70       * @param time1 Time; time of {@code frequency1} (&gt; {@code time})
71       * @param time Time; {@code time0} &le; {@code time} &lt; {@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} (&le; {@code time})
80       * @param frequency1 Frequency; frequency at {@code time1}
81       * @param time1 Time; time of {@code frequency1} (&gt; {@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 (ValueException 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 }