ShortPeriodicsInterpolatedCoefficient.java

  1. /* Copyright 2002-2025 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.propagation.semianalytical.dsst.utilities;

  18. import org.hipparchus.analysis.interpolation.HermiteInterpolator;
  19. import org.hipparchus.util.FastMath;
  20. import org.orekit.time.AbsoluteDate;

  21. import java.util.ArrayList;

  22. /** Interpolated short periodics coefficients.
  23.  * <p>
  24.  * Representation of a coefficient that need to be interpolated over time.
  25.  * </p><p>
  26.  * The short periodics coefficients can be interpolated for faster computation.
  27.  * This class stores computed values of the coefficients through the method
  28.  * {@link #addGridPoint} and gives an interpolated result through the method
  29.  * {@link #value}.
  30.  * </p>
  31.  * @author Nicolas Bernard
  32.  *
  33.  */
  34. public class ShortPeriodicsInterpolatedCoefficient {

  35.     /**Values of the already computed coefficients.*/
  36.     private ArrayList<double[]> values;

  37.     /**Grid points.*/
  38.     private ArrayList<AbsoluteDate> abscissae;

  39.     /**Number of points used in the interpolation.*/
  40.     private int interpolationPoints;

  41.     /**Index of the latest closest neighbor.*/
  42.     private int latestClosestNeighbor;

  43.     /**Simple constructor.
  44.      * @param interpolationPoints number of points used in the interpolation
  45.      */
  46.     public ShortPeriodicsInterpolatedCoefficient(final int interpolationPoints) {
  47.         this.interpolationPoints = interpolationPoints;
  48.         this.abscissae = new ArrayList<>();
  49.         this.values = new ArrayList<>();
  50.         this.latestClosestNeighbor = 0;
  51.     }

  52.     /**Compute the value of the coefficient.
  53.      * @param date date at which the coefficient should be computed
  54.      * @return value of the coefficient
  55.      */
  56.     public double[] value(final AbsoluteDate date) {
  57.         //Get the closest points from the input date
  58.         final int[] neighbors = getNeighborsIndices(date);

  59.         //Creation and set up of the interpolator
  60.         final HermiteInterpolator interpolator = new HermiteInterpolator();
  61.         for (int i : neighbors) {
  62.             interpolator.addSamplePoint(abscissae.get(i).durationFrom(date), values.get(i));
  63.         }

  64.         //interpolation
  65.         return interpolator.value(0.0);

  66.     }

  67.     /**Find the closest available points from the specified date.
  68.      * @param date date of interest
  69.      * @return indices corresponding to the closest points on the time scale
  70.      */
  71.     private int[] getNeighborsIndices(final AbsoluteDate date) {
  72.         final int sizeofNeighborhood = FastMath.min(interpolationPoints, abscissae.size());
  73.         final int[] neighborsIndices = new int[sizeofNeighborhood];

  74.         //If the size of the complete sample is less than
  75.         //the desired number of interpolation points,
  76.         //then the entire sample is considered as the neighborhood
  77.         if (interpolationPoints >= abscissae.size()) {
  78.             for (int i = 0; i < sizeofNeighborhood; i++) {
  79.                 neighborsIndices[i] = i;
  80.             }
  81.         } else {
  82.             // get indices around closest neighbor
  83.             int inf = getClosestNeighbor(date);
  84.             int sup = inf + 1;

  85.             while (sup - inf < interpolationPoints) {
  86.                 if (inf == 0) { //This means that we have reached the earliest date
  87.                     sup++;
  88.                 } else if (sup >= abscissae.size()) { //This means that we have reached the latest date
  89.                     inf--;
  90.                 } else { //the choice is made between the two next neighbors
  91.                     final double lowerNeighborDistance = FastMath.abs(abscissae.get(inf - 1).durationFrom(date));
  92.                     final double upperNeighborDistance = FastMath.abs(abscissae.get(sup).durationFrom(date));

  93.                     if (lowerNeighborDistance <= upperNeighborDistance) {
  94.                         inf--;
  95.                     } else {
  96.                         sup++;
  97.                     }
  98.                 }
  99.             }

  100.             for (int i = 0; i < interpolationPoints; ++i) {
  101.                 neighborsIndices[i] = inf + i;
  102.             }

  103.         }

  104.         return neighborsIndices;
  105.     }

  106.     /**Find the closest point from a specific date amongst the available points.
  107.      * @param date date of interest
  108.      * @return index of the closest abscissa from the date of interest
  109.      */
  110.     private int getClosestNeighbor(final AbsoluteDate date) {
  111.         //the starting point is the latest result of a call to this method.
  112.         //Indeed, as this class is meant to be called during an integration process
  113.         //with an input date evolving often continuously in time, there is a high
  114.         //probability that the result will be the same as for last call of
  115.         //this method.
  116.         final int closestNeighbor;

  117.         //case where the date is before the available points
  118.         if (date.compareTo(abscissae.get(0)) <= 0) {
  119.             closestNeighbor = 0;
  120.         }
  121.         //case where the date is after the available points
  122.         else if (date.compareTo(abscissae.get(abscissae.size() - 1)) >= 0) {
  123.             closestNeighbor = abscissae.size() - 1;
  124.         }
  125.         //general case: one is looking for the two consecutives entries that surround the input date
  126.         //then one choose the closest one
  127.         else {
  128.             int lowerBorder = latestClosestNeighbor;
  129.             int upperBorder = latestClosestNeighbor;

  130.             final int searchDirection = date.compareTo(abscissae.get(latestClosestNeighbor));
  131.             if (searchDirection > 0) {
  132.                 upperBorder++;
  133.                 while (date.compareTo(abscissae.get(upperBorder)) > 0) {
  134.                     upperBorder++;
  135.                     lowerBorder++;
  136.                 }
  137.             }
  138.             else {
  139.                 lowerBorder--;
  140.                 while (date.compareTo(abscissae.get(lowerBorder)) < 0) {
  141.                     upperBorder--;
  142.                     lowerBorder--;
  143.                 }
  144.             }

  145.             final double lowerDistance = FastMath.abs(date.durationFrom(abscissae.get(lowerBorder)));
  146.             final double upperDistance = FastMath.abs(date.durationFrom(abscissae.get(upperBorder)));

  147.             closestNeighbor = (lowerDistance < upperDistance) ? lowerBorder : upperBorder;
  148.         }

  149.         //The result is stored in order to speed up the next call to the function
  150.         //Indeed, it is highly likely that the requested result will be the same
  151.         this.latestClosestNeighbor = closestNeighbor;
  152.         return closestNeighbor;
  153.     }

  154.     /** Clear the recorded values from the interpolation grid.
  155.      */
  156.     public void clearHistory() {
  157.         abscissae.clear();
  158.         values.clear();
  159.     }

  160.     /** Add a point to the interpolation grid.
  161.      * @param date abscissa of the point
  162.      * @param value value of the element
  163.      */
  164.     public void addGridPoint(final AbsoluteDate date, final double[] value) {
  165.         //If the grid is empty, the value is directly added to both arrays
  166.         if (abscissae.isEmpty()) {
  167.             abscissae.add(date);
  168.             values.add(value);
  169.         }
  170.         //If the grid already contains this point, only its value is changed
  171.         else if (abscissae.contains(date)) {
  172.             values.set(abscissae.indexOf(date), value);
  173.         }
  174.         //If the grid does not contain this point, the position of the point
  175.         //in the grid is computed first
  176.         else {
  177.             final int closestNeighbor = getClosestNeighbor(date);
  178.             final int index = (date.compareTo(abscissae.get(closestNeighbor)) < 0) ? closestNeighbor : closestNeighbor + 1;
  179.             abscissae.add(index, date);
  180.             values.add(index, value);
  181.         }
  182.     }
  183. }