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