FundamentalNutationArguments.java

  1. /* Copyright 2002-2025 CS GROUP
  2.  * Licensed to CS GROUP (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.data;

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

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

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

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

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

  62.     /** Function computing Greenwich Mean Sidereal Time. */
  63.     private final transient TimeScalarFunction gmstFunction;

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

  66.     // luni-solar Delaunay arguments

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

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

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

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

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

  77.     // planetary nutation arguments

  78.     /** Coefficients for mean Mercury longitude. */
  79.     private final double[] lMeCoefficients;

  80.     /** Coefficients for mean Venus longitude. */
  81.     private final double[] lVeCoefficients;

  82.     /** Coefficients for mean Earth longitude. */
  83.     private final double[] lECoefficients;

  84.     /** Coefficients for mean Mars longitude. */
  85.     private final double[] lMaCoefficients;

  86.     /** Coefficients for mean Jupiter longitude. */
  87.     private final double[] lJCoefficients;

  88.     /** Coefficients for mean Saturn longitude. */
  89.     private final double[] lSaCoefficients;

  90.     /** Coefficients for mean Uranus longitude. */
  91.     private final double[] lUCoefficients;

  92.     /** Coefficients for mean Neptune longitude. */
  93.     private final double[] lNeCoefficients;

  94.     /** Coefficients for general accumulated precession. */
  95.     private final double[] paCoefficients;

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

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

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

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

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

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

  195.         if (stream == null) {
  196.             throw new OrekitException(OrekitMessages.UNABLE_TO_FIND_FILE, name);
  197.         }

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

  200.             final DefinitionParser definitionParser = new DefinitionParser();

  201.             int lineNumber = 0;

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

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

  238.             return coefficients;

  239.         } catch (IOException ioe) {
  240.             throw new OrekitException(ioe, new DummyLocalizable(ioe.getMessage()));
  241.         }

  242.     }

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

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

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

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

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

  307.     /** Evaluate all fundamental arguments for the current date (Delaunay plus planetary).
  308.      * @param date current date
  309.      * @return all fundamental arguments for the current date (Delaunay plus planetary)
  310.      */
  311.     public BodiesElements evaluateAll(final AbsoluteDate date) {

  312.         final double tc       = conventions.evaluateTC(date, timeScales);
  313.         final double gamma    = gmstFunction == null ?
  314.                                 Double.NaN : gmstFunction.value(date) + FastMath.PI;
  315.         final double gammaDot = gmstRateFunction == null ?
  316.                                 Double.NaN : gmstRateFunction.value(date);

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

  346.     }

  347.     /** Evaluate all fundamental arguments for the current date (Delaunay plus planetary).
  348.      * @param date current date
  349.      * @param <T> type of the field elements
  350.      * @return all fundamental arguments for the current date (Delaunay plus planetary)
  351.      */
  352.     public <T extends CalculusFieldElement<T>> FieldBodiesElements<T> evaluateAll(final FieldAbsoluteDate<T> date) {

  353.         final T tc       = conventions.evaluateTC(date, timeScales);
  354.         final T gamma    = gmstFunction == null ?
  355.                            tc.getField().getZero().add(Double.NaN) : gmstFunction.value(date).add(tc.getPi());
  356.         final T gammaDot = gmstRateFunction == null ?
  357.                            tc.getField().getZero().add(Double.NaN) : gmstRateFunction.value(date);

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

  387.     }

  388.     /** Enumerate for the fundamental names. */
  389.     private enum FundamentalName {

  390.         /** Constant for Mean anomaly of the Moon. */
  391.         L() {
  392.             /** {@inheritDoc} */
  393.             public String getArgumentName() {
  394.                 return "l";
  395.             }
  396.         },

  397.         /** Constant for Mean anomaly of the Sun. */
  398.         L_PRIME() {
  399.             /** {@inheritDoc} */
  400.             public String getArgumentName() {
  401.                 return "l'";
  402.             }
  403.         },

  404.         /** Constant for L - Ω where L is the mean longitude of the Moon. */
  405.         F() {
  406.             /** {@inheritDoc} */
  407.             public String getArgumentName() {
  408.                 return "F";
  409.             }
  410.         },

  411.         /** Constant for mean elongation of the Moon from the Sun. */
  412.         D() {
  413.             /** {@inheritDoc} */
  414.             public String getArgumentName() {
  415.                 return "D";
  416.             }
  417.         },

  418.         /** Constant for longitude of the ascending node of the Moon. */
  419.         OMEGA() {
  420.             /** {@inheritDoc} */
  421.             public String getArgumentName() {
  422.                 return "\u03a9";
  423.             }
  424.         },

  425.         /** Constant for mean Mercury longitude. */
  426.         L_ME() {
  427.             /** {@inheritDoc} */
  428.             public String getArgumentName() {
  429.                 return "LMe";
  430.             }
  431.         },

  432.         /** Constant for mean Venus longitude. */
  433.         L_VE() {
  434.             /** {@inheritDoc} */
  435.             public String getArgumentName() {
  436.                 return "LVe";
  437.             }
  438.         },

  439.         /** Constant for mean Earth longitude. */
  440.         L_E() {
  441.             /** {@inheritDoc} */
  442.             public String getArgumentName() {
  443.                 return "LE";
  444.             }
  445.         },

  446.         /** Constant for mean Mars longitude. */
  447.         L_MA() {
  448.             /** {@inheritDoc} */
  449.             public String getArgumentName() {
  450.                 return "LMa";
  451.             }
  452.         },

  453.         /** Constant for mean Jupiter longitude. */
  454.         L_J() {
  455.             /** {@inheritDoc} */
  456.             public String getArgumentName() {
  457.                 return "LJ";
  458.             }
  459.         },

  460.         /** Constant for mean Saturn longitude. */
  461.         L_SA() {
  462.             /** {@inheritDoc} */
  463.             public String getArgumentName() {
  464.                 return "LSa";
  465.             }
  466.         },

  467.         /** Constant for mean Uranus longitude. */
  468.         L_U() {
  469.             /** {@inheritDoc} */
  470.             public String getArgumentName() {
  471.                 return "LU";
  472.             }
  473.         },

  474.         /** Constant for mean Neptune longitude. */
  475.         L_NE() {
  476.             /** {@inheritDoc} */
  477.             public String getArgumentName() {
  478.                 return "LNe";
  479.             }
  480.         },

  481.         /** Constant for general accumulated precession in longitude. */
  482.         PA() {
  483.             /** {@inheritDoc} */
  484.             public String getArgumentName() {
  485.                 return "pA";
  486.             }
  487.         };

  488.         /** Get the fundamental name.
  489.          * @return fundamental name
  490.          */
  491.         public abstract String getArgumentName();

  492.     }

  493.     /** Local parser for argument definition lines. */
  494.     private static class DefinitionParser {

  495.         /** Regular expression pattern for definitions. */
  496.         private final Pattern pattern;

  497.         /** Parser for polynomials. */
  498.         private PolynomialParser polynomialParser;

  499.         /** Last parsed fundamental name. */
  500.         private FundamentalName parsedName;

  501.         /** Last parsed polynomial. */
  502.         private double[] parsedPolynomial;

  503.         /** Simple constructor. */
  504.         DefinitionParser() {

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

  510.             // pattern for the global line
  511.             final StringBuilder builder = new StringBuilder();
  512.             for (final FundamentalName fn : FundamentalName.values()) {
  513.                 if (builder.length() > 0) {
  514.                     builder.append('|');
  515.                 }
  516.                 builder.append(fn.getArgumentName());
  517.             }
  518.             final String fundamentalName = "\\p{Space}*((?:" + builder.toString() + ")+)";
  519.             pattern = Pattern.compile("\\p{Space}*F\\p{Digit}+\\p{Space}*" + unicodeIdenticalTo +
  520.                                       fundamentalName + "\\p{Space}*=\\p{Space}*(.*)");

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

  522.         }

  523.         /** Parse a definition line.
  524.          * @param line line to parse
  525.          * @param lineNumber line number
  526.          * @param fileName name of the file
  527.          * @return true if a definition has been parsed
  528.          */
  529.         public boolean parseDefinition(final String line, final int lineNumber, final String fileName) {

  530.             parsedName       = null;
  531.             parsedPolynomial = null;

  532.             final Matcher matcher = pattern.matcher(line);
  533.             if (matcher.matches()) {
  534.                 for (FundamentalName fn : FundamentalName.values()) {
  535.                     if (fn.getArgumentName().equals(matcher.group(1))) {
  536.                         parsedName = fn;
  537.                     }
  538.                 }

  539.                 // parse the polynomial
  540.                 parsedPolynomial = polynomialParser.parse(matcher.group(2));

  541.                 return true;

  542.             } else {
  543.                 return false;
  544.             }

  545.         }

  546.         /** Get the last parsed fundamental name.
  547.          * @return last parsed fundamental name
  548.          */
  549.         public FundamentalName getParsedName() {
  550.             return parsedName;
  551.         }

  552.         /** Get the last parsed polynomial.
  553.          * @return last parsed polynomial
  554.          */
  555.         public double[] getParsedPolynomial() {
  556.             return parsedPolynomial.clone();
  557.         }

  558.     }

  559. }