FundamentalNutationArguments.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.data;

  18. import java.io.BufferedReader;
  19. import java.io.IOException;
  20. import java.io.InputStream;
  21. import java.io.InputStreamReader;
  22. import java.io.Serializable;
  23. import java.util.ArrayList;
  24. import java.util.Arrays;
  25. import java.util.HashMap;
  26. import java.util.List;
  27. import java.util.Map;
  28. import java.util.regex.Matcher;
  29. import java.util.regex.Pattern;

  30. import org.apache.commons.math3.analysis.differentiation.DerivativeStructure;
  31. import org.apache.commons.math3.exception.util.DummyLocalizable;
  32. import org.apache.commons.math3.util.FastMath;
  33. import org.orekit.errors.OrekitException;
  34. import org.orekit.errors.OrekitMessages;
  35. import org.orekit.time.AbsoluteDate;
  36. import org.orekit.time.TimeFunction;
  37. import org.orekit.time.TimeScale;
  38. import org.orekit.utils.IERSConventions;

  39. /**
  40.  * Class computing the fundamental arguments for nutation and tides.
  41.  * <p>
  42.  * The fundamental arguments are split in two sets:
  43.  * </p>
  44.  * <ul>
  45.  *   <li>the Delaunay arguments for Moon and Sun effects</li>
  46.  *   <li>the planetary arguments for other planets</li>
  47.  * </ul>
  48.  *
  49.  * @author Luc Maisonobe
  50.  * @see SeriesTerm
  51.  * @see PoissonSeries
  52.  * @see BodiesElements
  53.  */
  54. public class FundamentalNutationArguments implements Serializable {

  55.     /** Serializable UID. */
  56.     private static final long serialVersionUID = 20131209L;

  57.     /** IERS conventions to use. */
  58.     private final IERSConventions conventions;

  59.     /** Time scale for GMST computation. */
  60.     private final TimeScale timeScale;

  61.     /** Function computing Greenwich Mean Sidereal Time. */
  62.     private final transient TimeFunction<DerivativeStructure> gmstFunction;

  63.     // luni-solar Delaunay arguments

  64.     /** Coefficients for mean anomaly of the Moon. */
  65.     private final double[] lCoefficients;

  66.     /** Coefficients for mean anomaly of the Sun. */
  67.     private final double[] lPrimeCoefficients;

  68.     /** Coefficients for L - &Omega; where L is the mean longitude of the Moon. */
  69.     private final double[] fCoefficients;

  70.     /** Coefficients for mean elongation of the Moon from the Sun. */
  71.     private final double[] dCoefficients;

  72.     /** Coefficients for mean longitude of the ascending node of the Moon. */
  73.     private final double[] omegaCoefficients;

  74.     // planetary nutation arguments

  75.     /** Coefficients for mean Mercury longitude. */
  76.     private final double[] lMeCoefficients;

  77.     /** Coefficients for mean Venus longitude. */
  78.     private final double[] lVeCoefficients;

  79.     /** Coefficients for mean Earth longitude. */
  80.     private final double[] lECoefficients;

  81.     /** Coefficients for mean Mars longitude. */
  82.     private final double[] lMaCoefficients;

  83.     /** Coefficients for mean Jupiter longitude. */
  84.     private final double[] lJCoefficients;

  85.     /** Coefficients for mean Saturn longitude. */
  86.     private final double[] lSaCoefficients;

  87.     /** Coefficients for mean Uranus longitude. */
  88.     private final double[] lUCoefficients;

  89.     /** Coefficients for mean Neptune longitude. */
  90.     private final double[] lNeCoefficients;

  91.     /** Coefficients for general accumulated precession. */
  92.     private final double[] paCoefficients;

  93.     /** Build a model of fundamental arguments from an IERS table file.
  94.      * @param conventions IERS conventions to use
  95.      * @param timeScale time scale for GMST computation
  96.      * (may be null if tide parameter γ = GMST + π is not needed)
  97.      * @param stream stream containing the IERS table
  98.      * @param name name of the resource file (for error messages only)
  99.      * @exception OrekitException if stream is null or the table cannot be parsed
  100.      */
  101.     public FundamentalNutationArguments(final IERSConventions conventions,
  102.                                         final TimeScale timeScale,
  103.                                         final InputStream stream, final String name)
  104.         throws OrekitException {
  105.         this(conventions, timeScale, parseCoefficients(stream, name));
  106.     }

  107.     /** Build a model of fundamental arguments from an IERS table file.
  108.      * @param conventions IERS conventions to use
  109.      * @param timeScale time scale for GMST computation
  110.      * (may be null if tide parameter γ = GMST + π is not needed)
  111.      * @param coefficients list of coefficients arrays (all 14 arrays must be provided,
  112.      * the 5 Delaunay first and the 9 planetary afterwards)
  113.      * @exception OrekitException if GMST function cannot be retrieved
  114.      * @since 6.1
  115.      */
  116.     public FundamentalNutationArguments(final IERSConventions conventions, final TimeScale timeScale,
  117.                                         final List<double[]> coefficients)
  118.         throws OrekitException {
  119.         this.conventions        = conventions;
  120.         this.timeScale          = timeScale;
  121.         this.gmstFunction       = (timeScale == null) ? null : conventions.getGMSTFunction(timeScale);
  122.         this.lCoefficients      = coefficients.get( 0);
  123.         this.lPrimeCoefficients = coefficients.get( 1);
  124.         this.fCoefficients      = coefficients.get( 2);
  125.         this.dCoefficients      = coefficients.get( 3);
  126.         this.omegaCoefficients  = coefficients.get( 4);
  127.         this.lMeCoefficients    = coefficients.get( 5);
  128.         this.lVeCoefficients    = coefficients.get( 6);
  129.         this.lECoefficients     = coefficients.get( 7);
  130.         this.lMaCoefficients    = coefficients.get( 8);
  131.         this.lJCoefficients     = coefficients.get( 9);
  132.         this.lSaCoefficients    = coefficients.get(10);
  133.         this.lUCoefficients     = coefficients.get(11);
  134.         this.lNeCoefficients    = coefficients.get(12);
  135.         this.paCoefficients     = coefficients.get(13);
  136.     }

  137.     /** Parse coefficients.
  138.      * @param stream stream containing the IERS table
  139.      * @param name name of the resource file (for error messages only)
  140.      * @return list of coefficients arrays
  141.      * @exception OrekitException if stream is null or the table cannot be parsed
  142.      */
  143.     private static List<double[]> parseCoefficients(final InputStream stream, final String name)
  144.         throws OrekitException {

  145.         if (stream == null) {
  146.             throw new OrekitException(OrekitMessages.UNABLE_TO_FIND_FILE, name);
  147.         }

  148.         try {

  149.             final DefinitionParser definitionParser = new DefinitionParser();

  150.             // setup the reader
  151.             final BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
  152.             int lineNumber = 0;

  153.             // look for the reference date and the 14 polynomials
  154.             final int n = FundamentalName.values().length;
  155.             final Map<FundamentalName, double[]> polynomials = new HashMap<FundamentalName, double[]>(n);
  156.             for (String line = reader.readLine(); line != null; line = reader.readLine()) {
  157.                 lineNumber++;
  158.                 if (definitionParser.parseDefinition(line, lineNumber, name)) {
  159.                     polynomials.put(definitionParser.getParsedName(),
  160.                                     definitionParser.getParsedPolynomial());
  161.                 }
  162.             }

  163.             final List<double[]> coefficients = new ArrayList<double[]>(n);
  164.             coefficients.add(getCoefficients(FundamentalName.L,       polynomials, name));
  165.             coefficients.add(getCoefficients(FundamentalName.L_PRIME, polynomials, name));
  166.             coefficients.add(getCoefficients(FundamentalName.F,       polynomials, name));
  167.             coefficients.add(getCoefficients(FundamentalName.D,       polynomials, name));
  168.             coefficients.add(getCoefficients(FundamentalName.OMEGA,   polynomials, name));
  169.             if (polynomials.containsKey(FundamentalName.L_ME)) {
  170.                 // IERS conventions 2003 and later provide planetary nutation arguments
  171.                 coefficients.add(getCoefficients(FundamentalName.L_ME,    polynomials, name));
  172.                 coefficients.add(getCoefficients(FundamentalName.L_VE,    polynomials, name));
  173.                 coefficients.add(getCoefficients(FundamentalName.L_E,     polynomials, name));
  174.                 coefficients.add(getCoefficients(FundamentalName.L_MA,    polynomials, name));
  175.                 coefficients.add(getCoefficients(FundamentalName.L_J,     polynomials, name));
  176.                 coefficients.add(getCoefficients(FundamentalName.L_SA,    polynomials, name));
  177.                 coefficients.add(getCoefficients(FundamentalName.L_U,     polynomials, name));
  178.                 coefficients.add(getCoefficients(FundamentalName.L_NE,    polynomials, name));
  179.                 coefficients.add(getCoefficients(FundamentalName.PA,      polynomials, name));
  180.             } else {
  181.                 // IERS conventions 1996 and earlier don't provide planetary nutation arguments
  182.                 final double[] zero = new double[] {
  183.                     0.0
  184.                 };
  185.                 while (coefficients.size() < n) {
  186.                     coefficients.add(zero);
  187.                 }
  188.             }

  189.             return coefficients;

  190.         } catch (IOException ioe) {
  191.             throw new OrekitException(ioe, new DummyLocalizable(ioe.getMessage()));
  192.         }

  193.     }

  194.     /** Get the coefficients for a fundamental argument.
  195.      * @param argument fundamental argument
  196.      * @param polynomials map of the polynomials
  197.      * @param fileName name of the file from which the coefficients have been read
  198.      * @return polynomials coefficients (ordered from high degrees to low degrees)
  199.      * @exception OrekitException if the argument is not found
  200.      */
  201.     private static double[] getCoefficients(final FundamentalName argument,
  202.                                             final Map<FundamentalName, double[]> polynomials,
  203.                                             final String fileName)
  204.         throws OrekitException {
  205.         if (!polynomials.containsKey(argument)) {
  206.             throw new OrekitException(OrekitMessages.NOT_A_SUPPORTED_IERS_DATA_FILE, fileName);
  207.         }
  208.         return polynomials.get(argument);
  209.     }

  210.     /** Evaluate a polynomial.
  211.      * @param tc offset in Julian centuries
  212.      * @param coefficients polynomial coefficients (ordered from low degrees to high degrees)
  213.      * @return value of the polynomial
  214.      */
  215.     private double value(final double tc, final double[] coefficients) {
  216.         double value = 0;
  217.         for (int i = coefficients.length - 1; i >= 0; --i) {
  218.             value = coefficients[i] + tc * value;
  219.         }
  220.         return value;
  221.     }

  222.     /** Evaluate all fundamental arguments for the current date (Delaunay plus planetary).
  223.      * @param date current date
  224.      * @return all fundamental arguments for the current date (Delaunay plus planetary)
  225.      */
  226.     public BodiesElements evaluateAll(final AbsoluteDate date) {

  227.         final double tc = conventions.evaluateTC(date);
  228.         final double gamma = gmstFunction == null ?
  229.                              Double.NaN : gmstFunction.value(date).getValue() + FastMath.PI;

  230.         return new BodiesElements(date, tc, gamma,
  231.                                   value(tc, lCoefficients),      // mean anomaly of the Moon
  232.                                   value(tc, lPrimeCoefficients), // mean anomaly of the Sun
  233.                                   value(tc, fCoefficients),      // L - &Omega; where L is the mean longitude of the Moon
  234.                                   value(tc, dCoefficients),      // mean elongation of the Moon from the Sun
  235.                                   value(tc, omegaCoefficients),  // mean longitude of the ascending node of the Moon
  236.                                   value(tc, lMeCoefficients),    // mean Mercury longitude
  237.                                   value(tc, lVeCoefficients),    // mean Venus longitude
  238.                                   value(tc, lECoefficients),     // mean Earth longitude
  239.                                   value(tc, lMaCoefficients),    // mean Mars longitude
  240.                                   value(tc, lJCoefficients),     // mean Jupiter longitude
  241.                                   value(tc, lSaCoefficients),    // mean Saturn longitude
  242.                                   value(tc, lUCoefficients),     // mean Uranus longitude
  243.                                   value(tc, lNeCoefficients),    // mean Neptune longitude
  244.                                   value(tc, paCoefficients));    // general accumulated precession in longitude

  245.     }

  246.     /** Evaluate a polynomial.
  247.      * @param tc offset in Julian centuries
  248.      * @param coefficients polynomial coefficients (ordered from low degrees to high degrees)
  249.      * @return value of the polynomial
  250.      */
  251.     private DerivativeStructure value(final DerivativeStructure tc, final double[] coefficients) {
  252.         DerivativeStructure value = tc.getField().getZero();
  253.         for (int i = coefficients.length - 1; i >= 0; --i) {
  254.             value = value.multiply(tc).add(coefficients[i]);
  255.         }
  256.         return value;
  257.     }

  258.     /** Evaluate all fundamental arguments for the current date (Delaunay plus planetary),
  259.      * including the first time derivative.
  260.      * @param date current date
  261.      * @return all fundamental arguments for the current date (Delaunay plus planetary),
  262.      * including the first time derivative
  263.      */
  264.     public FieldBodiesElements<DerivativeStructure> evaluateDerivative(final AbsoluteDate date) {

  265.         final DerivativeStructure tc = conventions.dsEvaluateTC(date);

  266.         return new FieldBodiesElements<DerivativeStructure>(date, tc,
  267.                                                             gmstFunction.value(date).add(FastMath.PI),
  268.                                                             value(tc, lCoefficients),      // mean anomaly of the Moon
  269.                                                             value(tc, lPrimeCoefficients), // mean anomaly of the Sun
  270.                                                             value(tc, fCoefficients),      // L - &Omega; where L is the mean longitude of the Moon
  271.                                                             value(tc, dCoefficients),      // mean elongation of the Moon from the Sun
  272.                                                             value(tc, omegaCoefficients),  // mean longitude of the ascending node of the Moon
  273.                                                             value(tc, lMeCoefficients),    // mean Mercury longitude
  274.                                                             value(tc, lVeCoefficients),    // mean Venus longitude
  275.                                                             value(tc, lECoefficients),     // mean Earth longitude
  276.                                                             value(tc, lMaCoefficients),    // mean Mars longitude
  277.                                                             value(tc, lJCoefficients),     // mean Jupiter longitude
  278.                                                             value(tc, lSaCoefficients),    // mean Saturn longitude
  279.                                                             value(tc, lUCoefficients),     // mean Uranus longitude
  280.                                                             value(tc, lNeCoefficients),    // mean Neptune longitude
  281.                                                             value(tc, paCoefficients));    // general accumulated precession in longitude

  282.     }

  283.     /** Replace the instance with a data transfer object for serialization.
  284.      * <p>
  285.      * This intermediate class serializes only the frame key.
  286.      * </p>
  287.      * @return data transfer object that will be serialized
  288.      */
  289.     private Object writeReplace() {
  290.         return new DataTransferObject(conventions, timeScale,
  291.                                       Arrays.asList(lCoefficients, lPrimeCoefficients, fCoefficients,
  292.                                                     dCoefficients, omegaCoefficients,
  293.                                                     lMeCoefficients, lVeCoefficients, lECoefficients,
  294.                                                     lMaCoefficients, lJCoefficients, lSaCoefficients,
  295.                                                     lUCoefficients, lNeCoefficients, paCoefficients));
  296.     }

  297.     /** Internal class used only for serialization. */
  298.     private static class DataTransferObject implements Serializable {

  299.         /** Serializable UID. */
  300.         private static final long serialVersionUID = 20131209L;

  301.         /** IERS conventions to use. */
  302.         private final IERSConventions conventions;

  303.         /** Time scale for GMST computation. */
  304.         private final TimeScale timeScale;

  305.         /** All coefficients. */
  306.         private final List<double[]> coefficients;

  307.         /** Simple constructor.
  308.          * @param conventions IERS conventions to use
  309.          * @param timeScale time scale for GMST computation
  310.          * @param coefficients all coefficients
  311.          */
  312.         public DataTransferObject(final IERSConventions conventions, final TimeScale timeScale,
  313.                                   final List<double[]> coefficients) {
  314.             this.conventions  = conventions;
  315.             this.timeScale    = timeScale;
  316.             this.coefficients = coefficients;
  317.         }

  318.         /** Replace the deserialized data transfer object with a {@link TIRFProvider}.
  319.          * @return replacement {@link TIRFProvider}
  320.          */
  321.         private Object readResolve() {
  322.             try {
  323.                 // retrieve a managed frame
  324.                 return new FundamentalNutationArguments(conventions, timeScale, coefficients);
  325.             } catch (OrekitException oe) {
  326.                 throw OrekitException.createInternalError(oe);
  327.             }
  328.         }

  329.     }

  330.     /** Enumerate for the fundamental names. */
  331.     private enum FundamentalName {

  332.         /** Constant for Mean anomaly of the Moon. */
  333.         L() {
  334.             /** {@inheritDoc} */
  335.             public String getArgumentName() {
  336.                 return "l";
  337.             }
  338.         },

  339.         /** Constant for Mean anomaly of the Sun. */
  340.         L_PRIME() {
  341.             /** {@inheritDoc} */
  342.             public String getArgumentName() {
  343.                 return "l'";
  344.             }
  345.         },

  346.         /** Constant for L - &Omega; where L is the mean longitude of the Moon. */
  347.         F() {
  348.             /** {@inheritDoc} */
  349.             public String getArgumentName() {
  350.                 return "F";
  351.             }
  352.         },

  353.         /** Constant for mean elongation of the Moon from the Sun. */
  354.         D() {
  355.             /** {@inheritDoc} */
  356.             public String getArgumentName() {
  357.                 return "D";
  358.             }
  359.         },

  360.         /** Constant for longitude of the ascending node of the Moon. */
  361.         OMEGA() {
  362.             /** {@inheritDoc} */
  363.             public String getArgumentName() {
  364.                 return "\u03a9";
  365.             }
  366.         },

  367.         /** Constant for mean Mercury longitude. */
  368.         L_ME() {
  369.             /** {@inheritDoc} */
  370.             public String getArgumentName() {
  371.                 return "LMe";
  372.             }
  373.         },

  374.         /** Constant for mean Venus longitude. */
  375.         L_VE() {
  376.             /** {@inheritDoc} */
  377.             public String getArgumentName() {
  378.                 return "LVe";
  379.             }
  380.         },

  381.         /** Constant for mean Earth longitude. */
  382.         L_E() {
  383.             /** {@inheritDoc} */
  384.             public String getArgumentName() {
  385.                 return "LE";
  386.             }
  387.         },

  388.         /** Constant for mean Mars longitude. */
  389.         L_MA() {
  390.             /** {@inheritDoc} */
  391.             public String getArgumentName() {
  392.                 return "LMa";
  393.             }
  394.         },

  395.         /** Constant for mean Jupiter longitude. */
  396.         L_J() {
  397.             /** {@inheritDoc} */
  398.             public String getArgumentName() {
  399.                 return "LJ";
  400.             }
  401.         },

  402.         /** Constant for mean Saturn longitude. */
  403.         L_SA() {
  404.             /** {@inheritDoc} */
  405.             public String getArgumentName() {
  406.                 return "LSa";
  407.             }
  408.         },

  409.         /** Constant for mean Uranus longitude. */
  410.         L_U() {
  411.             /** {@inheritDoc} */
  412.             public String getArgumentName() {
  413.                 return "LU";
  414.             }
  415.         },

  416.         /** Constant for mean Neptune longitude. */
  417.         L_NE() {
  418.             /** {@inheritDoc} */
  419.             public String getArgumentName() {
  420.                 return "LNe";
  421.             }
  422.         },

  423.         /** Constant for general accumulated precession in longitude. */
  424.         PA() {
  425.             /** {@inheritDoc} */
  426.             public String getArgumentName() {
  427.                 return "pA";
  428.             }
  429.         };

  430.         /** Get the fundamental name.
  431.          * @return fundamental name
  432.          */
  433.         public abstract String getArgumentName();

  434.     }

  435.     /** Local parser for argument definition lines. */
  436.     private static class DefinitionParser {

  437.         /** Regular expression pattern for definitions. */
  438.         private final Pattern pattern;

  439.         /** Parser for polynomials. */
  440.         private PolynomialParser polynomialParser;

  441.         /** Last parsed fundamental name. */
  442.         private FundamentalName parsedName;

  443.         /** Last parsed polynomial. */
  444.         private double[] parsedPolynomial;

  445.         /** Simple constructor. */
  446.         public DefinitionParser() {

  447.             // the luni-solar Delaunay arguments polynomial parts should read something like:
  448.             // F5 ≡ Ω = 125.04455501° − 6962890.5431″t + 7.4722″t² + 0.007702″t³ − 0.00005939″t⁴
  449.             // whereas the planetary arguments polynomial parts should read something like:
  450.             // F14 ≡ pA  = 0.02438175 × t + 0.00000538691 × t²
  451.             final String unicodeIdenticalTo = "\u2261";

  452.             // pattern for the global line
  453.             final StringBuilder builder = new StringBuilder();
  454.             for (final FundamentalName fn : FundamentalName.values()) {
  455.                 if (builder.length() > 0) {
  456.                     builder.append('|');
  457.                 }
  458.                 builder.append(fn.getArgumentName());
  459.             }
  460.             final String fundamentalName = "\\p{Space}*((?:" + builder.toString() + ")+)";
  461.             pattern = Pattern.compile("\\p{Space}*F\\p{Digit}+\\p{Space}*" + unicodeIdenticalTo +
  462.                                       fundamentalName + "\\p{Space}*=\\p{Space}*(.*)");

  463.             polynomialParser = new PolynomialParser('t', PolynomialParser.Unit.NO_UNITS);

  464.         }

  465.         /** Parse a definition line.
  466.          * @param line line to parse
  467.          * @param lineNumber line number
  468.          * @param fileName name of the file
  469.          * @return true if a definition has been parsed
  470.          */
  471.         public boolean parseDefinition(final String line, final int lineNumber, final String fileName) {

  472.             parsedName       = null;
  473.             parsedPolynomial = null;

  474.             final Matcher matcher = pattern.matcher(line);
  475.             if (matcher.matches()) {
  476.                 for (FundamentalName fn : FundamentalName.values()) {
  477.                     if (fn.getArgumentName().equals(matcher.group(1))) {
  478.                         parsedName = fn;
  479.                     }
  480.                 }

  481.                 // parse the polynomial
  482.                 parsedPolynomial = polynomialParser.parse(matcher.group(2));

  483.                 return true;

  484.             } else {
  485.                 return false;
  486.             }

  487.         }

  488.         /** Get the last parsed fundamental name.
  489.          * @return last parsed fundamental name
  490.          */
  491.         public FundamentalName getParsedName() {
  492.             return parsedName;
  493.         }

  494.         /** Get the last parsed polynomial.
  495.          * @return last parsed polynomial
  496.          */
  497.         public double[] getParsedPolynomial() {
  498.             return parsedPolynomial.clone();
  499.         }

  500.     }

  501. }