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