SeriesTerm.java

  1. /* Copyright 2002-2018 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.data;

  18. import java.util.Arrays;

  19. import org.hipparchus.RealFieldElement;
  20. import org.hipparchus.util.FastMath;
  21. import org.hipparchus.util.MathArrays;
  22. import org.orekit.errors.OrekitInternalError;
  23. import org.orekit.utils.Constants;

  24. /** Base class for nutation series terms.
  25.  * @author Luc Maisonobe
  26.  * @see PoissonSeries
  27.  */
  28. abstract class SeriesTerm {

  29.     /** Coefficients for the sine part. */
  30.     private double[][] sinCoeff;

  31.     /** Coefficients for the cosine part. */
  32.     private double[][] cosCoeff;

  33.     /** Simple constructor for the base class.
  34.      */
  35.     protected SeriesTerm() {
  36.         this.sinCoeff = new double[0][0];
  37.         this.cosCoeff = new double[0][0];
  38.     }

  39.     /** Get the degree of the function component.
  40.      * @param index index of the function component (must be less than dimension)
  41.      * @return degree of the function component
  42.      */
  43.     public int getDegree(final int index) {
  44.         return  sinCoeff[index].length - 1;
  45.     }

  46.     /** Add a pair of values to existing term coefficients.
  47.      * <p>
  48.      * Despite it would seem logical to simply set coefficients
  49.      * rather than add to them, this does not work for some IERS
  50.      * files. As an example in table 5.3a in IERS conventions 2003,
  51.      * the coefficients for luni-solar term for 2F+Ω with period
  52.      * 13.633 days appears twice with different coefficients, as
  53.      * well as term for 2(F+D+Ω)+l with period 5.643 days, term for
  54.      * 2(F+D+Ω)-l with period 9.557 days, term for 2(Ω-l') with
  55.      * period -173.318 days, term for 2D-l with period 31.812 days ...
  56.      * 35 different duplicated terms have been identified in the
  57.      * tables 5.3a and 5.3b in IERS conventions 2003.
  58.      * The coefficients read in lines duplicating a term must be
  59.      * added together.
  60.      * </p>
  61.      * @param index index of the components (will automatically
  62.      * increase dimension if needed)
  63.      * @param degree degree of the coefficients, may be negative if
  64.      * the term does not contribute to component (will automatically
  65.      * increase {@link #getDegree() degree} of the component if needed)
  66.      * @param sinID coefficient for the sine part, at index and degree
  67.      * @param cosID coefficient for the cosine part, at index and degree
  68.      */
  69.     public void add(final int index, final int degree,
  70.                     final double sinID, final double cosID) {
  71.         sinCoeff = extendArray(index, degree, sinCoeff);
  72.         cosCoeff = extendArray(index, degree, cosCoeff);
  73.         if (degree >= 0) {
  74.             sinCoeff[index][degree] += sinID;
  75.             cosCoeff[index][degree] += cosID;
  76.         }
  77.     }

  78.     /** Get a coefficient for the sine part.
  79.      * @param index index of the function component (must be less than dimension)
  80.      * @param degree degree of the coefficients
  81.      * (must be less than {@link #getDegree() degree} for the component)
  82.      * @return coefficient for the sine part, at index and degree
  83.      */
  84.     public double getSinCoeff(final int index, final int degree) {
  85.         return sinCoeff[index][degree];
  86.     }

  87.     /** Get a coefficient for the cosine part.
  88.      * @param index index of the function component (must be less than dimension)
  89.      * @param degree degree of the coefficients
  90.      * (must be less than {@link #getDegree() degree} for the component)
  91.      * @return coefficient for the cosine part, at index and degree
  92.      */
  93.     public double getCosCoeff(final int index, final int degree) {
  94.         return cosCoeff[index][degree];
  95.     }

  96.     /** Evaluate the value of the series term.
  97.      * @param elements bodies elements for nutation
  98.      * @return value of the series term
  99.      */
  100.     public double[] value(final BodiesElements elements) {

  101.         // preliminary computation
  102.         final double tc  = elements.getTC();
  103.         final double a   = argument(elements);
  104.         final double sin = FastMath.sin(a);
  105.         final double cos = FastMath.cos(a);

  106.         // compute each function
  107.         final double[] values = new double[sinCoeff.length];
  108.         for (int i = 0; i < values.length; ++i) {
  109.             double s = 0;
  110.             double c = 0;
  111.             for (int j = sinCoeff[i].length - 1; j >= 0; --j) {
  112.                 s = s * tc + sinCoeff[i][j];
  113.                 c = c * tc + cosCoeff[i][j];
  114.             }
  115.             values[i] = s * sin + c * cos;
  116.         }

  117.         return values;

  118.     }

  119.     /** Evaluate the time derivative of the series term.
  120.      * @param elements bodies elements for nutation
  121.      * @return time derivative of the series term
  122.      */
  123.     public double[] derivative(final BodiesElements elements) {

  124.         // preliminary computation
  125.         final double tc   = elements.getTC();
  126.         final double a    = argument(elements);
  127.         final double aDot = argumentDerivative(elements);
  128.         final double sin  = FastMath.sin(a);
  129.         final double cos  = FastMath.cos(a);

  130.         // compute each function
  131.         final double[] derivatives = new double[sinCoeff.length];
  132.         for (int i = 0; i < derivatives.length; ++i) {
  133.             double s    = 0;
  134.             double c    = 0;
  135.             double sDot = 0;
  136.             double cDot = 0;
  137.             if (sinCoeff[i].length > 0) {
  138.                 for (int j = sinCoeff[i].length - 1; j > 0; --j) {
  139.                     s    = s    * tc +     sinCoeff[i][j];
  140.                     c    = c    * tc +     cosCoeff[i][j];
  141.                     sDot = sDot * tc + j * sinCoeff[i][j];
  142.                     cDot = cDot * tc + j * cosCoeff[i][j];
  143.                 }
  144.                 s     = s * tc + sinCoeff[i][0];
  145.                 c     = c * tc + cosCoeff[i][0];
  146.                 sDot /= Constants.JULIAN_CENTURY;
  147.                 cDot /= Constants.JULIAN_CENTURY;
  148.             }
  149.             derivatives[i] = (sDot - c * aDot) * sin + (cDot + s * aDot) * cos;
  150.         }

  151.         return derivatives;

  152.     }

  153.     /** Compute the argument for the current date.
  154.      * @param elements luni-solar and planetary elements for the current date
  155.      * @return current value of the argument
  156.      */
  157.     protected abstract double argument(BodiesElements elements);

  158.     /** Compute the time derivative of the argument for the current date.
  159.      * @param elements luni-solar and planetary elements for the current date
  160.      * @return current time derivative of the argument
  161.      */
  162.     protected abstract double argumentDerivative(BodiesElements elements);

  163.     /** Evaluate the value of the series term.
  164.      * @param elements bodies elements for nutation
  165.      * @param <T> the type of the field elements
  166.      * @return value of the series term
  167.      */
  168.     public <T extends RealFieldElement<T>> T[] value(final FieldBodiesElements<T> elements) {

  169.         // preliminary computation
  170.         final T tc  = elements.getTC();
  171.         final T a   = argument(elements);
  172.         final T sin = a.sin();
  173.         final T cos = a.cos();

  174.         // compute each function
  175.         final T[] values = MathArrays.buildArray(tc.getField(), sinCoeff.length);
  176.         for (int i = 0; i < values.length; ++i) {
  177.             T s = tc.getField().getZero();
  178.             T c = tc.getField().getZero();
  179.             for (int j = sinCoeff[i].length - 1; j >= 0; --j) {
  180.                 s = s.multiply(tc).add(sinCoeff[i][j]);
  181.                 c = c.multiply(tc).add(cosCoeff[i][j]);
  182.             }
  183.             values[i] = s.multiply(sin).add(c.multiply(cos));
  184.         }

  185.         return values;

  186.     }

  187.     /** Evaluate the time derivative of the series term.
  188.      * @param elements bodies elements for nutation
  189.      * @param <T> the type of the field elements
  190.      * @return time derivative of the series term
  191.      */
  192.     public <T extends RealFieldElement<T>> T[] derivative(final FieldBodiesElements<T> elements) {

  193.         // preliminary computation
  194.         final T tc   = elements.getTC();
  195.         final T a    = argument(elements);
  196.         final T aDot = argumentDerivative(elements);
  197.         final T sin  = a.sin();
  198.         final T cos  = a.cos();

  199.         // compute each function
  200.         final T[] derivatives = MathArrays.buildArray(tc.getField(), sinCoeff.length);
  201.         for (int i = 0; i < derivatives.length; ++i) {
  202.             T s    = tc.getField().getZero();
  203.             T c    = tc.getField().getZero();
  204.             T sDot = tc.getField().getZero();
  205.             T cDot = tc.getField().getZero();
  206.             if (sinCoeff[i].length > 0) {
  207.                 for (int j = sinCoeff[i].length - 1; j > 0; --j) {
  208.                     s    = s.multiply(tc).add(sinCoeff[i][j]);
  209.                     c    = c.multiply(tc).add(cosCoeff[i][j]);
  210.                     sDot = sDot.multiply(tc).add(j * sinCoeff[i][j]);
  211.                     cDot = cDot.multiply(tc).add(j * cosCoeff[i][j]);
  212.                 }
  213.                 s    = s.multiply(tc).add(sinCoeff[i][0]);
  214.                 c    = c.multiply(tc).add(cosCoeff[i][0]);
  215.                 sDot = sDot.divide(Constants.JULIAN_CENTURY);
  216.                 cDot = cDot.divide(Constants.JULIAN_CENTURY);
  217.             }
  218.             derivatives[i] = sDot.subtract(c.multiply(aDot)).multiply(sin).
  219.                              add(cDot.add(s.multiply(aDot)).multiply(cos));
  220.         }

  221.         return derivatives;

  222.     }

  223.     /** Compute the argument for the current date.
  224.      * @param elements luni-solar and planetary elements for the current date
  225.      * @param <T> the type of the field elements
  226.      * @return current value of the argument
  227.      */
  228.     protected abstract <T extends RealFieldElement<T>> T argument(FieldBodiesElements<T> elements);

  229.     /** Compute the time derivative of the argument for the current date.
  230.      * @param elements luni-solar and planetary elements for the current date
  231.      * @param <T> the type of the field elements
  232.      * @return current time derivative of the argument
  233.      */
  234.     protected abstract <T extends RealFieldElement<T>> T argumentDerivative(FieldBodiesElements<T> elements);

  235.     /** Factory method for building the appropriate object.
  236.      * <p>The method checks the null coefficients and build an instance
  237.      * of an appropriate type to avoid too many unnecessary multiplications
  238.      * by zero coefficients.</p>
  239.      * @param cGamma coefficient for γ = GMST + π tide parameter
  240.      * @param cL coefficient for mean anomaly of the Moon
  241.      * @param cLPrime coefficient for mean anomaly of the Sun
  242.      * @param cF coefficient for L - Ω where L is the mean longitude of the Moon
  243.      * @param cD coefficient for mean elongation of the Moon from the Sun
  244.      * @param cOmega coefficient for mean longitude of the ascending node of the Moon
  245.      * @param cMe coefficient for mean Mercury longitude
  246.      * @param cVe coefficient for mean Venus longitude
  247.      * @param cE coefficient for mean Earth longitude
  248.      * @param cMa coefficient for mean Mars longitude
  249.      * @param cJu coefficient for mean Jupiter longitude
  250.      * @param cSa coefficient for mean Saturn longitude
  251.      * @param cUr coefficient for mean Uranus longitude
  252.      * @param cNe coefficient for mean Neptune longitude
  253.      * @param cPa coefficient for general accumulated precession in longitude
  254.      * @return a nutation serie term instance well suited for the set of coefficients
  255.      */
  256.     public static  SeriesTerm buildTerm(final int cGamma,
  257.                                         final int cL, final int cLPrime, final int cF,
  258.                                         final int cD, final int cOmega,
  259.                                         final int cMe, final int cVe, final int cE,
  260.                                         final int cMa, final int cJu, final int cSa,
  261.                                         final int cUr, final int cNe, final int cPa) {
  262.         if (cGamma == 0 && cL == 0 && cLPrime == 0 && cF == 0 && cD == 0 && cOmega == 0) {
  263.             return new PlanetaryTerm(cMe, cVe, cE, cMa, cJu, cSa, cUr, cNe, cPa);
  264.         } else if (cGamma == 0 &&
  265.                    cMe == 0 && cVe == 0 && cE == 0 && cMa == 0 && cJu == 0 &&
  266.                    cSa == 0 && cUr == 0 && cNe == 0 && cPa == 0) {
  267.             return new LuniSolarTerm(cL, cLPrime, cF, cD, cOmega);
  268.         } else if (cGamma != 0 &&
  269.                    cMe == 0 && cVe == 0 && cE == 0 && cMa == 0 && cJu == 0 &&
  270.                    cSa == 0 && cUr == 0 && cNe == 0 && cPa == 0) {
  271.             return new TideTerm(cGamma, cL, cLPrime, cF, cD, cOmega);
  272.         } else if (cGamma == 0 && cLPrime == 0 && cUr == 0 && cNe == 0 && cPa == 0) {
  273.             return new NoFarPlanetsTerm(cL, cF, cD, cOmega,
  274.                                         cMe, cVe, cE, cMa, cJu, cSa);
  275.         } else if (cGamma == 0) {
  276.             return new GeneralTerm(cL, cLPrime, cF, cD, cOmega,
  277.                                    cMe, cVe, cE, cMa, cJu, cSa, cUr, cNe, cPa);
  278.         } else {
  279.             throw new OrekitInternalError(null);
  280.         }

  281.     }

  282.     /** Extend an array to hold at least index and degree.
  283.      * @param index index of the function
  284.      * @param degree degree of the coefficients
  285.      * @param array to extend
  286.      * @return extended array
  287.      */
  288.     private static double[][] extendArray(final int index, final int degree,
  289.                                           final double[][] array) {

  290.         // extend the number of rows if needed
  291.         final double[][] extended;
  292.         if (array.length > index) {
  293.             extended = array;
  294.         } else {
  295.             final int rows =  index + 1;
  296.             extended = new double[rows][];
  297.             System.arraycopy(array, 0, extended, 0, array.length);
  298.             Arrays.fill(extended, array.length, index + 1, new double[0]);
  299.         }

  300.         // extend the number of elements in the row if needed
  301.         extended[index] = extendArray(degree, extended[index]);

  302.         return extended;

  303.     }

  304.     /** Extend an array to hold at least degree.
  305.      * @param degree degree of the coefficients
  306.      * @param array to extend
  307.      * @return extended array
  308.      */
  309.     private static double[] extendArray(final int degree, final double[] array) {
  310.         // extend the number of elements if needed
  311.         if (array.length > degree) {
  312.             return array;
  313.         } else {
  314.             final double[] extended = new double[degree + 1];
  315.             System.arraycopy(array, 0, extended, 0, array.length);
  316.             return extended;
  317.         }
  318.     }

  319. }