FundamentalNutationArguments.java

  1. /* Copyright 2002-2019 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.hipparchus.RealFieldElement;
  31. import org.hipparchus.exception.DummyLocalizable;
  32. import org.hipparchus.util.FastMath;
  33. import org.orekit.errors.OrekitException;
  34. import org.orekit.errors.OrekitInternalError;
  35. import org.orekit.errors.OrekitMessages;
  36. import org.orekit.time.AbsoluteDate;
  37. import org.orekit.time.FieldAbsoluteDate;
  38. import org.orekit.time.TimeScalarFunction;
  39. import org.orekit.time.TimeScale;
  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 implements Serializable {

  58.     /** Serializable UID. */
  59.     private static final long serialVersionUID = 20131209L;

  60.     /** IERS conventions to use. */
  61.     private final IERSConventions conventions;

  62.     /** Time scale for GMST computation. */
  63.     private final TimeScale timeScale;

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

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

  68.     // luni-solar Delaunay arguments

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

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

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

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

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

  79.     // planetary nutation arguments

  80.     /** Coefficients for mean Mercury longitude. */
  81.     private final double[] lMeCoefficients;

  82.     /** Coefficients for mean Venus longitude. */
  83.     private final double[] lVeCoefficients;

  84.     /** Coefficients for mean Earth longitude. */
  85.     private final double[] lECoefficients;

  86.     /** Coefficients for mean Mars longitude. */
  87.     private final double[] lMaCoefficients;

  88.     /** Coefficients for mean Jupiter longitude. */
  89.     private final double[] lJCoefficients;

  90.     /** Coefficients for mean Saturn longitude. */
  91.     private final double[] lSaCoefficients;

  92.     /** Coefficients for mean Uranus longitude. */
  93.     private final double[] lUCoefficients;

  94.     /** Coefficients for mean Neptune longitude. */
  95.     private final double[] lNeCoefficients;

  96.     /** Coefficients for general accumulated precession. */
  97.     private final double[] paCoefficients;

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

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

  139.     /** Parse coefficients.
  140.      * @param stream stream containing the IERS table
  141.      * @param name name of the resource file (for error messages only)
  142.      * @return list of coefficients arrays
  143.      */
  144.     private static List<double[]> parseCoefficients(final InputStream stream, final String name) {

  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.      */
  200.     private static double[] getCoefficients(final FundamentalName argument,
  201.                                             final Map<FundamentalName, double[]> polynomials,
  202.                                             final String fileName) {
  203.         if (!polynomials.containsKey(argument)) {
  204.             throw new OrekitException(OrekitMessages.NOT_A_SUPPORTED_IERS_DATA_FILE, fileName);
  205.         }
  206.         return polynomials.get(argument);
  207.     }

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

  220.     /** Evaluate a polynomial time derivative.
  221.      * @param tc offset in Julian centuries
  222.      * @param coefficients polynomial coefficients (ordered from low degrees to high degrees)
  223.      * @return time derivative of the polynomial
  224.      */
  225.     private double derivative(final double tc, final double[] coefficients) {
  226.         double derivative = 0;
  227.         for (int i = coefficients.length - 1; i > 0; --i) {
  228.             derivative = i * coefficients[i] + tc * derivative;
  229.         }
  230.         return derivative / Constants.JULIAN_CENTURY;
  231.     }

  232.     /** Evaluate a polynomial.
  233.      * @param tc offset in Julian centuries
  234.      * @param <T> type of the field elements
  235.      * @param coefficients polynomial coefficients (ordered from low degrees to high degrees)
  236.      * @return value of the polynomial
  237.      */
  238.     private <T extends RealFieldElement<T>> T value(final T tc, final double[] coefficients) {
  239.         T value = tc.getField().getZero();
  240.         for (int i = coefficients.length - 1; i >= 0; --i) {
  241.             value = tc.multiply(value).add(coefficients[i]);
  242.         }
  243.         return value;
  244.     }

  245.     /** Evaluate a polynomial time derivative.
  246.      * @param tc offset in Julian centuries
  247.      * @param <T> type of the field elements
  248.      * @param coefficients polynomial coefficients (ordered from low degrees to high degrees)
  249.      * @return time derivative of the polynomial
  250.      */
  251.     private <T extends RealFieldElement<T>> T derivative(final T tc, final double[] coefficients) {
  252.         T derivative = tc.getField().getZero();
  253.         for (int i = coefficients.length - 1; i > 0; --i) {
  254.             derivative = tc.multiply(derivative).add(i * coefficients[i]);
  255.         }
  256.         return derivative.divide(Constants.JULIAN_CENTURY);
  257.     }

  258.     /** Evaluate all fundamental arguments for the current date (Delaunay plus planetary).
  259.      * @param date current date
  260.      * @return all fundamental arguments for the current date (Delaunay plus planetary)
  261.      */
  262.     public BodiesElements evaluateAll(final AbsoluteDate date) {

  263.         final double tc       = conventions.evaluateTC(date);
  264.         final double gamma    = gmstFunction == null ?
  265.                                 Double.NaN : gmstFunction.value(date) + FastMath.PI;
  266.         final double gammaDot = gmstRateFunction == null ?
  267.                                 Double.NaN : gmstRateFunction.value(date);

  268.         return new BodiesElements(date, tc, gamma, gammaDot,
  269.                                   value(tc, lCoefficients),           // mean anomaly of the Moon
  270.                                   derivative(tc, lCoefficients),      // mean anomaly of the Moon time derivative
  271.                                   value(tc, lPrimeCoefficients),      // mean anomaly of the Sun
  272.                                   derivative(tc, lPrimeCoefficients), // mean anomaly of the Sun time derivative
  273.                                   value(tc, fCoefficients),           // L - Ω where L is the mean longitude of the Moon
  274.                                   derivative(tc, fCoefficients),      // L - Ω where L is the mean longitude of the Moon time derivative
  275.                                   value(tc, dCoefficients),           // mean elongation of the Moon from the Sun
  276.                                   derivative(tc, dCoefficients),      // mean elongation of the Moon from the Sun time derivative
  277.                                   value(tc, omegaCoefficients),       // mean longitude of the ascending node of the Moon
  278.                                   derivative(tc, omegaCoefficients),  // mean longitude of the ascending node of the Moon time derivative
  279.                                   value(tc, lMeCoefficients),         // mean Mercury longitude
  280.                                   derivative(tc, lMeCoefficients),    // mean Mercury longitude time derivative
  281.                                   value(tc, lVeCoefficients),         // mean Venus longitude
  282.                                   derivative(tc, lVeCoefficients),    // mean Venus longitude time derivative
  283.                                   value(tc, lECoefficients),          // mean Earth longitude
  284.                                   derivative(tc, lECoefficients),     // mean Earth longitude time derivative
  285.                                   value(tc, lMaCoefficients),         // mean Mars longitude
  286.                                   derivative(tc, lMaCoefficients),    // mean Mars longitude time derivative
  287.                                   value(tc, lJCoefficients),          // mean Jupiter longitude
  288.                                   derivative(tc, lJCoefficients),     // mean Jupiter longitude time derivative
  289.                                   value(tc, lSaCoefficients),         // mean Saturn longitude
  290.                                   derivative(tc, lSaCoefficients),    // mean Saturn longitude time derivative
  291.                                   value(tc, lUCoefficients),          // mean Uranus longitude
  292.                                   derivative(tc, lUCoefficients),     // mean Uranus longitude time derivative
  293.                                   value(tc, lNeCoefficients),         // mean Neptune longitude
  294.                                   derivative(tc, lNeCoefficients),    // mean Neptune longitude time derivative
  295.                                   value(tc, paCoefficients),          // general accumulated precession in longitude
  296.                                   derivative(tc, paCoefficients));    // general accumulated precession in longitude time derivative

  297.     }

  298.     /** Evaluate all fundamental arguments for the current date (Delaunay plus planetary).
  299.      * @param date current date
  300.      * @param <T> type of the field elements
  301.      * @return all fundamental arguments for the current date (Delaunay plus planetary)
  302.      */
  303.     public <T extends RealFieldElement<T>> FieldBodiesElements<T> evaluateAll(final FieldAbsoluteDate<T> date) {

  304.         final T tc       = conventions.evaluateTC(date);
  305.         final T gamma    = gmstFunction == null ?
  306.                            tc.getField().getZero().add(Double.NaN) : gmstFunction.value(date).add(FastMath.PI);
  307.         final T gammaDot = gmstRateFunction == null ?
  308.                            tc.getField().getZero().add(Double.NaN) : gmstRateFunction.value(date);

  309.         return new FieldBodiesElements<>(date, tc, gamma, gammaDot,
  310.                                          value(tc, lCoefficients),           // mean anomaly of the Moon
  311.                                          derivative(tc, lCoefficients),      // mean anomaly of the Moon time derivative
  312.                                          value(tc, lPrimeCoefficients),      // mean anomaly of the Sun
  313.                                          derivative(tc, lPrimeCoefficients), // mean anomaly of the Sun time derivative
  314.                                          value(tc, fCoefficients),           // L - Ω where L is the mean longitude of the Moon
  315.                                          derivative(tc, fCoefficients),      // L - Ω where L is the mean longitude of the Moon time derivative
  316.                                          value(tc, dCoefficients),           // mean elongation of the Moon from the Sun
  317.                                          derivative(tc, dCoefficients),      // mean elongation of the Moon from the Sun time derivative
  318.                                          value(tc, omegaCoefficients),       // mean longitude of the ascending node of the Moon
  319.                                          derivative(tc, omegaCoefficients),  // mean longitude of the ascending node of the Moon time derivative
  320.                                          value(tc, lMeCoefficients),         // mean Mercury longitude
  321.                                          derivative(tc, lMeCoefficients),    // mean Mercury longitude time derivative
  322.                                          value(tc, lVeCoefficients),         // mean Venus longitude
  323.                                          derivative(tc, lVeCoefficients),    // mean Venus longitude time derivative
  324.                                          value(tc, lECoefficients),          // mean Earth longitude
  325.                                          derivative(tc, lECoefficients),     // mean Earth longitude time derivative
  326.                                          value(tc, lMaCoefficients),         // mean Mars longitude
  327.                                          derivative(tc, lMaCoefficients),    // mean Mars longitude time derivative
  328.                                          value(tc, lJCoefficients),          // mean Jupiter longitude
  329.                                          derivative(tc, lJCoefficients),     // mean Jupiter longitude time derivative
  330.                                          value(tc, lSaCoefficients),         // mean Saturn longitude
  331.                                          derivative(tc, lSaCoefficients),    // mean Saturn longitude time derivative
  332.                                          value(tc, lUCoefficients),          // mean Uranus longitude
  333.                                          derivative(tc, lUCoefficients),     // mean Uranus longitude time derivative
  334.                                          value(tc, lNeCoefficients),         // mean Neptune longitude
  335.                                          derivative(tc, lNeCoefficients),    // mean Neptune longitude time derivative
  336.                                          value(tc, paCoefficients),          // general accumulated precession in longitude
  337.                                          derivative(tc, paCoefficients));    // general accumulated precession in longitude time derivative

  338.     }

  339.     /** Replace the instance with a data transfer object for serialization.
  340.      * <p>
  341.      * This intermediate class serializes only the frame key.
  342.      * </p>
  343.      * @return data transfer object that will be serialized
  344.      */
  345.     private Object writeReplace() {
  346.         return new DataTransferObject(conventions, timeScale,
  347.                                       Arrays.asList(lCoefficients, lPrimeCoefficients, fCoefficients,
  348.                                                     dCoefficients, omegaCoefficients,
  349.                                                     lMeCoefficients, lVeCoefficients, lECoefficients,
  350.                                                     lMaCoefficients, lJCoefficients, lSaCoefficients,
  351.                                                     lUCoefficients, lNeCoefficients, paCoefficients));
  352.     }

  353.     /** Internal class used only for serialization. */
  354.     private static class DataTransferObject implements Serializable {

  355.         /** Serializable UID. */
  356.         private static final long serialVersionUID = 20131209L;

  357.         /** IERS conventions to use. */
  358.         private final IERSConventions conventions;

  359.         /** Time scale for GMST computation. */
  360.         private final TimeScale timeScale;

  361.         /** All coefficients. */
  362.         private final List<double[]> coefficients;

  363.         /** Simple constructor.
  364.          * @param conventions IERS conventions to use
  365.          * @param timeScale time scale for GMST computation
  366.          * @param coefficients all coefficients
  367.          */
  368.         DataTransferObject(final IERSConventions conventions, final TimeScale timeScale,
  369.                                   final List<double[]> coefficients) {
  370.             this.conventions  = conventions;
  371.             this.timeScale    = timeScale;
  372.             this.coefficients = coefficients;
  373.         }

  374.         /** Replace the deserialized data transfer object with a {@link TIRFProvider}.
  375.          * @return replacement {@link TIRFProvider}
  376.          */
  377.         private Object readResolve() {
  378.             try {
  379.                 // retrieve a managed frame
  380.                 return new FundamentalNutationArguments(conventions, timeScale, coefficients);
  381.             } catch (OrekitException oe) {
  382.                 throw new OrekitInternalError(oe);
  383.             }
  384.         }

  385.     }

  386.     /** Enumerate for the fundamental names. */
  387.     private enum FundamentalName {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  490.     }

  491.     /** Local parser for argument definition lines. */
  492.     private static class DefinitionParser {

  493.         /** Regular expression pattern for definitions. */
  494.         private final Pattern pattern;

  495.         /** Parser for polynomials. */
  496.         private PolynomialParser polynomialParser;

  497.         /** Last parsed fundamental name. */
  498.         private FundamentalName parsedName;

  499.         /** Last parsed polynomial. */
  500.         private double[] parsedPolynomial;

  501.         /** Simple constructor. */
  502.         DefinitionParser() {

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

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

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

  520.         }

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

  528.             parsedName       = null;
  529.             parsedPolynomial = null;

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

  537.                 // parse the polynomial
  538.                 parsedPolynomial = polynomialParser.parse(matcher.group(2));

  539.                 return true;

  540.             } else {
  541.                 return false;
  542.             }

  543.         }

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

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

  556.     }

  557. }