CachedNormalizedSphericalHarmonicsProvider.java

  1. /* Copyright 2002-2013 CS Systèmes d'Information
  2.  * Licensed to CS Systèmes d'Information (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.forces.gravity.potential;

  18. import java.io.Serializable;
  19. import java.util.ArrayList;
  20. import java.util.Collection;
  21. import java.util.List;

  22. import org.apache.commons.math3.analysis.interpolation.HermiteInterpolator;
  23. import org.orekit.errors.OrekitException;
  24. import org.orekit.errors.TimeStampedCacheException;
  25. import org.orekit.time.AbsoluteDate;
  26. import org.orekit.time.TimeStamped;
  27. import org.orekit.utils.GenericTimeStampedCache;
  28. import org.orekit.utils.TimeStampedCache;
  29. import org.orekit.utils.TimeStampedGenerator;

  30. /** Caching wrapper for {@link NormalizedSphericalHarmonicsProvider}.
  31.  * <p>
  32.  * This wrapper improves efficiency of {@link NormalizedSphericalHarmonicsProvider}
  33.  * by sampling the values at a user defined rate and using interpolation
  34.  * between samples. This is important with providers that have sub-daily
  35.  * frequencies and are computing intensive, such as tides fields.
  36.  * </p>
  37.  * @see NormalizedSphericalHarmonicsProvider
  38.  * @see org.orekit.forces.gravity.SolidTides
  39.  * @see TimeStampedCache
  40.  * @author Luc Maisonobe
  41.  * @since 6.1
  42.  */
  43. public class CachedNormalizedSphericalHarmonicsProvider implements NormalizedSphericalHarmonicsProvider {

  44.     /** Underlying raw provider. */
  45.     private final NormalizedSphericalHarmonicsProvider rawProvider;

  46.     /** Number of coefficients in C<sub>n, m</sub> and S<sub>n, m</sub> arrays (counted separately). */
  47.     private final int size;

  48.     /** Cache. */
  49.     private final TimeStampedCache<TimeStampedSphericalHarmonics> cache;

  50.     /** Simple constructor.
  51.      * @param rawProvider underlying raw provider
  52.      * @param step time step between sample points for interpolation
  53.      * @param nbPoints number of points to use for interpolation, must be at least 2
  54.      * @param maxSlots maximum number of independent cached time slots
  55.      * @param maxSpan maximum duration span in seconds of one slot
  56.      * (can be set to {@code Double.POSITIVE_INFINITY} if desired)
  57.      * @param newSlotInterval time interval above which a new slot is created
  58.      * instead of extending an existing one
  59.      */
  60.     public CachedNormalizedSphericalHarmonicsProvider(final NormalizedSphericalHarmonicsProvider rawProvider,
  61.                                                       final double step, final int nbPoints,
  62.                                                       final int maxSlots, final double maxSpan,
  63.                                                       final double newSlotInterval) {

  64.         this.rawProvider  = rawProvider;
  65.         final int k       = rawProvider.getMaxDegree() + 1;
  66.         this.size         = (k * (k + 1)) / 2;

  67.         cache = new GenericTimeStampedCache<TimeStampedSphericalHarmonics>(nbPoints, maxSlots, maxSpan,
  68.                                                                            newSlotInterval, new Generator(step),
  69.                                                                            TimeStampedSphericalHarmonics.class);
  70.     }

  71.     /** {@inheritDoc} */
  72.     @Override
  73.     public int getMaxDegree() {
  74.         return rawProvider.getMaxDegree();
  75.     }

  76.     /** {@inheritDoc} */
  77.     @Override
  78.     public int getMaxOrder() {
  79.         return rawProvider.getMaxOrder();
  80.     }

  81.     /** {@inheritDoc} */
  82.     @Override
  83.     public double getMu() {
  84.         return rawProvider.getMu();
  85.     }

  86.     /** {@inheritDoc} */
  87.     @Override
  88.     public double getAe() {
  89.         return rawProvider.getAe();
  90.     }

  91.     /** {@inheritDoc} */
  92.     @Override
  93.     public AbsoluteDate getReferenceDate() {
  94.         return rawProvider.getReferenceDate();
  95.     }

  96.     /** {@inheritDoc} */
  97.     @Override
  98.     public double getOffset(final AbsoluteDate date) {
  99.         return rawProvider.getOffset(date);
  100.     }

  101.     /** {@inheritDoc} */
  102.     @Override
  103.     public TideSystem getTideSystem() {
  104.         return rawProvider.getTideSystem();
  105.     }

  106.     /** {@inheritDoc} */
  107.     @Override
  108.     @Deprecated
  109.     public double getNormalizedCnm(final double dateOffset, final int n, final int m)
  110.         throws OrekitException {
  111.         return onDate(getReferenceDate().shiftedBy(dateOffset)).getNormalizedCnm(n, m);
  112.     }

  113.     /** {@inheritDoc} */
  114.     @Override
  115.     @Deprecated
  116.     public double getNormalizedSnm(final double dateOffset, final int n, final int m)
  117.         throws OrekitException {
  118.         return onDate(getReferenceDate().shiftedBy(dateOffset)).getNormalizedSnm(n, m);
  119.     }

  120.     /** {@inheritDoc} */
  121.     @Override
  122.     public NormalizedSphericalHarmonics onDate(final AbsoluteDate date) throws
  123.             TimeStampedCacheException {
  124.         return TimeStampedSphericalHarmonics.interpolate(date, cache.getNeighbors(date));
  125.     }

  126.     /** Generator for time-stamped spherical harmonics. */
  127.     private class Generator implements TimeStampedGenerator<TimeStampedSphericalHarmonics> {

  128.         /** Time step between generated sets. */
  129.         private final double step;

  130.         /** Simple constructor.
  131.          * @param step time step between generated sets
  132.          */
  133.         public Generator(final double step) {
  134.             this.step = step;
  135.         }

  136.         /** {@inheritDoc} */
  137.         @Override
  138.         public List<TimeStampedSphericalHarmonics> generate(final TimeStampedSphericalHarmonics existing,
  139.                                                             final AbsoluteDate date)
  140.             throws TimeStampedCacheException {
  141.             try {

  142.                 final List<TimeStampedSphericalHarmonics> generated =
  143.                         new ArrayList<TimeStampedSphericalHarmonics>();
  144.                 final double[] cnmsnm = new double[2 * size];

  145.                 if (existing == null) {

  146.                     // no prior existing transforms, just generate a first set
  147.                     for (int i = 0; i < cache.getNeighborsSize(); ++i) {
  148.                         final AbsoluteDate t = date.shiftedBy((i - cache.getNeighborsSize() / 2) * step);
  149.                         fillArray(rawProvider.onDate(t), cnmsnm);
  150.                         generated.add(new TimeStampedSphericalHarmonics(t, cnmsnm));
  151.                     }

  152.                 } else {

  153.                     // some coefficients have already been generated
  154.                     // add the missing ones up to specified date

  155.                     AbsoluteDate t = existing.getDate();
  156.                     if (date.compareTo(t) > 0) {
  157.                         // forward generation
  158.                         do {
  159.                             t = t.shiftedBy(step);
  160.                             fillArray(rawProvider.onDate(t), cnmsnm);
  161.                             generated.add(new TimeStampedSphericalHarmonics(t, cnmsnm));
  162.                         } while (t.compareTo(date) <= 0);
  163.                     } else {
  164.                         // backward generation
  165.                         do {
  166.                             t = t.shiftedBy(-step);
  167.                             fillArray(rawProvider.onDate(t), cnmsnm);
  168.                             generated.add(new TimeStampedSphericalHarmonics(t, cnmsnm));
  169.                         } while (t.compareTo(date) >= 0);
  170.                     }

  171.                 }

  172.                 // return the generated sample
  173.                 return generated;

  174.             } catch (OrekitException oe) {
  175.                 throw new TimeStampedCacheException(oe);
  176.             }
  177.         }

  178.         /** Fill coefficients array for one entry.
  179.          * @param raw the un-interpolated spherical harmonics
  180.          * @param cnmsnm arrays to fill in
  181.          * @exception OrekitException if coefficients cannot be computed at specified date
  182.          */
  183.         private void fillArray(final NormalizedSphericalHarmonics raw,
  184.                                final double[] cnmsnm)
  185.             throws OrekitException {
  186.             int index = 0;
  187.             for (int n = 0; n <= rawProvider.getMaxDegree(); ++n) {
  188.                 for (int m = 0; m <= n; ++m) {
  189.                     cnmsnm[index++] = raw.getNormalizedCnm(n, m);
  190.                 }
  191.             }
  192.             for (int n = 0; n <= rawProvider.getMaxDegree(); ++n) {
  193.                 for (int m = 0; m <= n; ++m) {
  194.                     cnmsnm[index++] = raw.getNormalizedSnm(n, m);
  195.                 }
  196.             }
  197.         }

  198.     }

  199.     /**
  200.      * Internal class for time-stamped spherical harmonics. Instances are created using
  201.      * {@link #interpolate(AbsoluteDate, Collection)}
  202.      */
  203.     private static class TimeStampedSphericalHarmonics
  204.             implements TimeStamped, Serializable, NormalizedSphericalHarmonics {

  205.         /** Serializable UID. */
  206.         private static final long serialVersionUID = 20131029l;

  207.         /** Current date. */
  208.         private final AbsoluteDate date;

  209.         /** number of C or S coefficients. */
  210.         private final int size;

  211.         /** Flattened array for C<sub>n,m</sub> and S<sub>n,m</sub> coefficients. */
  212.         private final double[] cnmsnm;

  213.         /** Simple constructor.
  214.          * @param date current date
  215.          * @param cnmsnm flattened array for C<sub>n,m</sub> and S<sub>n,m</sub>
  216.          *               coefficients. It is copied.
  217.          */
  218.         private TimeStampedSphericalHarmonics(final AbsoluteDate date,
  219.                                               final double[] cnmsnm) {
  220.             this.date   = date;
  221.             this.cnmsnm = cnmsnm.clone();
  222.             this.size   = cnmsnm.length / 2;
  223.         }

  224.         /** {@inheritDoc} */
  225.         @Override
  226.         public AbsoluteDate getDate() {
  227.             return date;
  228.         }

  229.         /** {@inheritDoc} */
  230.         @Override
  231.         public double getNormalizedCnm(final int n, final int m) throws OrekitException {
  232.             return cnmsnm[(n * (n + 1)) / 2 + m];
  233.         }

  234.         /** {@inheritDoc} */
  235.         @Override
  236.         public double getNormalizedSnm(final int n, final int m) throws OrekitException {
  237.             return cnmsnm[(n * (n + 1)) / 2 + m + size];
  238.         }

  239.         /** Interpolate spherical harmonics.
  240.          * <p>
  241.          * The interpolated instance is created by polynomial Hermite interpolation.
  242.          * </p>
  243.          * @param date interpolation date
  244.          * @param sample sample points on which interpolation should be done
  245.          * @return a new time-stamped spherical harmonics, interpolated at specified date
  246.          */
  247.         public static TimeStampedSphericalHarmonics interpolate(final AbsoluteDate date,
  248.                                                                 final Collection<TimeStampedSphericalHarmonics> sample) {

  249.             // set up an interpolator taking derivatives into account
  250.             final HermiteInterpolator interpolator = new HermiteInterpolator();

  251.             // add sample points
  252.             for (final TimeStampedSphericalHarmonics tssh : sample) {
  253.                 interpolator.addSamplePoint(tssh.date.durationFrom(date), tssh.cnmsnm);
  254.             }

  255.             // build a new interpolated instance
  256.             return new TimeStampedSphericalHarmonics(date, interpolator.value(0.0));

  257.         }

  258.     }

  259. }