AbstractTimeInterpolator.java

  1. /* Copyright 2002-2023 CS GROUP
  2.  * Licensed to CS GROUP (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.time;

  18. import org.hipparchus.util.FastMath;
  19. import org.orekit.errors.OrekitIllegalArgumentException;
  20. import org.orekit.errors.OrekitMessages;
  21. import org.orekit.utils.ImmutableTimeStampedCache;

  22. import java.util.Collection;
  23. import java.util.Collections;
  24. import java.util.List;
  25. import java.util.stream.Collectors;
  26. import java.util.stream.Stream;

  27. /**
  28.  * Abstract class for time interpolator.
  29.  *
  30.  * @param <T> interpolated time stamped type
  31.  *
  32.  * @author Vincent Cucchietti
  33.  */
  34. public abstract class AbstractTimeInterpolator<T extends TimeStamped> implements TimeInterpolator<T> {

  35.     /** Default extrapolation time threshold: 1ms. */
  36.     public static final double DEFAULT_EXTRAPOLATION_THRESHOLD_SEC = 1e-3;

  37.     /** Default number of interpolation points. */
  38.     public static final int DEFAULT_INTERPOLATION_POINTS = 2;

  39.     /** The extrapolation threshold beyond which the propagation will fail. */
  40.     private final double extrapolationThreshold;

  41.     /** Neighbor size. */
  42.     private final int interpolationPoints;

  43.     /**
  44.      * Constructor.
  45.      *
  46.      * @param interpolationPoints number of interpolation points
  47.      * @param extrapolationThreshold extrapolation threshold beyond which the propagation will fail
  48.      */
  49.     public AbstractTimeInterpolator(final int interpolationPoints, final double extrapolationThreshold) {
  50.         this.interpolationPoints    = interpolationPoints;
  51.         this.extrapolationThreshold = extrapolationThreshold;
  52.     }

  53.     /**
  54.      * Method checking if given interpolator is compatible with given sample size.
  55.      *
  56.      * @param interpolator interpolator
  57.      * @param sampleSize sample size
  58.      */
  59.     public static void checkInterpolatorCompatibilityWithSampleSize(
  60.             final TimeInterpolator<? extends TimeStamped> interpolator,
  61.             final int sampleSize) {

  62.         // Retrieve all sub-interpolators (or a singleton list with given interpolator if there are no sub-interpolators)
  63.         final List<TimeInterpolator<? extends TimeStamped>> subInterpolators = interpolator.getSubInterpolators();
  64.         for (final TimeInterpolator<? extends TimeStamped> subInterpolator : subInterpolators) {
  65.             if (sampleSize < subInterpolator.getNbInterpolationPoints()) {
  66.                 throw new OrekitIllegalArgumentException(OrekitMessages.NOT_ENOUGH_DATA, sampleSize);
  67.             }
  68.         }
  69.     }

  70.     /** {@inheritDoc} */
  71.     @Override
  72.     public T interpolate(final AbsoluteDate interpolationDate, final Stream<T> sample) {
  73.         return interpolate(interpolationDate, sample.collect(Collectors.toList()));
  74.     }

  75.     /** {@inheritDoc}. */
  76.     @Override
  77.     public T interpolate(final AbsoluteDate interpolationDate, final Collection<T> sample) {
  78.         final InterpolationData interpolationData = new InterpolationData(interpolationDate, sample);
  79.         return interpolate(interpolationData);
  80.     }

  81.     /** {@inheritDoc} */
  82.     public List<TimeInterpolator<? extends TimeStamped>> getSubInterpolators() {
  83.         return Collections.singletonList(this);
  84.     }

  85.     /** {@inheritDoc} */
  86.     public int getNbInterpolationPoints() {
  87.         return interpolationPoints;
  88.     }

  89.     /** {@inheritDoc} */
  90.     public double getExtrapolationThreshold() {
  91.         return extrapolationThreshold;
  92.     }

  93.     /**
  94.      * Add all lowest level sub interpolators to the sub interpolator list.
  95.      *
  96.      * @param subInterpolator optional sub interpolator to add
  97.      * @param subInterpolators list of sub interpolators
  98.      */
  99.     protected void addOptionalSubInterpolatorIfDefined(final TimeInterpolator<? extends TimeStamped> subInterpolator,
  100.                                                        final List<TimeInterpolator<? extends TimeStamped>> subInterpolators) {
  101.         // Add all lowest level sub interpolators
  102.         if (subInterpolator != null) {
  103.             subInterpolators.addAll(subInterpolator.getSubInterpolators());
  104.         }
  105.     }

  106.     /**
  107.      * Interpolate instance from given interpolation data.
  108.      *
  109.      * @param interpolationData interpolation data
  110.      *
  111.      * @return interpolated instance from given interpolation data.
  112.      */
  113.     protected abstract T interpolate(InterpolationData interpolationData);

  114.     /**
  115.      * Get the time parameter which lies between [0:1] by normalizing the difference between interpolating time and previous
  116.      * date by the Δt between tabulated values.
  117.      *
  118.      * @param interpolatingTime time at which we want to interpolate a value (between previous and next tabulated dates)
  119.      * @param previousDate previous tabulated value date
  120.      * @param nextDate next tabulated value date
  121.      *
  122.      * @return time parameter which lies between [0:1]
  123.      */
  124.     protected double getTimeParameter(final AbsoluteDate interpolatingTime,
  125.                                       final AbsoluteDate previousDate,
  126.                                       final AbsoluteDate nextDate) {
  127.         return interpolatingTime.durationFrom(previousDate) / nextDate.getDate().durationFrom(previousDate);
  128.     }

  129.     /**
  130.      * Nested class used to store interpolation data.
  131.      * <p>
  132.      * It makes the interpolator thread safe.
  133.      */
  134.     public class InterpolationData {

  135.         /** Interpolation date. */
  136.         private final AbsoluteDate interpolationDate;

  137.         /** Cached samples. */
  138.         private final ImmutableTimeStampedCache<T> cachedSamples;

  139.         /** Neighbor list around interpolation date. */
  140.         private final List<T> neighborList;

  141.         /**
  142.          * Constructor.
  143.          *
  144.          * @param interpolationDate interpolation date
  145.          * @param sample time stamped sample
  146.          */
  147.         protected InterpolationData(final AbsoluteDate interpolationDate, final Collection<T> sample) {
  148.             // Handle specific case that is not handled by the immutable time stamped cache constructor
  149.             if (sample.size() < 2) {
  150.                 throw new OrekitIllegalArgumentException(OrekitMessages.NOT_ENOUGH_DATA, sample.size());
  151.             }

  152.             // Create immutable time stamped cache
  153.             this.cachedSamples = new ImmutableTimeStampedCache<>(interpolationPoints, sample);

  154.             // Find neighbors
  155.             final AbsoluteDate central         = getCentralDate(interpolationDate);
  156.             final Stream<T>    neighborsStream = cachedSamples.getNeighbors(central);

  157.             // Convert to unmodifiable list
  158.             this.neighborList = Collections.unmodifiableList(neighborsStream.collect(Collectors.toList()));

  159.             // Store interpolation date
  160.             this.interpolationDate = interpolationDate;
  161.         }

  162.         /**
  163.          * Get the central date to use to find neighbors while taking into account extrapolation threshold.
  164.          *
  165.          * @param date interpolation date
  166.          *
  167.          * @return central date to use to find neighbors
  168.          */
  169.         protected AbsoluteDate getCentralDate(final AbsoluteDate date) {
  170.             final AbsoluteDate central;
  171.             final AbsoluteDate minDate = cachedSamples.getEarliest().getDate();
  172.             final AbsoluteDate maxDate = cachedSamples.getLatest().getDate();

  173.             if (date.compareTo(minDate) < 0 &&
  174.                     FastMath.abs(date.durationFrom(minDate)) <= extrapolationThreshold) {
  175.                 // avoid TimeStampedCacheException as we are still within the tolerance before minDate
  176.                 central = minDate;
  177.             } else if (date.compareTo(maxDate) > 0 &&
  178.                     FastMath.abs(date.durationFrom(maxDate)) <= extrapolationThreshold) {
  179.                 // avoid TimeStampedCacheException as we are still within the tolerance after maxDate
  180.                 central = maxDate;
  181.             } else {
  182.                 central = date;
  183.             }

  184.             return central;
  185.         }

  186.         /** Get interpolation date.
  187.          * @return interpolation date
  188.          */
  189.         public AbsoluteDate getInterpolationDate() {
  190.             return interpolationDate;
  191.         }

  192.         /** Get cached samples.
  193.          * @return cached samples
  194.          */
  195.         public ImmutableTimeStampedCache<T> getCachedSamples() {
  196.             return cachedSamples;
  197.         }

  198.         /** Get neighbor list.
  199.          * @return neighbor list
  200.          */
  201.         public List<T> getNeighborList() {
  202.             return neighborList;
  203.         }

  204.     }
  205. }