FundamentalNutationArguments.java

  1. /* Copyright 2002-2024 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.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.nio.charset.StandardCharsets;
  24. import java.util.ArrayList;
  25. import java.util.Arrays;
  26. import java.util.HashMap;
  27. import java.util.List;
  28. import java.util.Map;
  29. import java.util.regex.Matcher;
  30. import java.util.regex.Pattern;

  31. import org.hipparchus.CalculusFieldElement;
  32. import org.hipparchus.exception.DummyLocalizable;
  33. import org.hipparchus.util.FastMath;
  34. import org.orekit.annotation.DefaultDataContext;
  35. import org.orekit.errors.OrekitException;
  36. import org.orekit.errors.OrekitInternalError;
  37. import org.orekit.errors.OrekitMessages;
  38. import org.orekit.time.AbsoluteDate;
  39. import org.orekit.time.FieldAbsoluteDate;
  40. import org.orekit.time.TimeScalarFunction;
  41. import org.orekit.time.TimeScale;
  42. import org.orekit.time.TimeScales;
  43. import org.orekit.utils.Constants;
  44. import org.orekit.utils.IERSConventions;

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

  61.     /** Serializable UID. */
  62.     private static final long serialVersionUID = 20131209L;

  63.     /** IERS conventions to use. */
  64.     private final IERSConventions conventions;

  65.     /** Time scale for GMST computation. */
  66.     private final TimeScale timeScale;

  67.     /** Function computing Greenwich Mean Sidereal Time. */
  68.     private final transient TimeScalarFunction gmstFunction;

  69.     /** Function computing Greenwich Mean Sidereal Time rate. */
  70.     private final transient TimeScalarFunction gmstRateFunction;

  71.     // luni-solar Delaunay arguments

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

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

  76.     /** Coefficients for L - Ω where L is the mean longitude of the Moon. */
  77.     private final double[] fCoefficients;

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

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

  82.     // planetary nutation arguments

  83.     /** Coefficients for mean Mercury longitude. */
  84.     private final double[] lMeCoefficients;

  85.     /** Coefficients for mean Venus longitude. */
  86.     private final double[] lVeCoefficients;

  87.     /** Coefficients for mean Earth longitude. */
  88.     private final double[] lECoefficients;

  89.     /** Coefficients for mean Mars longitude. */
  90.     private final double[] lMaCoefficients;

  91.     /** Coefficients for mean Jupiter longitude. */
  92.     private final double[] lJCoefficients;

  93.     /** Coefficients for mean Saturn longitude. */
  94.     private final double[] lSaCoefficients;

  95.     /** Coefficients for mean Uranus longitude. */
  96.     private final double[] lUCoefficients;

  97.     /** Coefficients for mean Neptune longitude. */
  98.     private final double[] lNeCoefficients;

  99.     /** Coefficients for general accumulated precession. */
  100.     private final double[] paCoefficients;

  101.     /** Set of time scales to use in computations. */
  102.     private final transient TimeScales timeScales;

  103.     /** Build a model of fundamental arguments from an IERS table file.
  104.      *
  105.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  106.      *
  107.      * @param conventions IERS conventions to use
  108.      * @param timeScale time scale for GMST computation
  109.      * (may be null if tide parameter γ = GMST + π is not needed)
  110.      * @param stream stream containing the IERS table
  111.      * @param name name of the resource file (for error messages only)
  112.      * @see #FundamentalNutationArguments(IERSConventions, TimeScale, List, TimeScales)
  113.      * @see #FundamentalNutationArguments(IERSConventions, TimeScale, InputStream, String, TimeScales)
  114.      */
  115.     @DefaultDataContext
  116.     public FundamentalNutationArguments(final IERSConventions conventions,
  117.                                         final TimeScale timeScale,
  118.                                         final InputStream stream, final String name) {
  119.         this(conventions, timeScale, stream, name,
  120.                 DataContext.getDefault().getTimeScales());
  121.     }

  122.     /**
  123.      * Build a model of fundamental arguments from an IERS table file.
  124.      *
  125.      * @param conventions IERS conventions to use
  126.      * @param timeScale   time scale for GMST computation (may be null if tide parameter γ
  127.      *                    = GMST + π is not needed)
  128.      * @param stream      stream containing the IERS table
  129.      * @param name        name of the resource file (for error messages only)
  130.      * @param timeScales         TAI time scale
  131.      * @see #FundamentalNutationArguments(IERSConventions, TimeScale, List, TimeScales)
  132.      * @since 10.1
  133.      */
  134.     public FundamentalNutationArguments(final IERSConventions conventions,
  135.                                         final TimeScale timeScale,
  136.                                         final InputStream stream,
  137.                                         final String name,
  138.                                         final TimeScales timeScales) {
  139.         this(conventions, timeScale, parseCoefficients(stream, name), timeScales);
  140.     }

  141.     /** Build a model of fundamental arguments from an IERS table file.
  142.      *
  143.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  144.      *
  145.      * @param conventions IERS conventions to use
  146.      * @param timeScale time scale for GMST computation
  147.      * (may be null if tide parameter γ = GMST + π is not needed)
  148.      * @param coefficients list of coefficients arrays (all 14 arrays must be provided,
  149.      * the 5 Delaunay first and the 9 planetary afterwards)
  150.      * @since 6.1
  151.      * @see #FundamentalNutationArguments(IERSConventions, TimeScale, List, TimeScales)
  152.      */
  153.     @DefaultDataContext
  154.     public FundamentalNutationArguments(final IERSConventions conventions, final TimeScale timeScale,
  155.                                         final List<double[]> coefficients) {
  156.         this(conventions, timeScale, coefficients,
  157.                 DataContext.getDefault().getTimeScales());
  158.     }

  159.     /** Build a model of fundamental arguments from an IERS table file.
  160.      * @param conventions IERS conventions to use
  161.      * @param timeScale time scale for GMST computation
  162.      * (may be null if tide parameter γ = GMST + π is not needed)
  163.      * @param coefficients list of coefficients arrays (all 14 arrays must be provided,
  164.      * the 5 Delaunay first and the 9 planetary afterwards)
  165.      * @param timeScales used in the computation.
  166.      * @since 10.1
  167.      */
  168.     public FundamentalNutationArguments(final IERSConventions conventions,
  169.                                         final TimeScale timeScale,
  170.                                         final List<double[]> coefficients,
  171.                                         final TimeScales timeScales) {
  172.         this.conventions        = conventions;
  173.         this.timeScale          = timeScale;
  174.         this.timeScales         = timeScales;
  175.         this.gmstFunction       = (timeScale == null) ? null :
  176.                 conventions.getGMSTFunction(timeScale, timeScales);
  177.         this.gmstRateFunction   = (timeScale == null) ? null :
  178.                 conventions.getGMSTRateFunction(timeScale, timeScales);
  179.         this.lCoefficients      = coefficients.get( 0);
  180.         this.lPrimeCoefficients = coefficients.get( 1);
  181.         this.fCoefficients      = coefficients.get( 2);
  182.         this.dCoefficients      = coefficients.get( 3);
  183.         this.omegaCoefficients  = coefficients.get( 4);
  184.         this.lMeCoefficients    = coefficients.get( 5);
  185.         this.lVeCoefficients    = coefficients.get( 6);
  186.         this.lECoefficients     = coefficients.get( 7);
  187.         this.lMaCoefficients    = coefficients.get( 8);
  188.         this.lJCoefficients     = coefficients.get( 9);
  189.         this.lSaCoefficients    = coefficients.get(10);
  190.         this.lUCoefficients     = coefficients.get(11);
  191.         this.lNeCoefficients    = coefficients.get(12);
  192.         this.paCoefficients     = coefficients.get(13);
  193.     }

  194.     /** Parse coefficients.
  195.      * @param stream stream containing the IERS table
  196.      * @param name name of the resource file (for error messages only)
  197.      * @return list of coefficients arrays
  198.      */
  199.     private static List<double[]> parseCoefficients(final InputStream stream, final String name) {

  200.         if (stream == null) {
  201.             throw new OrekitException(OrekitMessages.UNABLE_TO_FIND_FILE, name);
  202.         }

  203.         // setup the reader
  204.         try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) {

  205.             final DefinitionParser definitionParser = new DefinitionParser();

  206.             int lineNumber = 0;

  207.             // look for the reference date and the 14 polynomials
  208.             final int n = FundamentalName.values().length;
  209.             final Map<FundamentalName, double[]> polynomials = new HashMap<FundamentalName, double[]>(n);
  210.             for (String line = reader.readLine(); line != null; line = reader.readLine()) {
  211.                 lineNumber++;
  212.                 if (definitionParser.parseDefinition(line, lineNumber, name)) {
  213.                     polynomials.put(definitionParser.getParsedName(),
  214.                                     definitionParser.getParsedPolynomial());
  215.                 }
  216.             }

  217.             final List<double[]> coefficients = new ArrayList<double[]>(n);
  218.             coefficients.add(getCoefficients(FundamentalName.L,       polynomials, name));
  219.             coefficients.add(getCoefficients(FundamentalName.L_PRIME, polynomials, name));
  220.             coefficients.add(getCoefficients(FundamentalName.F,       polynomials, name));
  221.             coefficients.add(getCoefficients(FundamentalName.D,       polynomials, name));
  222.             coefficients.add(getCoefficients(FundamentalName.OMEGA,   polynomials, name));
  223.             if (polynomials.containsKey(FundamentalName.L_ME)) {
  224.                 // IERS conventions 2003 and later provide planetary nutation arguments
  225.                 coefficients.add(getCoefficients(FundamentalName.L_ME,    polynomials, name));
  226.                 coefficients.add(getCoefficients(FundamentalName.L_VE,    polynomials, name));
  227.                 coefficients.add(getCoefficients(FundamentalName.L_E,     polynomials, name));
  228.                 coefficients.add(getCoefficients(FundamentalName.L_MA,    polynomials, name));
  229.                 coefficients.add(getCoefficients(FundamentalName.L_J,     polynomials, name));
  230.                 coefficients.add(getCoefficients(FundamentalName.L_SA,    polynomials, name));
  231.                 coefficients.add(getCoefficients(FundamentalName.L_U,     polynomials, name));
  232.                 coefficients.add(getCoefficients(FundamentalName.L_NE,    polynomials, name));
  233.                 coefficients.add(getCoefficients(FundamentalName.PA,      polynomials, name));
  234.             } else {
  235.                 // IERS conventions 1996 and earlier don't provide planetary nutation arguments
  236.                 final double[] zero = new double[] {
  237.                     0.0
  238.                 };
  239.                 while (coefficients.size() < n) {
  240.                     coefficients.add(zero);
  241.                 }
  242.             }

  243.             return coefficients;

  244.         } catch (IOException ioe) {
  245.             throw new OrekitException(ioe, new DummyLocalizable(ioe.getMessage()));
  246.         }

  247.     }

  248.     /** Get the coefficients for a fundamental argument.
  249.      * @param argument fundamental argument
  250.      * @param polynomials map of the polynomials
  251.      * @param fileName name of the file from which the coefficients have been read
  252.      * @return polynomials coefficients (ordered from high degrees to low degrees)
  253.      */
  254.     private static double[] getCoefficients(final FundamentalName argument,
  255.                                             final Map<FundamentalName, double[]> polynomials,
  256.                                             final String fileName) {
  257.         if (!polynomials.containsKey(argument)) {
  258.             throw new OrekitException(OrekitMessages.NOT_A_SUPPORTED_IERS_DATA_FILE, fileName);
  259.         }
  260.         return polynomials.get(argument);
  261.     }

  262.     /** Evaluate a polynomial.
  263.      * @param tc offset in Julian centuries
  264.      * @param coefficients polynomial coefficients (ordered from low degrees to high degrees)
  265.      * @return value of the polynomial
  266.      */
  267.     private double value(final double tc, final double[] coefficients) {
  268.         double value = 0;
  269.         for (int i = coefficients.length - 1; i >= 0; --i) {
  270.             value = coefficients[i] + tc * value;
  271.         }
  272.         return value;
  273.     }

  274.     /** Evaluate a polynomial time derivative.
  275.      * @param tc offset in Julian centuries
  276.      * @param coefficients polynomial coefficients (ordered from low degrees to high degrees)
  277.      * @return time derivative of the polynomial
  278.      */
  279.     private double derivative(final double tc, final double[] coefficients) {
  280.         double derivative = 0;
  281.         for (int i = coefficients.length - 1; i > 0; --i) {
  282.             derivative = i * coefficients[i] + tc * derivative;
  283.         }
  284.         return derivative / Constants.JULIAN_CENTURY;
  285.     }

  286.     /** Evaluate a polynomial.
  287.      * @param tc offset in Julian centuries
  288.      * @param <T> type of the field elements
  289.      * @param coefficients polynomial coefficients (ordered from low degrees to high degrees)
  290.      * @return value of the polynomial
  291.      */
  292.     private <T extends CalculusFieldElement<T>> T value(final T tc, final double[] coefficients) {
  293.         T value = tc.getField().getZero();
  294.         for (int i = coefficients.length - 1; i >= 0; --i) {
  295.             value = tc.multiply(value).add(coefficients[i]);
  296.         }
  297.         return value;
  298.     }

  299.     /** Evaluate a polynomial time derivative.
  300.      * @param tc offset in Julian centuries
  301.      * @param <T> type of the field elements
  302.      * @param coefficients polynomial coefficients (ordered from low degrees to high degrees)
  303.      * @return time derivative of the polynomial
  304.      */
  305.     private <T extends CalculusFieldElement<T>> T derivative(final T tc, final double[] coefficients) {
  306.         T derivative = tc.getField().getZero();
  307.         for (int i = coefficients.length - 1; i > 0; --i) {
  308.             derivative = tc.multiply(derivative).add(i * coefficients[i]);
  309.         }
  310.         return derivative.divide(Constants.JULIAN_CENTURY);
  311.     }

  312.     /** Evaluate all fundamental arguments for the current date (Delaunay plus planetary).
  313.      * @param date current date
  314.      * @return all fundamental arguments for the current date (Delaunay plus planetary)
  315.      */
  316.     public BodiesElements evaluateAll(final AbsoluteDate date) {

  317.         final double tc       = conventions.evaluateTC(date, timeScales);
  318.         final double gamma    = gmstFunction == null ?
  319.                                 Double.NaN : gmstFunction.value(date) + FastMath.PI;
  320.         final double gammaDot = gmstRateFunction == null ?
  321.                                 Double.NaN : gmstRateFunction.value(date);

  322.         return new BodiesElements(date, tc, gamma, gammaDot,
  323.                                   value(tc, lCoefficients),           // mean anomaly of the Moon
  324.                                   derivative(tc, lCoefficients),      // mean anomaly of the Moon time derivative
  325.                                   value(tc, lPrimeCoefficients),      // mean anomaly of the Sun
  326.                                   derivative(tc, lPrimeCoefficients), // mean anomaly of the Sun time derivative
  327.                                   value(tc, fCoefficients),           // L - Ω where L is the mean longitude of the Moon
  328.                                   derivative(tc, fCoefficients),      // L - Ω where L is the mean longitude of the Moon time derivative
  329.                                   value(tc, dCoefficients),           // mean elongation of the Moon from the Sun
  330.                                   derivative(tc, dCoefficients),      // mean elongation of the Moon from the Sun time derivative
  331.                                   value(tc, omegaCoefficients),       // mean longitude of the ascending node of the Moon
  332.                                   derivative(tc, omegaCoefficients),  // mean longitude of the ascending node of the Moon time derivative
  333.                                   value(tc, lMeCoefficients),         // mean Mercury longitude
  334.                                   derivative(tc, lMeCoefficients),    // mean Mercury longitude time derivative
  335.                                   value(tc, lVeCoefficients),         // mean Venus longitude
  336.                                   derivative(tc, lVeCoefficients),    // mean Venus longitude time derivative
  337.                                   value(tc, lECoefficients),          // mean Earth longitude
  338.                                   derivative(tc, lECoefficients),     // mean Earth longitude time derivative
  339.                                   value(tc, lMaCoefficients),         // mean Mars longitude
  340.                                   derivative(tc, lMaCoefficients),    // mean Mars longitude time derivative
  341.                                   value(tc, lJCoefficients),          // mean Jupiter longitude
  342.                                   derivative(tc, lJCoefficients),     // mean Jupiter longitude time derivative
  343.                                   value(tc, lSaCoefficients),         // mean Saturn longitude
  344.                                   derivative(tc, lSaCoefficients),    // mean Saturn longitude time derivative
  345.                                   value(tc, lUCoefficients),          // mean Uranus longitude
  346.                                   derivative(tc, lUCoefficients),     // mean Uranus longitude time derivative
  347.                                   value(tc, lNeCoefficients),         // mean Neptune longitude
  348.                                   derivative(tc, lNeCoefficients),    // mean Neptune longitude time derivative
  349.                                   value(tc, paCoefficients),          // general accumulated precession in longitude
  350.                                   derivative(tc, paCoefficients));    // general accumulated precession in longitude time derivative

  351.     }

  352.     /** Evaluate all fundamental arguments for the current date (Delaunay plus planetary).
  353.      * @param date current date
  354.      * @param <T> type of the field elements
  355.      * @return all fundamental arguments for the current date (Delaunay plus planetary)
  356.      */
  357.     public <T extends CalculusFieldElement<T>> FieldBodiesElements<T> evaluateAll(final FieldAbsoluteDate<T> date) {

  358.         final T tc       = conventions.evaluateTC(date, timeScales);
  359.         final T gamma    = gmstFunction == null ?
  360.                            tc.getField().getZero().add(Double.NaN) : gmstFunction.value(date).add(tc.getPi());
  361.         final T gammaDot = gmstRateFunction == null ?
  362.                            tc.getField().getZero().add(Double.NaN) : gmstRateFunction.value(date);

  363.         return new FieldBodiesElements<>(date, tc, gamma, gammaDot,
  364.                                          value(tc, lCoefficients),           // mean anomaly of the Moon
  365.                                          derivative(tc, lCoefficients),      // mean anomaly of the Moon time derivative
  366.                                          value(tc, lPrimeCoefficients),      // mean anomaly of the Sun
  367.                                          derivative(tc, lPrimeCoefficients), // mean anomaly of the Sun time derivative
  368.                                          value(tc, fCoefficients),           // L - Ω where L is the mean longitude of the Moon
  369.                                          derivative(tc, fCoefficients),      // L - Ω where L is the mean longitude of the Moon time derivative
  370.                                          value(tc, dCoefficients),           // mean elongation of the Moon from the Sun
  371.                                          derivative(tc, dCoefficients),      // mean elongation of the Moon from the Sun time derivative
  372.                                          value(tc, omegaCoefficients),       // mean longitude of the ascending node of the Moon
  373.                                          derivative(tc, omegaCoefficients),  // mean longitude of the ascending node of the Moon time derivative
  374.                                          value(tc, lMeCoefficients),         // mean Mercury longitude
  375.                                          derivative(tc, lMeCoefficients),    // mean Mercury longitude time derivative
  376.                                          value(tc, lVeCoefficients),         // mean Venus longitude
  377.                                          derivative(tc, lVeCoefficients),    // mean Venus longitude time derivative
  378.                                          value(tc, lECoefficients),          // mean Earth longitude
  379.                                          derivative(tc, lECoefficients),     // mean Earth longitude time derivative
  380.                                          value(tc, lMaCoefficients),         // mean Mars longitude
  381.                                          derivative(tc, lMaCoefficients),    // mean Mars longitude time derivative
  382.                                          value(tc, lJCoefficients),          // mean Jupiter longitude
  383.                                          derivative(tc, lJCoefficients),     // mean Jupiter longitude time derivative
  384.                                          value(tc, lSaCoefficients),         // mean Saturn longitude
  385.                                          derivative(tc, lSaCoefficients),    // mean Saturn longitude time derivative
  386.                                          value(tc, lUCoefficients),          // mean Uranus longitude
  387.                                          derivative(tc, lUCoefficients),     // mean Uranus longitude time derivative
  388.                                          value(tc, lNeCoefficients),         // mean Neptune longitude
  389.                                          derivative(tc, lNeCoefficients),    // mean Neptune longitude time derivative
  390.                                          value(tc, paCoefficients),          // general accumulated precession in longitude
  391.                                          derivative(tc, paCoefficients));    // general accumulated precession in longitude time derivative

  392.     }

  393.     /** Replace the instance with a data transfer object for serialization.
  394.      * <p>
  395.      * This intermediate class serializes only the frame key.
  396.      * </p>
  397.      * @return data transfer object that will be serialized
  398.      */
  399.     @DefaultDataContext
  400.     private Object writeReplace() {
  401.         return new DataTransferObject(conventions, timeScale,
  402.                                       Arrays.asList(lCoefficients, lPrimeCoefficients, fCoefficients,
  403.                                                     dCoefficients, omegaCoefficients,
  404.                                                     lMeCoefficients, lVeCoefficients, lECoefficients,
  405.                                                     lMaCoefficients, lJCoefficients, lSaCoefficients,
  406.                                                     lUCoefficients, lNeCoefficients, paCoefficients));
  407.     }

  408.     /** Internal class used only for serialization. */
  409.     @DefaultDataContext
  410.     private static class DataTransferObject implements Serializable {

  411.         /** Serializable UID. */
  412.         private static final long serialVersionUID = 20131209L;

  413.         /** IERS conventions to use. */
  414.         private final IERSConventions conventions;

  415.         /** Time scale for GMST computation. */
  416.         private final TimeScale timeScale;

  417.         /** All coefficients. */
  418.         private final List<double[]> coefficients;

  419.         /** Simple constructor.
  420.          * @param conventions IERS conventions to use
  421.          * @param timeScale time scale for GMST computation
  422.          * @param coefficients all coefficients
  423.          */
  424.         DataTransferObject(final IERSConventions conventions, final TimeScale timeScale,
  425.                                   final List<double[]> coefficients) {
  426.             this.conventions  = conventions;
  427.             this.timeScale    = timeScale;
  428.             this.coefficients = coefficients;
  429.         }

  430.         /** Replace the deserialized data transfer object with a {@link TIRFProvider}.
  431.          * @return replacement {@link TIRFProvider}
  432.          */
  433.         private Object readResolve() {
  434.             try {
  435.                 // retrieve a managed frame
  436.                 return new FundamentalNutationArguments(conventions, timeScale, coefficients);
  437.             } catch (OrekitException oe) {
  438.                 throw new OrekitInternalError(oe);
  439.             }
  440.         }

  441.     }

  442.     /** Enumerate for the fundamental names. */
  443.     private enum FundamentalName {

  444.         /** Constant for Mean anomaly of the Moon. */
  445.         L() {
  446.             /** {@inheritDoc} */
  447.             public String getArgumentName() {
  448.                 return "l";
  449.             }
  450.         },

  451.         /** Constant for Mean anomaly of the Sun. */
  452.         L_PRIME() {
  453.             /** {@inheritDoc} */
  454.             public String getArgumentName() {
  455.                 return "l'";
  456.             }
  457.         },

  458.         /** Constant for L - Ω where L is the mean longitude of the Moon. */
  459.         F() {
  460.             /** {@inheritDoc} */
  461.             public String getArgumentName() {
  462.                 return "F";
  463.             }
  464.         },

  465.         /** Constant for mean elongation of the Moon from the Sun. */
  466.         D() {
  467.             /** {@inheritDoc} */
  468.             public String getArgumentName() {
  469.                 return "D";
  470.             }
  471.         },

  472.         /** Constant for longitude of the ascending node of the Moon. */
  473.         OMEGA() {
  474.             /** {@inheritDoc} */
  475.             public String getArgumentName() {
  476.                 return "\u03a9";
  477.             }
  478.         },

  479.         /** Constant for mean Mercury longitude. */
  480.         L_ME() {
  481.             /** {@inheritDoc} */
  482.             public String getArgumentName() {
  483.                 return "LMe";
  484.             }
  485.         },

  486.         /** Constant for mean Venus longitude. */
  487.         L_VE() {
  488.             /** {@inheritDoc} */
  489.             public String getArgumentName() {
  490.                 return "LVe";
  491.             }
  492.         },

  493.         /** Constant for mean Earth longitude. */
  494.         L_E() {
  495.             /** {@inheritDoc} */
  496.             public String getArgumentName() {
  497.                 return "LE";
  498.             }
  499.         },

  500.         /** Constant for mean Mars longitude. */
  501.         L_MA() {
  502.             /** {@inheritDoc} */
  503.             public String getArgumentName() {
  504.                 return "LMa";
  505.             }
  506.         },

  507.         /** Constant for mean Jupiter longitude. */
  508.         L_J() {
  509.             /** {@inheritDoc} */
  510.             public String getArgumentName() {
  511.                 return "LJ";
  512.             }
  513.         },

  514.         /** Constant for mean Saturn longitude. */
  515.         L_SA() {
  516.             /** {@inheritDoc} */
  517.             public String getArgumentName() {
  518.                 return "LSa";
  519.             }
  520.         },

  521.         /** Constant for mean Uranus longitude. */
  522.         L_U() {
  523.             /** {@inheritDoc} */
  524.             public String getArgumentName() {
  525.                 return "LU";
  526.             }
  527.         },

  528.         /** Constant for mean Neptune longitude. */
  529.         L_NE() {
  530.             /** {@inheritDoc} */
  531.             public String getArgumentName() {
  532.                 return "LNe";
  533.             }
  534.         },

  535.         /** Constant for general accumulated precession in longitude. */
  536.         PA() {
  537.             /** {@inheritDoc} */
  538.             public String getArgumentName() {
  539.                 return "pA";
  540.             }
  541.         };

  542.         /** Get the fundamental name.
  543.          * @return fundamental name
  544.          */
  545.         public abstract String getArgumentName();

  546.     }

  547.     /** Local parser for argument definition lines. */
  548.     private static class DefinitionParser {

  549.         /** Regular expression pattern for definitions. */
  550.         private final Pattern pattern;

  551.         /** Parser for polynomials. */
  552.         private PolynomialParser polynomialParser;

  553.         /** Last parsed fundamental name. */
  554.         private FundamentalName parsedName;

  555.         /** Last parsed polynomial. */
  556.         private double[] parsedPolynomial;

  557.         /** Simple constructor. */
  558.         DefinitionParser() {

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

  564.             // pattern for the global line
  565.             final StringBuilder builder = new StringBuilder();
  566.             for (final FundamentalName fn : FundamentalName.values()) {
  567.                 if (builder.length() > 0) {
  568.                     builder.append('|');
  569.                 }
  570.                 builder.append(fn.getArgumentName());
  571.             }
  572.             final String fundamentalName = "\\p{Space}*((?:" + builder.toString() + ")+)";
  573.             pattern = Pattern.compile("\\p{Space}*F\\p{Digit}+\\p{Space}*" + unicodeIdenticalTo +
  574.                                       fundamentalName + "\\p{Space}*=\\p{Space}*(.*)");

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

  576.         }

  577.         /** Parse a definition line.
  578.          * @param line line to parse
  579.          * @param lineNumber line number
  580.          * @param fileName name of the file
  581.          * @return true if a definition has been parsed
  582.          */
  583.         public boolean parseDefinition(final String line, final int lineNumber, final String fileName) {

  584.             parsedName       = null;
  585.             parsedPolynomial = null;

  586.             final Matcher matcher = pattern.matcher(line);
  587.             if (matcher.matches()) {
  588.                 for (FundamentalName fn : FundamentalName.values()) {
  589.                     if (fn.getArgumentName().equals(matcher.group(1))) {
  590.                         parsedName = fn;
  591.                     }
  592.                 }

  593.                 // parse the polynomial
  594.                 parsedPolynomial = polynomialParser.parse(matcher.group(2));

  595.                 return true;

  596.             } else {
  597.                 return false;
  598.             }

  599.         }

  600.         /** Get the last parsed fundamental name.
  601.          * @return last parsed fundamental name
  602.          */
  603.         public FundamentalName getParsedName() {
  604.             return parsedName;
  605.         }

  606.         /** Get the last parsed polynomial.
  607.          * @return last parsed polynomial
  608.          */
  609.         public double[] getParsedPolynomial() {
  610.             return parsedPolynomial.clone();
  611.         }

  612.     }

  613. }