Interpolation.java

  1. package org.opentrafficsim.road.od;

  2. import org.djunits.unit.FrequencyUnit;
  3. import org.djunits.unit.TimeUnit;
  4. import org.djunits.value.ValueRuntimeException;
  5. import org.djunits.value.vdouble.scalar.Frequency;
  6. import org.djunits.value.vdouble.scalar.Time;
  7. import org.djunits.value.vdouble.vector.FrequencyVector;
  8. import org.djunits.value.vdouble.vector.TimeVector;

  9. /**
  10.  * Interpolation of demand.
  11.  * <p>
  12.  * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  13.  * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
  14.  * </p>
  15.  * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
  16.  * @author <a href="https://github.com/peter-knoppers">Peter Knoppers</a>
  17.  * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
  18.  */
  19. public enum Interpolation
  20. {

  21.     /** Stepwise interpolation of demand. */
  22.     STEPWISE
  23.     {
  24.         @Override
  25.         Frequency interpolate(final Frequency frequency0, final Time time0, final Frequency frequency1, final Time time1,
  26.                 final Time time)
  27.         {
  28.             return frequency0;
  29.         }

  30.         @Override
  31.         int integrate(final Frequency frequency0, final Time time0, final Frequency frequency1, final Time time1)
  32.         {
  33.             return (int) (frequency0.getInUnit(FrequencyUnit.PER_HOUR)
  34.                     * (time1.getInUnit(TimeUnit.BASE_HOUR) - time0.getInUnit(TimeUnit.BASE_HOUR)));
  35.         }

  36.         @Override
  37.         public String toString()
  38.         {
  39.             return "STEPWISE";
  40.         }
  41.     },

  42.     /** Linear interpolation of demand. */
  43.     LINEAR
  44.     {
  45.         @Override
  46.         Frequency interpolate(final Frequency frequency0, final Time time0, final Frequency frequency1, final Time time1,
  47.                 final Time time)
  48.         {
  49.             return Frequency.interpolate(frequency0, frequency1, (time.si - time0.si) / (time1.si - time0.si));
  50.         }

  51.         @Override
  52.         int integrate(final Frequency frequency0, final Time time0, final Frequency frequency1, final Time time1)
  53.         {
  54.             return (int) (0.5 * (frequency0.getInUnit(FrequencyUnit.PER_HOUR) + frequency1.getInUnit(FrequencyUnit.PER_HOUR))
  55.                     * (time1.getInUnit(TimeUnit.BASE_HOUR) - time0.getInUnit(TimeUnit.BASE_HOUR)));
  56.         }

  57.         @Override
  58.         public String toString()
  59.         {
  60.             return "LINEAR";
  61.         }
  62.     };

  63.     /**
  64.      * Interpolate between given frequencies.
  65.      * @param frequency0 frequency at {@code time0}
  66.      * @param time0 time of {@code frequency0} (&le; {@code time})
  67.      * @param frequency1 frequency at {@code time1}
  68.      * @param time1 time of {@code frequency1} (&gt; {@code time})
  69.      * @param time {@code time0} &le; {@code time} &lt; {@code time1}
  70.      * @return interpolated frequency
  71.      */
  72.     abstract Frequency interpolate(Frequency frequency0, Time time0, Frequency frequency1, Time time1, Time time);

  73.     /**
  74.      * Integrates to the number of trips in given period.
  75.      * @param frequency0 frequency at {@code time0}
  76.      * @param time0 time of {@code frequency0} (&le; {@code time})
  77.      * @param frequency1 frequency at {@code time1}
  78.      * @param time1 time of {@code frequency1} (&gt; {@code time})
  79.      * @return number of trips in given period
  80.      */
  81.     abstract int integrate(Frequency frequency0, Time time0, Frequency frequency1, Time time1);

  82.     /**
  83.      * @return whether this is step-wise interpolation
  84.      */
  85.     public boolean isStepWise()
  86.     {
  87.         return this.equals(STEPWISE);
  88.     }

  89.     /**
  90.      * @return whether this is linear interpolation
  91.      */
  92.     public boolean isLinear()
  93.     {
  94.         return this.equals(LINEAR);
  95.     }

  96.     /**
  97.      * Returns interpolated value from array at given time. If time is outside of the vector range, 0 is returned.
  98.      * @param time time to determine the frequency at
  99.      * @param demandVector demand vector
  100.      * @param timeVector time vector
  101.      * @param sliceStart whether the time is at the start of an arbitrary time slice
  102.      * @return interpolated value from array at given time, or 0 when time is outside of range
  103.      */
  104.     public final Frequency interpolateVector(final Time time, final FrequencyVector demandVector, final TimeVector timeVector,
  105.             final boolean sliceStart)
  106.     {
  107.         try
  108.         {
  109.             // empty data or before start or after end, return 0
  110.             // case 1: t < t(0)
  111.             // case 2: sliceEnd & t == t(0), i.e. end of no-demand time before time array
  112.             // case 3: sliceStart & t == t(end), i.e. start of no-demand time after time array
  113.             // case 4: t > t(end)
  114.             if (timeVector.size() == 0 || (sliceStart ? time.lt(timeVector.get(0)) : time.le(timeVector.get(0))) || (sliceStart
  115.                     ? time.ge(timeVector.get(timeVector.size() - 1)) : time.gt(timeVector.get(timeVector.size() - 1))))
  116.             {
  117.                 return new Frequency(0.0, FrequencyUnit.PER_HOUR); // Frequency.ZERO give "Hz" which is not nice for flow
  118.             }
  119.             // interpolate
  120.             for (int i = 0; i < timeVector.size() - 1; i++)
  121.             {
  122.                 // cases where we can take the slice from i to i+1
  123.                 // case 1: sliceStart & t(i+1) > t [edge case: t(i) = t]
  124.                 // case 2: sliceEnd & t(i+1) >= t [edge case: t(i+1) = t]
  125.                 if (sliceStart ? timeVector.get(i + 1).gt(time) : timeVector.get(i + 1).ge(time))
  126.                 {
  127.                     return interpolate(demandVector.get(i), timeVector.get(i), demandVector.get(i + 1), timeVector.get(i + 1),
  128.                             time);
  129.                 }
  130.             }
  131.         }
  132.         catch (ValueRuntimeException ve)
  133.         {
  134.             // should not happen, vector lengths are checked when given is input
  135.             throw new RuntimeException("Index out of bounds.", ve);
  136.         }
  137.         // should not happen
  138.         throw new RuntimeException("Demand interpolation failed.");
  139.     }

  140. }