AbstractFieldTimeInterpolator.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.CalculusFieldElement;
  19. import org.hipparchus.Field;
  20. import org.hipparchus.util.FastMath;
  21. import org.orekit.errors.OrekitIllegalArgumentException;
  22. import org.orekit.errors.OrekitMessages;
  23. import org.orekit.utils.ImmutableFieldTimeStampedCache;

  24. import java.util.Collection;
  25. import java.util.Collections;
  26. import java.util.List;
  27. import java.util.stream.Collectors;
  28. import java.util.stream.Stream;

  29. /**
  30.  * Abstract class for time interpolator.
  31.  *
  32.  * @param <T> interpolated time stamped type
  33.  * @param <KK> type of the field element
  34.  *
  35.  * @author Vincent Cucchietti
  36.  */
  37. public abstract class AbstractFieldTimeInterpolator<T extends FieldTimeStamped<KK>, KK extends CalculusFieldElement<KK>>
  38.         implements FieldTimeInterpolator<T, KK> {

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

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

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

  45.     /** Neighbor size. */
  46.     private final int interpolationPoints;

  47.     /**
  48.      * Constructor.
  49.      *
  50.      * @param interpolationPoints number of interpolation points
  51.      * @param extrapolationThreshold extrapolation threshold beyond which the propagation will fail
  52.      */
  53.     public AbstractFieldTimeInterpolator(final int interpolationPoints, final double extrapolationThreshold) {
  54.         this.interpolationPoints    = interpolationPoints;
  55.         this.extrapolationThreshold = extrapolationThreshold;
  56.     }

  57.     /**
  58.      * Method checking if given interpolator is compatible with given sample size.
  59.      *
  60.      * @param interpolator interpolator
  61.      * @param sampleSize sample size
  62.      * @param <T> type of the field elements
  63.      */
  64.     public static <T extends CalculusFieldElement<T>> void checkInterpolatorCompatibilityWithSampleSize(
  65.             final FieldTimeInterpolator<? extends FieldTimeStamped<T>, T> interpolator,
  66.             final int sampleSize) {

  67.         // Retrieve all sub-interpolators (or a singleton list with given interpolator if there are no sub-interpolators)
  68.         final List<FieldTimeInterpolator<? extends FieldTimeStamped<T>, T>> subInterpolators =
  69.                 interpolator.getSubInterpolators();
  70.         for (final FieldTimeInterpolator<? extends FieldTimeStamped<T>, T> subInterpolator : subInterpolators) {
  71.             if (sampleSize < subInterpolator.getNbInterpolationPoints()) {
  72.                 throw new OrekitIllegalArgumentException(OrekitMessages.NOT_ENOUGH_DATA, sampleSize);
  73.             }
  74.         }
  75.     }

  76.     /** {@inheritDoc} */
  77.     @Override
  78.     public T interpolate(final FieldAbsoluteDate<KK> interpolationDate, final Stream<T> sample) {
  79.         return interpolate(interpolationDate, sample.collect(Collectors.toList()));
  80.     }

  81.     /** {@inheritDoc}. */
  82.     @Override
  83.     public T interpolate(final FieldAbsoluteDate<KK> interpolationDate, final Collection<T> sample) {
  84.         final InterpolationData interpolationData = new InterpolationData(interpolationDate, sample);
  85.         return interpolate(interpolationData);
  86.     }

  87.     /** {@inheritDoc} */
  88.     public List<FieldTimeInterpolator<? extends FieldTimeStamped<KK>, KK>> getSubInterpolators() {
  89.         return Collections.singletonList(this);
  90.     }

  91.     /** {@inheritDoc} */
  92.     public int getNbInterpolationPoints() {
  93.         return interpolationPoints;
  94.     }

  95.     /** {@inheritDoc} */
  96.     public double getExtrapolationThreshold() {
  97.         return extrapolationThreshold;
  98.     }

  99.     /**
  100.      * Add all lowest level sub interpolators to the sub interpolator list.
  101.      *
  102.      * @param subInterpolator optional sub interpolator to add
  103.      * @param subInterpolators list of sub interpolators
  104.      * @param <S> type of the field element
  105.      */
  106.     protected <S extends CalculusFieldElement<S>> void addOptionalSubInterpolatorIfDefined(
  107.             final FieldTimeInterpolator<? extends FieldTimeStamped<S>, S> subInterpolator,
  108.             final List<FieldTimeInterpolator<? extends FieldTimeStamped<S>, S>> subInterpolators) {
  109.         // Add all lowest level sub interpolators
  110.         if (subInterpolator != null) {
  111.             subInterpolators.addAll(subInterpolator.getSubInterpolators());
  112.         }
  113.     }

  114.     /**
  115.      * Interpolate instance from given interpolation data.
  116.      *
  117.      * @param interpolationData interpolation data
  118.      *
  119.      * @return interpolated instance from given interpolation data.
  120.      */
  121.     protected abstract T interpolate(InterpolationData interpolationData);

  122.     /**
  123.      * Get the time parameter which lies between [0:1] by normalizing the difference between interpolating time and previous
  124.      * date by the Δt between tabulated values.
  125.      *
  126.      * @param interpolatingTime time at which we want to interpolate a value (between previous and next tabulated dates)
  127.      * @param previousDate previous tabulated value date
  128.      * @param nextDate next tabulated value date
  129.      *
  130.      * @return time parameter which lies between [0:1]
  131.      */
  132.     protected KK getTimeParameter(final FieldAbsoluteDate<KK> interpolatingTime,
  133.                                   final FieldAbsoluteDate<KK> previousDate,
  134.                                   final FieldAbsoluteDate<KK> nextDate) {

  135.         return interpolatingTime.durationFrom(previousDate).divide(nextDate.getDate().durationFrom(previousDate));
  136.     }

  137.     /**
  138.      * Nested class used to store interpolation data.
  139.      * <p>
  140.      * It makes the interpolator thread safe.
  141.      */
  142.     public class InterpolationData {

  143.         /** Interpolation date. */
  144.         private final FieldAbsoluteDate<KK> interpolationDate;

  145.         /** Immutable time stamped cached samples. */
  146.         private final ImmutableFieldTimeStampedCache<T, KK> cachedSamples;

  147.         /** Unmodifiable list of neighbors. */
  148.         private final List<T> neighborList;

  149.         /** Field of the element. */
  150.         private final Field<KK> field;

  151.         /** Fielded zero. */
  152.         private final KK zero;

  153.         /** Fielded one. */
  154.         private final KK one;

  155.         /**
  156.          * Constructor.
  157.          *
  158.          * @param interpolationDate interpolation date
  159.          * @param sample time stamped sample
  160.          */
  161.         protected InterpolationData(final FieldAbsoluteDate<KK> interpolationDate, final Collection<T> sample) {
  162.             try {
  163.                 // Handle specific case that is not handled by the immutable time stamped cache constructor
  164.                 if (sample.size() < 2) {
  165.                     throw new OrekitIllegalArgumentException(OrekitMessages.NOT_ENOUGH_DATA,
  166.                                                              sample.size());
  167.                 }

  168.                 // Create immutable time stamped cache
  169.                 cachedSamples = new ImmutableFieldTimeStampedCache<>(interpolationPoints, sample);

  170.                 // Find neighbors
  171.                 final FieldAbsoluteDate<KK> central         = getCentralDate(interpolationDate);
  172.                 final Stream<T>             neighborsStream = cachedSamples.getNeighbors(central);

  173.                 // Extract field and useful terms
  174.                 this.field = interpolationDate.getField();
  175.                 this.zero  = field.getZero();
  176.                 this.one   = field.getOne();

  177.                 // Convert to unmodifiable list
  178.                 neighborList = Collections.unmodifiableList(neighborsStream.collect(Collectors.toList()));

  179.                 // Store interpolation date
  180.                 this.interpolationDate = interpolationDate;
  181.             }
  182.             catch (OrekitIllegalArgumentException exception) {
  183.                 throw new OrekitIllegalArgumentException(OrekitMessages.NOT_ENOUGH_DATA, sample.size());
  184.             }
  185.         }

  186.         /**
  187.          * Get the central date to use to find neighbors while taking into account extrapolation threshold.
  188.          *
  189.          * @param date interpolation date
  190.          *
  191.          * @return central date to use to find neighbors
  192.          */
  193.         protected FieldAbsoluteDate<KK> getCentralDate(final FieldAbsoluteDate<KK> date) {
  194.             final FieldAbsoluteDate<KK> central;
  195.             final FieldAbsoluteDate<KK> minDate = cachedSamples.getEarliest().getDate();
  196.             final FieldAbsoluteDate<KK> maxDate = cachedSamples.getLatest().getDate();

  197.             if (date.compareTo(minDate) < 0 &&
  198.                     FastMath.abs(date.durationFrom(minDate)).getReal() <= extrapolationThreshold) {
  199.                 // avoid TimeStampedCacheException as we are still within the tolerance before minDate
  200.                 central = minDate;
  201.             } else if (date.compareTo(maxDate) > 0 &&
  202.                     FastMath.abs(date.durationFrom(maxDate)).getReal() <= extrapolationThreshold) {
  203.                 // avoid TimeStampedCacheException as we are still within the tolerance after maxDate
  204.                 central = maxDate;
  205.             } else {
  206.                 central = date;
  207.             }

  208.             return central;
  209.         }

  210.         /** Get interpolation date.
  211.          * @return interpolation date
  212.          */
  213.         public FieldAbsoluteDate<KK> getInterpolationDate() {
  214.             return interpolationDate;
  215.         }

  216.         /** Get cached samples.
  217.          * @return cached samples
  218.          */
  219.         public ImmutableFieldTimeStampedCache<T, KK> getCachedSamples() {
  220.             return cachedSamples;
  221.         }

  222.         /** Get neighbor list.
  223.          * @return neighbor list
  224.          */
  225.         public List<T> getNeighborList() {
  226.             return neighborList;
  227.         }

  228.         /** Get field.
  229.          * @return field
  230.          */
  231.         public Field<KK> getField() {
  232.             return field;
  233.         }

  234.         /** Get zero.
  235.          * @return zero
  236.          */
  237.         public KK getZero() {
  238.             return zero;
  239.         }

  240.         /** Get one.
  241.          * @return one
  242.          */
  243.         public KK getOne() {
  244.             return one;
  245.         }
  246.     }
  247. }