1   /* Copyright 2002-2023 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  
19  import java.io.BufferedReader;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.io.InputStreamReader;
23  import java.io.Serializable;
24  import java.nio.charset.StandardCharsets;
25  import java.util.ArrayList;
26  import java.util.Arrays;
27  import java.util.HashMap;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.regex.Matcher;
31  import java.util.regex.Pattern;
32  
33  import org.hipparchus.CalculusFieldElement;
34  import org.hipparchus.exception.DummyLocalizable;
35  import org.hipparchus.util.FastMath;
36  import org.orekit.annotation.DefaultDataContext;
37  import org.orekit.errors.OrekitException;
38  import org.orekit.errors.OrekitInternalError;
39  import org.orekit.errors.OrekitMessages;
40  import org.orekit.time.AbsoluteDate;
41  import org.orekit.time.FieldAbsoluteDate;
42  import org.orekit.time.TimeScalarFunction;
43  import org.orekit.time.TimeScale;
44  import org.orekit.time.TimeScales;
45  import org.orekit.utils.Constants;
46  import org.orekit.utils.IERSConventions;
47  
48  /**
49   * Class computing the fundamental arguments for nutation and tides.
50   * <p>
51   * The fundamental arguments are split in two sets:
52   * </p>
53   * <ul>
54   *   <li>the Delaunay arguments for Moon and Sun effects</li>
55   *   <li>the planetary arguments for other planets</li>
56   * </ul>
57   *
58   * @author Luc Maisonobe
59   * @see SeriesTerm
60   * @see PoissonSeries
61   * @see BodiesElements
62   */
63  public class FundamentalNutationArguments implements Serializable {
64  
65      /** Serializable UID. */
66      private static final long serialVersionUID = 20131209L;
67  
68      /** IERS conventions to use. */
69      private final IERSConventions conventions;
70  
71      /** Time scale for GMST computation. */
72      private final TimeScale timeScale;
73  
74      /** Function computing Greenwich Mean Sidereal Time. */
75      private final transient TimeScalarFunction gmstFunction;
76  
77      /** Function computing Greenwich Mean Sidereal Time rate. */
78      private final transient TimeScalarFunction gmstRateFunction;
79  
80      // luni-solar Delaunay arguments
81  
82      /** Coefficients for mean anomaly of the Moon. */
83      private final double[] lCoefficients;
84  
85      /** Coefficients for mean anomaly of the Sun. */
86      private final double[] lPrimeCoefficients;
87  
88      /** Coefficients for L - Ω where L is the mean longitude of the Moon. */
89      private final double[] fCoefficients;
90  
91      /** Coefficients for mean elongation of the Moon from the Sun. */
92      private final double[] dCoefficients;
93  
94      /** Coefficients for mean longitude of the ascending node of the Moon. */
95      private final double[] omegaCoefficients;
96  
97      // planetary nutation arguments
98  
99      /** Coefficients for mean Mercury longitude. */
100     private final double[] lMeCoefficients;
101 
102     /** Coefficients for mean Venus longitude. */
103     private final double[] lVeCoefficients;
104 
105     /** Coefficients for mean Earth longitude. */
106     private final double[] lECoefficients;
107 
108     /** Coefficients for mean Mars longitude. */
109     private final double[] lMaCoefficients;
110 
111     /** Coefficients for mean Jupiter longitude. */
112     private final double[] lJCoefficients;
113 
114     /** Coefficients for mean Saturn longitude. */
115     private final double[] lSaCoefficients;
116 
117     /** Coefficients for mean Uranus longitude. */
118     private final double[] lUCoefficients;
119 
120     /** Coefficients for mean Neptune longitude. */
121     private final double[] lNeCoefficients;
122 
123     /** Coefficients for general accumulated precession. */
124     private final double[] paCoefficients;
125 
126     /** Set of time scales to use in computations. */
127     private final transient TimeScales timeScales;
128 
129     /** Build a model of fundamental arguments from an IERS table file.
130      *
131      * <p>This method uses the {@link DataContext#getDefault() default data context}.
132      *
133      * @param conventions IERS conventions to use
134      * @param timeScale time scale for GMST computation
135      * (may be null if tide parameter γ = GMST + π is not needed)
136      * @param stream stream containing the IERS table
137      * @param name name of the resource file (for error messages only)
138      * @see #FundamentalNutationArguments(IERSConventions, TimeScale, List, TimeScales)
139      * @see #FundamentalNutationArguments(IERSConventions, TimeScale, InputStream, String, TimeScales)
140      */
141     @DefaultDataContext
142     public FundamentalNutationArguments(final IERSConventions conventions,
143                                         final TimeScale timeScale,
144                                         final InputStream stream, final String name) {
145         this(conventions, timeScale, stream, name,
146                 DataContext.getDefault().getTimeScales());
147     }
148 
149     /**
150      * Build a model of fundamental arguments from an IERS table file.
151      *
152      * @param conventions IERS conventions to use
153      * @param timeScale   time scale for GMST computation (may be null if tide parameter γ
154      *                    = GMST + π is not needed)
155      * @param stream      stream containing the IERS table
156      * @param name        name of the resource file (for error messages only)
157      * @param timeScales         TAI time scale
158      * @see #FundamentalNutationArguments(IERSConventions, TimeScale, List, TimeScales)
159      * @since 10.1
160      */
161     public FundamentalNutationArguments(final IERSConventions conventions,
162                                         final TimeScale timeScale,
163                                         final InputStream stream,
164                                         final String name,
165                                         final TimeScales timeScales) {
166         this(conventions, timeScale, parseCoefficients(stream, name), timeScales);
167     }
168 
169     /** Build a model of fundamental arguments from an IERS table file.
170      *
171      * <p>This method uses the {@link DataContext#getDefault() default data context}.
172      *
173      * @param conventions IERS conventions to use
174      * @param timeScale time scale for GMST computation
175      * (may be null if tide parameter γ = GMST + π is not needed)
176      * @param coefficients list of coefficients arrays (all 14 arrays must be provided,
177      * the 5 Delaunay first and the 9 planetary afterwards)
178      * @since 6.1
179      * @see #FundamentalNutationArguments(IERSConventions, TimeScale, List, TimeScales)
180      */
181     @DefaultDataContext
182     public FundamentalNutationArguments(final IERSConventions conventions, final TimeScale timeScale,
183                                         final List<double[]> coefficients) {
184         this(conventions, timeScale, coefficients,
185                 DataContext.getDefault().getTimeScales());
186     }
187 
188     /** Build a model of fundamental arguments from an IERS table file.
189      * @param conventions IERS conventions to use
190      * @param timeScale time scale for GMST computation
191      * (may be null if tide parameter γ = GMST + π is not needed)
192      * @param coefficients list of coefficients arrays (all 14 arrays must be provided,
193      * the 5 Delaunay first and the 9 planetary afterwards)
194      * @param timeScales used in the computation.
195      * @since 10.1
196      */
197     public FundamentalNutationArguments(final IERSConventions conventions,
198                                         final TimeScale timeScale,
199                                         final List<double[]> coefficients,
200                                         final TimeScales timeScales) {
201         this.conventions        = conventions;
202         this.timeScale          = timeScale;
203         this.timeScales         = timeScales;
204         this.gmstFunction       = (timeScale == null) ? null :
205                 conventions.getGMSTFunction(timeScale, timeScales);
206         this.gmstRateFunction   = (timeScale == null) ? null :
207                 conventions.getGMSTRateFunction(timeScale, timeScales);
208         this.lCoefficients      = coefficients.get( 0);
209         this.lPrimeCoefficients = coefficients.get( 1);
210         this.fCoefficients      = coefficients.get( 2);
211         this.dCoefficients      = coefficients.get( 3);
212         this.omegaCoefficients  = coefficients.get( 4);
213         this.lMeCoefficients    = coefficients.get( 5);
214         this.lVeCoefficients    = coefficients.get( 6);
215         this.lECoefficients     = coefficients.get( 7);
216         this.lMaCoefficients    = coefficients.get( 8);
217         this.lJCoefficients     = coefficients.get( 9);
218         this.lSaCoefficients    = coefficients.get(10);
219         this.lUCoefficients     = coefficients.get(11);
220         this.lNeCoefficients    = coefficients.get(12);
221         this.paCoefficients     = coefficients.get(13);
222     }
223 
224     /** Parse coefficients.
225      * @param stream stream containing the IERS table
226      * @param name name of the resource file (for error messages only)
227      * @return list of coefficients arrays
228      */
229     private static List<double[]> parseCoefficients(final InputStream stream, final String name) {
230 
231         if (stream == null) {
232             throw new OrekitException(OrekitMessages.UNABLE_TO_FIND_FILE, name);
233         }
234 
235         // setup the reader
236         try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) {
237 
238             final DefinitionParser definitionParser = new DefinitionParser();
239 
240             int lineNumber = 0;
241 
242             // look for the reference date and the 14 polynomials
243             final int n = FundamentalName.values().length;
244             final Map<FundamentalName, double[]> polynomials = new HashMap<FundamentalName, double[]>(n);
245             for (String line = reader.readLine(); line != null; line = reader.readLine()) {
246                 lineNumber++;
247                 if (definitionParser.parseDefinition(line, lineNumber, name)) {
248                     polynomials.put(definitionParser.getParsedName(),
249                                     definitionParser.getParsedPolynomial());
250                 }
251             }
252 
253             final List<double[]> coefficients = new ArrayList<double[]>(n);
254             coefficients.add(getCoefficients(FundamentalName.L,       polynomials, name));
255             coefficients.add(getCoefficients(FundamentalName.L_PRIME, polynomials, name));
256             coefficients.add(getCoefficients(FundamentalName.F,       polynomials, name));
257             coefficients.add(getCoefficients(FundamentalName.D,       polynomials, name));
258             coefficients.add(getCoefficients(FundamentalName.OMEGA,   polynomials, name));
259             if (polynomials.containsKey(FundamentalName.L_ME)) {
260                 // IERS conventions 2003 and later provide planetary nutation arguments
261                 coefficients.add(getCoefficients(FundamentalName.L_ME,    polynomials, name));
262                 coefficients.add(getCoefficients(FundamentalName.L_VE,    polynomials, name));
263                 coefficients.add(getCoefficients(FundamentalName.L_E,     polynomials, name));
264                 coefficients.add(getCoefficients(FundamentalName.L_MA,    polynomials, name));
265                 coefficients.add(getCoefficients(FundamentalName.L_J,     polynomials, name));
266                 coefficients.add(getCoefficients(FundamentalName.L_SA,    polynomials, name));
267                 coefficients.add(getCoefficients(FundamentalName.L_U,     polynomials, name));
268                 coefficients.add(getCoefficients(FundamentalName.L_NE,    polynomials, name));
269                 coefficients.add(getCoefficients(FundamentalName.PA,      polynomials, name));
270             } else {
271                 // IERS conventions 1996 and earlier don't provide planetary nutation arguments
272                 final double[] zero = new double[] {
273                     0.0
274                 };
275                 while (coefficients.size() < n) {
276                     coefficients.add(zero);
277                 }
278             }
279 
280             return coefficients;
281 
282         } catch (IOException ioe) {
283             throw new OrekitException(ioe, new DummyLocalizable(ioe.getMessage()));
284         }
285 
286     }
287 
288     /** Get the coefficients for a fundamental argument.
289      * @param argument fundamental argument
290      * @param polynomials map of the polynomials
291      * @param fileName name of the file from which the coefficients have been read
292      * @return polynomials coefficients (ordered from high degrees to low degrees)
293      */
294     private static double[] getCoefficients(final FundamentalName argument,
295                                             final Map<FundamentalName, double[]> polynomials,
296                                             final String fileName) {
297         if (!polynomials.containsKey(argument)) {
298             throw new OrekitException(OrekitMessages.NOT_A_SUPPORTED_IERS_DATA_FILE, fileName);
299         }
300         return polynomials.get(argument);
301     }
302 
303     /** Evaluate a polynomial.
304      * @param tc offset in Julian centuries
305      * @param coefficients polynomial coefficients (ordered from low degrees to high degrees)
306      * @return value of the polynomial
307      */
308     private double value(final double tc, final double[] coefficients) {
309         double value = 0;
310         for (int i = coefficients.length - 1; i >= 0; --i) {
311             value = coefficients[i] + tc * value;
312         }
313         return value;
314     }
315 
316     /** Evaluate a polynomial time derivative.
317      * @param tc offset in Julian centuries
318      * @param coefficients polynomial coefficients (ordered from low degrees to high degrees)
319      * @return time derivative of the polynomial
320      */
321     private double derivative(final double tc, final double[] coefficients) {
322         double derivative = 0;
323         for (int i = coefficients.length - 1; i > 0; --i) {
324             derivative = i * coefficients[i] + tc * derivative;
325         }
326         return derivative / Constants.JULIAN_CENTURY;
327     }
328 
329     /** Evaluate a polynomial.
330      * @param tc offset in Julian centuries
331      * @param <T> type of the field elements
332      * @param coefficients polynomial coefficients (ordered from low degrees to high degrees)
333      * @return value of the polynomial
334      */
335     private <T extends CalculusFieldElement<T>> T value(final T tc, final double[] coefficients) {
336         T value = tc.getField().getZero();
337         for (int i = coefficients.length - 1; i >= 0; --i) {
338             value = tc.multiply(value).add(coefficients[i]);
339         }
340         return value;
341     }
342 
343     /** Evaluate a polynomial time derivative.
344      * @param tc offset in Julian centuries
345      * @param <T> type of the field elements
346      * @param coefficients polynomial coefficients (ordered from low degrees to high degrees)
347      * @return time derivative of the polynomial
348      */
349     private <T extends CalculusFieldElement<T>> T derivative(final T tc, final double[] coefficients) {
350         T derivative = tc.getField().getZero();
351         for (int i = coefficients.length - 1; i > 0; --i) {
352             derivative = tc.multiply(derivative).add(i * coefficients[i]);
353         }
354         return derivative.divide(Constants.JULIAN_CENTURY);
355     }
356 
357     /** Evaluate all fundamental arguments for the current date (Delaunay plus planetary).
358      * @param date current date
359      * @return all fundamental arguments for the current date (Delaunay plus planetary)
360      */
361     public BodiesElements evaluateAll(final AbsoluteDate date) {
362 
363         final double tc       = conventions.evaluateTC(date, timeScales);
364         final double gamma    = gmstFunction == null ?
365                                 Double.NaN : gmstFunction.value(date) + FastMath.PI;
366         final double gammaDot = gmstRateFunction == null ?
367                                 Double.NaN : gmstRateFunction.value(date);
368 
369         return new BodiesElements(date, tc, gamma, gammaDot,
370                                   value(tc, lCoefficients),           // mean anomaly of the Moon
371                                   derivative(tc, lCoefficients),      // mean anomaly of the Moon time derivative
372                                   value(tc, lPrimeCoefficients),      // mean anomaly of the Sun
373                                   derivative(tc, lPrimeCoefficients), // mean anomaly of the Sun time derivative
374                                   value(tc, fCoefficients),           // L - Ω where L is the mean longitude of the Moon
375                                   derivative(tc, fCoefficients),      // L - Ω where L is the mean longitude of the Moon time derivative
376                                   value(tc, dCoefficients),           // mean elongation of the Moon from the Sun
377                                   derivative(tc, dCoefficients),      // mean elongation of the Moon from the Sun time derivative
378                                   value(tc, omegaCoefficients),       // mean longitude of the ascending node of the Moon
379                                   derivative(tc, omegaCoefficients),  // mean longitude of the ascending node of the Moon time derivative
380                                   value(tc, lMeCoefficients),         // mean Mercury longitude
381                                   derivative(tc, lMeCoefficients),    // mean Mercury longitude time derivative
382                                   value(tc, lVeCoefficients),         // mean Venus longitude
383                                   derivative(tc, lVeCoefficients),    // mean Venus longitude time derivative
384                                   value(tc, lECoefficients),          // mean Earth longitude
385                                   derivative(tc, lECoefficients),     // mean Earth longitude time derivative
386                                   value(tc, lMaCoefficients),         // mean Mars longitude
387                                   derivative(tc, lMaCoefficients),    // mean Mars longitude time derivative
388                                   value(tc, lJCoefficients),          // mean Jupiter longitude
389                                   derivative(tc, lJCoefficients),     // mean Jupiter longitude time derivative
390                                   value(tc, lSaCoefficients),         // mean Saturn longitude
391                                   derivative(tc, lSaCoefficients),    // mean Saturn longitude time derivative
392                                   value(tc, lUCoefficients),          // mean Uranus longitude
393                                   derivative(tc, lUCoefficients),     // mean Uranus longitude time derivative
394                                   value(tc, lNeCoefficients),         // mean Neptune longitude
395                                   derivative(tc, lNeCoefficients),    // mean Neptune longitude time derivative
396                                   value(tc, paCoefficients),          // general accumulated precession in longitude
397                                   derivative(tc, paCoefficients));    // general accumulated precession in longitude time derivative
398 
399     }
400 
401     /** Evaluate all fundamental arguments for the current date (Delaunay plus planetary).
402      * @param date current date
403      * @param <T> type of the field elements
404      * @return all fundamental arguments for the current date (Delaunay plus planetary)
405      */
406     public <T extends CalculusFieldElement<T>> FieldBodiesElements<T> evaluateAll(final FieldAbsoluteDate<T> date) {
407 
408         final T tc       = conventions.evaluateTC(date, timeScales);
409         final T gamma    = gmstFunction == null ?
410                            tc.getField().getZero().add(Double.NaN) : gmstFunction.value(date).add(tc.getPi());
411         final T gammaDot = gmstRateFunction == null ?
412                            tc.getField().getZero().add(Double.NaN) : gmstRateFunction.value(date);
413 
414         return new FieldBodiesElements<>(date, tc, gamma, gammaDot,
415                                          value(tc, lCoefficients),           // mean anomaly of the Moon
416                                          derivative(tc, lCoefficients),      // mean anomaly of the Moon time derivative
417                                          value(tc, lPrimeCoefficients),      // mean anomaly of the Sun
418                                          derivative(tc, lPrimeCoefficients), // mean anomaly of the Sun time derivative
419                                          value(tc, fCoefficients),           // L - Ω where L is the mean longitude of the Moon
420                                          derivative(tc, fCoefficients),      // L - Ω where L is the mean longitude of the Moon time derivative
421                                          value(tc, dCoefficients),           // mean elongation of the Moon from the Sun
422                                          derivative(tc, dCoefficients),      // mean elongation of the Moon from the Sun time derivative
423                                          value(tc, omegaCoefficients),       // mean longitude of the ascending node of the Moon
424                                          derivative(tc, omegaCoefficients),  // mean longitude of the ascending node of the Moon time derivative
425                                          value(tc, lMeCoefficients),         // mean Mercury longitude
426                                          derivative(tc, lMeCoefficients),    // mean Mercury longitude time derivative
427                                          value(tc, lVeCoefficients),         // mean Venus longitude
428                                          derivative(tc, lVeCoefficients),    // mean Venus longitude time derivative
429                                          value(tc, lECoefficients),          // mean Earth longitude
430                                          derivative(tc, lECoefficients),     // mean Earth longitude time derivative
431                                          value(tc, lMaCoefficients),         // mean Mars longitude
432                                          derivative(tc, lMaCoefficients),    // mean Mars longitude time derivative
433                                          value(tc, lJCoefficients),          // mean Jupiter longitude
434                                          derivative(tc, lJCoefficients),     // mean Jupiter longitude time derivative
435                                          value(tc, lSaCoefficients),         // mean Saturn longitude
436                                          derivative(tc, lSaCoefficients),    // mean Saturn longitude time derivative
437                                          value(tc, lUCoefficients),          // mean Uranus longitude
438                                          derivative(tc, lUCoefficients),     // mean Uranus longitude time derivative
439                                          value(tc, lNeCoefficients),         // mean Neptune longitude
440                                          derivative(tc, lNeCoefficients),    // mean Neptune longitude time derivative
441                                          value(tc, paCoefficients),          // general accumulated precession in longitude
442                                          derivative(tc, paCoefficients));    // general accumulated precession in longitude time derivative
443 
444     }
445 
446     /** Replace the instance with a data transfer object for serialization.
447      * <p>
448      * This intermediate class serializes only the frame key.
449      * </p>
450      * @return data transfer object that will be serialized
451      */
452     @DefaultDataContext
453     private Object writeReplace() {
454         return new DataTransferObject(conventions, timeScale,
455                                       Arrays.asList(lCoefficients, lPrimeCoefficients, fCoefficients,
456                                                     dCoefficients, omegaCoefficients,
457                                                     lMeCoefficients, lVeCoefficients, lECoefficients,
458                                                     lMaCoefficients, lJCoefficients, lSaCoefficients,
459                                                     lUCoefficients, lNeCoefficients, paCoefficients));
460     }
461 
462     /** Internal class used only for serialization. */
463     @DefaultDataContext
464     private static class DataTransferObject implements Serializable {
465 
466         /** Serializable UID. */
467         private static final long serialVersionUID = 20131209L;
468 
469         /** IERS conventions to use. */
470         private final IERSConventions conventions;
471 
472         /** Time scale for GMST computation. */
473         private final TimeScale timeScale;
474 
475         /** All coefficients. */
476         private final List<double[]> coefficients;
477 
478         /** Simple constructor.
479          * @param conventions IERS conventions to use
480          * @param timeScale time scale for GMST computation
481          * @param coefficients all coefficients
482          */
483         DataTransferObject(final IERSConventions conventions, final TimeScale timeScale,
484                                   final List<double[]> coefficients) {
485             this.conventions  = conventions;
486             this.timeScale    = timeScale;
487             this.coefficients = coefficients;
488         }
489 
490         /** Replace the deserialized data transfer object with a {@link TIRFProvider}.
491          * @return replacement {@link TIRFProvider}
492          */
493         private Object readResolve() {
494             try {
495                 // retrieve a managed frame
496                 return new FundamentalNutationArguments(conventions, timeScale, coefficients);
497             } catch (OrekitException oe) {
498                 throw new OrekitInternalError(oe);
499             }
500         }
501 
502     }
503 
504     /** Enumerate for the fundamental names. */
505     private enum FundamentalName {
506 
507         /** Constant for Mean anomaly of the Moon. */
508         L() {
509             /** {@inheritDoc} */
510             public String getArgumentName() {
511                 return "l";
512             }
513         },
514 
515         /** Constant for Mean anomaly of the Sun. */
516         L_PRIME() {
517             /** {@inheritDoc} */
518             public String getArgumentName() {
519                 return "l'";
520             }
521         },
522 
523         /** Constant for L - Ω where L is the mean longitude of the Moon. */
524         F() {
525             /** {@inheritDoc} */
526             public String getArgumentName() {
527                 return "F";
528             }
529         },
530 
531         /** Constant for mean elongation of the Moon from the Sun. */
532         D() {
533             /** {@inheritDoc} */
534             public String getArgumentName() {
535                 return "D";
536             }
537         },
538 
539         /** Constant for longitude of the ascending node of the Moon. */
540         OMEGA() {
541             /** {@inheritDoc} */
542             public String getArgumentName() {
543                 return "\u03a9";
544             }
545         },
546 
547         /** Constant for mean Mercury longitude. */
548         L_ME() {
549             /** {@inheritDoc} */
550             public String getArgumentName() {
551                 return "LMe";
552             }
553         },
554 
555         /** Constant for mean Venus longitude. */
556         L_VE() {
557             /** {@inheritDoc} */
558             public String getArgumentName() {
559                 return "LVe";
560             }
561         },
562 
563         /** Constant for mean Earth longitude. */
564         L_E() {
565             /** {@inheritDoc} */
566             public String getArgumentName() {
567                 return "LE";
568             }
569         },
570 
571         /** Constant for mean Mars longitude. */
572         L_MA() {
573             /** {@inheritDoc} */
574             public String getArgumentName() {
575                 return "LMa";
576             }
577         },
578 
579         /** Constant for mean Jupiter longitude. */
580         L_J() {
581             /** {@inheritDoc} */
582             public String getArgumentName() {
583                 return "LJ";
584             }
585         },
586 
587         /** Constant for mean Saturn longitude. */
588         L_SA() {
589             /** {@inheritDoc} */
590             public String getArgumentName() {
591                 return "LSa";
592             }
593         },
594 
595         /** Constant for mean Uranus longitude. */
596         L_U() {
597             /** {@inheritDoc} */
598             public String getArgumentName() {
599                 return "LU";
600             }
601         },
602 
603         /** Constant for mean Neptune longitude. */
604         L_NE() {
605             /** {@inheritDoc} */
606             public String getArgumentName() {
607                 return "LNe";
608             }
609         },
610 
611         /** Constant for general accumulated precession in longitude. */
612         PA() {
613             /** {@inheritDoc} */
614             public String getArgumentName() {
615                 return "pA";
616             }
617         };
618 
619         /** Get the fundamental name.
620          * @return fundamental name
621          */
622         public abstract String getArgumentName();
623 
624     }
625 
626     /** Local parser for argument definition lines. */
627     private static class DefinitionParser {
628 
629         /** Regular expression pattern for definitions. */
630         private final Pattern pattern;
631 
632         /** Parser for polynomials. */
633         private PolynomialParser polynomialParser;
634 
635         /** Last parsed fundamental name. */
636         private FundamentalName parsedName;
637 
638         /** Last parsed polynomial. */
639         private double[] parsedPolynomial;
640 
641         /** Simple constructor. */
642         DefinitionParser() {
643 
644             // the luni-solar Delaunay arguments polynomial parts should read something like:
645             // F5 ≡ Ω = 125.04455501° − 6962890.5431″t + 7.4722″t² + 0.007702″t³ − 0.00005939″t⁴
646             // whereas the planetary arguments polynomial parts should read something like:
647             // F14 ≡ pA  = 0.02438175 × t + 0.00000538691 × t²
648             final String unicodeIdenticalTo = "\u2261";
649 
650             // pattern for the global line
651             final StringBuilder builder = new StringBuilder();
652             for (final FundamentalName fn : FundamentalName.values()) {
653                 if (builder.length() > 0) {
654                     builder.append('|');
655                 }
656                 builder.append(fn.getArgumentName());
657             }
658             final String fundamentalName = "\\p{Space}*((?:" + builder.toString() + ")+)";
659             pattern = Pattern.compile("\\p{Space}*F\\p{Digit}+\\p{Space}*" + unicodeIdenticalTo +
660                                       fundamentalName + "\\p{Space}*=\\p{Space}*(.*)");
661 
662             polynomialParser = new PolynomialParser('t', PolynomialParser.Unit.NO_UNITS);
663 
664         }
665 
666         /** Parse a definition line.
667          * @param line line to parse
668          * @param lineNumber line number
669          * @param fileName name of the file
670          * @return true if a definition has been parsed
671          */
672         public boolean parseDefinition(final String line, final int lineNumber, final String fileName) {
673 
674             parsedName       = null;
675             parsedPolynomial = null;
676 
677             final Matcher matcher = pattern.matcher(line);
678             if (matcher.matches()) {
679                 for (FundamentalName fn : FundamentalName.values()) {
680                     if (fn.getArgumentName().equals(matcher.group(1))) {
681                         parsedName = fn;
682                     }
683                 }
684 
685                 // parse the polynomial
686                 parsedPolynomial = polynomialParser.parse(matcher.group(2));
687 
688                 return true;
689 
690             } else {
691                 return false;
692             }
693 
694         }
695 
696         /** Get the last parsed fundamental name.
697          * @return last parsed fundamental name
698          */
699         public FundamentalName getParsedName() {
700             return parsedName;
701         }
702 
703         /** Get the last parsed polynomial.
704          * @return last parsed polynomial
705          */
706         public double[] getParsedPolynomial() {
707             return parsedPolynomial.clone();
708         }
709 
710     }
711 
712 }