AstronomicalAmplitudeReader.java

  1. /* Copyright 2002-2018 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.forces.gravity.potential;

  18. import java.io.BufferedReader;
  19. import java.io.IOException;
  20. import java.io.InputStream;
  21. import java.io.InputStreamReader;
  22. import java.util.Collections;
  23. import java.util.HashMap;
  24. import java.util.Map;
  25. import java.util.regex.Matcher;
  26. import java.util.regex.Pattern;

  27. import org.hipparchus.util.FastMath;
  28. import org.orekit.data.DataLoader;
  29. import org.orekit.errors.OrekitException;
  30. import org.orekit.errors.OrekitMessages;

  31. /**
  32.  * Parser for tides astronomical amplitude H<sub>f</sub>.
  33.  * @author Luc Maisonobe
  34.  * @since 6.1
  35.  */
  36. public class AstronomicalAmplitudeReader implements DataLoader {

  37.     /** Pattern for optional fields (either nothing or non-space characters). */
  38.     private static final String  OPTIONAL_FIELD_PATTERN = "\\S*";

  39.     /** Pattern for fields with Doodson number. */
  40.     private static final String  DOODSON_TYPE_PATTERN = "\\p{Digit}{2,3}[.,]\\p{Digit}{3}";

  41.     /** Pattern for fields with real type. */
  42.     private static final String  REAL_TYPE_PATTERN =
  43.             "[-+]?(?:(?:\\p{Digit}+(?:\\.\\p{Digit}*)?)|(?:\\.\\p{Digit}+))(?:[eE][-+]?\\p{Digit}+)?";

  44.     /** Regular expression for supported files names. */
  45.     private final String supportedNames;

  46.     /** Pattern for regular data lines. */
  47.     private final Pattern regularLinePattern;

  48.     /** Doodson number column. */
  49.     private final int columnDoodson;

  50.     /** H<sub>f</sub> column. */
  51.     private final int columnHf;

  52.     /** Scaling factor for astronomical amplitude. */
  53.     private final double scale;

  54.     /** Amplitudes map. */
  55.     private final Map<Integer, Double> amplitudesMap;

  56.     /** Simple constructor.
  57.      * @param supportedNames regular expression for supported files names
  58.      * @param columns number of columns
  59.      * @param columnDoodson Doodson number column (counting from 1)
  60.      * @param columnHf H<sub>f</sub> column (counting from 1)
  61.      * @param scale scaling factor for astronomical amplitude
  62.      */
  63.     public AstronomicalAmplitudeReader(final String supportedNames, final int columns,
  64.                                        final int columnDoodson, final int columnHf,
  65.                                        final double scale) {

  66.         // build the pattern for the regular data lines
  67.         final StringBuilder builder = new StringBuilder("^\\p{Space}*");
  68.         for (int i = 1; i <= columns; ++i) {
  69.             builder.append("(");
  70.             if (i == columnDoodson) {
  71.                 builder.append(DOODSON_TYPE_PATTERN);
  72.             } else if (i == columnHf) {
  73.                 builder.append(REAL_TYPE_PATTERN);
  74.             } else {
  75.                 builder.append(OPTIONAL_FIELD_PATTERN);
  76.             }
  77.             builder.append(")");
  78.             builder.append(i < FastMath.max(columnDoodson, columnHf) ? "\\p{Space}+" : "\\p{Space}*");
  79.         }
  80.         builder.append('$');
  81.         this.regularLinePattern = Pattern.compile(builder.toString());

  82.         this.supportedNames = supportedNames;
  83.         this.columnDoodson  = columnDoodson;
  84.         this.columnHf       = columnHf;
  85.         this.scale          = scale;

  86.         this.amplitudesMap  = new HashMap<Integer, Double>();

  87.     }

  88.     /** Get the regular expression for supported files names.
  89.      * @return regular expression for supported files names
  90.      */
  91.     public String getSupportedNames() {
  92.         return supportedNames;
  93.     }

  94.     /** {@inheritDoc} */
  95.     @Override
  96.     public boolean stillAcceptsData() {
  97.         return amplitudesMap.isEmpty();
  98.     }

  99.     /** {@inheritDoc} */
  100.     @Override
  101.     public void loadData(final InputStream input, final String name)
  102.         throws OrekitException, IOException {

  103.         // parse the file
  104.         final BufferedReader r = new BufferedReader(new InputStreamReader(input, "UTF-8"));
  105.         int lineNumber      = 0;
  106.         for (String line = r.readLine(); line != null; line = r.readLine()) {
  107.             ++lineNumber;

  108.             try {

  109.                 // replace unicode minus sign ('−') by regular hyphen ('-') for parsing
  110.                 // such unicode characters occur in tables that are copy-pasted from PDF files
  111.                 line = line.replace('\u2212', '-');

  112.                 final Matcher regularMatcher = regularLinePattern.matcher(line);
  113.                 if (regularMatcher.matches()) {
  114.                     // we have found a regular data line
  115.                     final int    doodson = Integer.parseInt(regularMatcher.group(columnDoodson).replaceAll("[.,]", ""));
  116.                     final double hf      = scale * Double.parseDouble(regularMatcher.group(columnHf));
  117.                     amplitudesMap.put(doodson, hf);
  118.                 }

  119.             } catch (NumberFormatException nfe) {
  120.                 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
  121.                                           lineNumber, name, line);
  122.             }

  123.         }

  124.         if (amplitudesMap.isEmpty()) {
  125.             throw new OrekitException(OrekitMessages.NOT_A_SUPPORTED_IERS_DATA_FILE, name);
  126.         }

  127.     }

  128.     /** Get astronomical amplitudes map.
  129.      * @return an unmodifiable map containing astronomical amplitudes H<sub>f</sub>
  130.      * from a Doodson number key
  131.      */
  132.     public Map<Integer, Double> getAstronomicalAmplitudesMap() {
  133.         return Collections.unmodifiableMap(amplitudesMap);
  134.     }

  135. }