SHAFormatReader.java

  1. /* Contributed in the public domain.
  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.forces.gravity.potential;

  18. import org.orekit.errors.OrekitException;
  19. import org.orekit.errors.OrekitMessages;

  20. import java.io.BufferedReader;
  21. import java.io.IOException;
  22. import java.io.InputStream;
  23. import java.io.InputStreamReader;
  24. import java.nio.charset.StandardCharsets;
  25. import java.text.ParseException;
  26. import java.util.regex.Pattern;

  27. /** Reader for the SHA gravity field format.
  28.  *
  29.  * <p> This format is used by some lunar gravity models distributed by
  30.  * NASA's Planetary Geology, Geophysics and Geochemistry Laboratory such as
  31.  * GRGM1200B and GRGM1200L. It is a simple ASCII format, described in
  32.  * <a href="https://pgda.gsfc.nasa.gov/products/75"> the GRGM1200B model product site</a>.
  33.  * The first line contains 4 constants: model GM, mean radius, maximum degree and maximum order.
  34.  * All other lines contain 6 entries: degree, order, Clm, Slm, sigma Clm and sigma Slm
  35.  * (formal errors of Clm and Slm).
  36.  *
  37.  * <p> The proper way to use this class is to call the {@link GravityFieldFactory}
  38.  *  which will determine which reader to use with the selected gravity field file.</p>
  39.  *
  40.  * @see GravityFields
  41.  * @author Rafael Ayala
  42.  */
  43. public class SHAFormatReader extends PotentialCoefficientsReader {

  44.     /** Default "0" text value. */
  45.     private static final String ZERO = "0.0";

  46.     /** Default "1" text value. */
  47.     private static final String ONE = "1.0";

  48.     /** Expression for multiple spaces. */
  49.     private static final String SPACES = "\\s+";

  50.     /** Pattern for delimiting regular expressions. */
  51.     private static final Pattern SEPARATOR = Pattern.compile(SPACES);

  52.     /** Pattern for real numbers. */
  53.     private static final Pattern REAL =  Pattern.compile("[-+]?\\d?\\.\\d+[eEdD][-+]\\d\\d");

  54.     /** Pattern for header line. */
  55.     private static final Pattern HEADER_LINE =  Pattern.compile("^\\s*" + REAL + SPACES + REAL + "\\s+\\d+\\s+\\d+\\s*$");

  56.     /** Pattern for data lines. */
  57.     private static final Pattern DATA_LINE = Pattern.compile("^\\s*\\d+\\s+\\d+\\s+" + REAL + SPACES + REAL + SPACES + REAL + SPACES + REAL + "\\s*$");

  58.     /** Start degree and order for coefficients container. */
  59.     private static final int START_DEGREE_ORDER = 120;

  60.     /** Simple constructor.
  61.      * @param supportedNames regular expression for supported files names
  62.      * @param missingCoefficientsAllowed if true, allows missing coefficients in the input data
  63.      * @since 12.2
  64.      */
  65.     public SHAFormatReader(final String supportedNames, final boolean missingCoefficientsAllowed) {
  66.         super(supportedNames, missingCoefficientsAllowed, null);
  67.     }

  68.     /** {@inheritDoc} */
  69.     public void loadData(final InputStream input, final String name) throws IOException, ParseException, OrekitException {

  70.         // reset the indicator before loading any data
  71.         setReadComplete(false);
  72.         setTideSystem(TideSystem.UNKNOWN);
  73.         int       lineNumber = 0;
  74.         int       maxDegree;
  75.         int       maxOrder;
  76.         String    line = null;
  77.         TemporaryCoefficientsContainer container = new TemporaryCoefficientsContainer(START_DEGREE_ORDER, START_DEGREE_ORDER,
  78.                                                                                       missingCoefficientsAllowed() ? 0.0 : Double.NaN);
  79.         try (BufferedReader r = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8))) {
  80.             for (line = r.readLine(); line != null; line = r.readLine()) {
  81.                 ++lineNumber;
  82.                 if (lineNumber == 1) {
  83.                     // match the pattern of the header line
  84.                     if (!HEADER_LINE.matcher(line).matches()) {
  85.                         throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
  86.                                                   lineNumber, name, line);
  87.                     }
  88.                     final String[] headerFields = SEPARATOR.split(line.trim());
  89.                     setMu(Double.parseDouble(headerFields[0]));
  90.                     setAe(Double.parseDouble(headerFields[1]));
  91.                     maxDegree = Integer.parseInt(headerFields[2]);
  92.                     maxOrder = Integer.parseInt(headerFields[3]);
  93.                     container = container.resize(maxDegree, maxOrder);
  94.                     parseCoefficient(ONE, container.getFlattener(), container.getC(), 0, 0, "C", name);
  95.                     parseCoefficient(ZERO, container.getFlattener(), container.getS(), 0, 0, "S", name);
  96.                     parseCoefficient(ZERO, container.getFlattener(), container.getS(), 1, 0, "C", name);
  97.                     parseCoefficient(ZERO, container.getFlattener(), container.getS(), 1, 0, "S", name);
  98.                     parseCoefficient(ZERO, container.getFlattener(), container.getS(), 1, 1, "C", name);
  99.                     parseCoefficient(ZERO, container.getFlattener(), container.getS(), 1, 1, "S", name);
  100.                 } else if (lineNumber > 1) {
  101.                     // match the pattern of the data lines
  102.                     if (!DATA_LINE.matcher(line).matches()) {
  103.                         throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
  104.                                                 lineNumber, name, line);
  105.                     }
  106.                     final String[] dataFields = SEPARATOR.split(line.trim());
  107.                     // we want to assign the values of the data fields to the corresponding variables
  108.                     final int n = Integer.parseInt(dataFields[0]);
  109.                     final int m = Integer.parseInt(dataFields[1]);
  110.                     parseCoefficient(dataFields[2], container.getFlattener(), container.getC(), n, m, "C", name);
  111.                     parseCoefficient(dataFields[3], container.getFlattener(), container.getS(), n, m, "S", name);
  112.                 }
  113.             }
  114.         } catch (NumberFormatException nfe) {
  115.             throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
  116.                                       lineNumber, name, line);
  117.         }
  118.         setRawCoefficients(true, container.getFlattener(), container.getC(), container.getS(), name);
  119.         setReadComplete(true);
  120.     }

  121.     /** Provider for read spherical harmonics coefficients.
  122.      * Like EGM fields, SHA fields don't include time-dependent parts,
  123.      * so this method returns directly a constant provider.
  124.      * @param wantNormalized if true, the provider will provide normalized coefficients,
  125.      * otherwise it will provide un-normalized coefficients
  126.      * @param degree maximal degree
  127.      * @param order maximal order
  128.      * @return a new provider
  129.      * @since 12.2
  130.      */
  131.     public RawSphericalHarmonicsProvider getProvider(final boolean wantNormalized,
  132.                                                      final int degree, final int order) {
  133.         return getBaseProvider(wantNormalized, degree, order);
  134.     }

  135. }