EGMFormatReader.java

  1. /* Copyright 2002-2020 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.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.nio.charset.StandardCharsets;
  23. import java.text.ParseException;
  24. import java.util.ArrayList;
  25. import java.util.List;
  26. import java.util.Locale;
  27. import java.util.regex.Pattern;

  28. import org.hipparchus.util.FastMath;
  29. import org.hipparchus.util.Precision;
  30. import org.orekit.errors.OrekitException;
  31. import org.orekit.errors.OrekitMessages;
  32. import org.orekit.utils.Constants;

  33. /**This reader is adapted to the EGM Format.
  34.  *
  35.  * <p> The proper way to use this class is to call the {@link GravityFieldFactory}
  36.  *  which will determine which reader to use with the selected gravity field file.</p>
  37.  *
  38.  * @see GravityFields
  39.  * @author Fabien Maussion
  40.  */
  41. public class EGMFormatReader extends PotentialCoefficientsReader {

  42.     /** Pattern for delimiting regular expressions. */
  43.     private static final Pattern SEPARATOR = Pattern.compile("\\s+");

  44.     /** Flag for using WGS84 values for equatorial radius and central attraction coefficient. */
  45.     private final boolean useWgs84Coefficients;

  46.     /** Simple constructor.
  47.      * @param supportedNames regular expression for supported files names
  48.      * @param missingCoefficientsAllowed if true, allows missing coefficients in the input data
  49.      */
  50.     public EGMFormatReader(final String supportedNames, final boolean missingCoefficientsAllowed) {
  51.         this(supportedNames, missingCoefficientsAllowed, false);
  52.     }

  53.     /**
  54.      * Simple constructor that allows overriding 'standard' EGM96 ae and mu with
  55.      * WGS84 variants.
  56.      *
  57.      * @param supportedNames regular expression for supported files names
  58.      * @param missingCoefficientsAllowed if true, allows missing coefficients in the input data
  59.      * @param useWgs84Coefficients if true, the WGS84 values will be used for equatorial radius
  60.      * and central attraction coefficient
  61.      */
  62.     public EGMFormatReader(final String supportedNames, final boolean missingCoefficientsAllowed,
  63.                            final boolean useWgs84Coefficients) {
  64.         super(supportedNames, missingCoefficientsAllowed, null);
  65.         this.useWgs84Coefficients = useWgs84Coefficients;
  66.     }


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

  70.         // reset the indicator before loading any data
  71.         setReadComplete(false);

  72.         // both EGM96 and EGM2008 use the same values for ae and mu
  73.         // if a new EGM model changes them, we should have some selection logic
  74.         // based on file name (a better way would be to have the data in the
  75.         // file...)
  76.         if (this.useWgs84Coefficients) {
  77.             setAe(Constants.WGS84_EARTH_EQUATORIAL_RADIUS);
  78.             setMu(Constants.WGS84_EARTH_MU);
  79.         } else {
  80.             setAe(Constants.EGM96_EARTH_EQUATORIAL_RADIUS);
  81.             setMu(Constants.EGM96_EARTH_MU);
  82.         }

  83.         final String lowerCaseName = name.toLowerCase(Locale.US);
  84.         if (lowerCaseName.contains("2008") || lowerCaseName.contains("zerotide")) {
  85.             setTideSystem(TideSystem.ZERO_TIDE);
  86.         } else {
  87.             setTideSystem(TideSystem.TIDE_FREE);
  88.         }

  89.         final List<List<Double>> c = new ArrayList<>();
  90.         final List<List<Double>> s = new ArrayList<>();
  91.         boolean okFields = true;
  92.         int lineNumber = 0;
  93.         String line = null;
  94.         try (BufferedReader r = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8))) {
  95.             for (line = r.readLine(); okFields && line != null; line = r.readLine()) {
  96.                 lineNumber++;
  97.                 if (line.length() >= 15) {

  98.                     // get the fields defining the current the potential terms
  99.                     final String[] tab = SEPARATOR.split(line.trim());
  100.                     if (tab.length != 6) {
  101.                         okFields = false;
  102.                     }

  103.                     final int i = Integer.parseInt(tab[0]);
  104.                     final int j = Integer.parseInt(tab[1]);
  105.                     if (i <= getMaxParseDegree() && j <= getMaxParseOrder()) {
  106.                         for (int k = 0; k <= i; ++k) {
  107.                             extendListOfLists(c, k, FastMath.min(k, getMaxParseOrder()),
  108.                                               missingCoefficientsAllowed() ? 0.0 : Double.NaN);
  109.                             extendListOfLists(s, k, FastMath.min(k, getMaxParseOrder()),
  110.                                               missingCoefficientsAllowed() ? 0.0 : Double.NaN);
  111.                         }
  112.                         parseCoefficient(tab[2], c, i, j, "C", name);
  113.                         parseCoefficient(tab[3], s, i, j, "S", name);
  114.                     }

  115.                 }
  116.             }
  117.         } catch (NumberFormatException nfe) {
  118.             throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
  119.                                       lineNumber, name, line);
  120.         }

  121.         if (missingCoefficientsAllowed() && getMaxParseDegree() > 0 && getMaxParseOrder() > 0) {
  122.             // ensure at least the (0, 0) element is properly set
  123.             extendListOfLists(c, 0, 0, 0.0);
  124.             extendListOfLists(s, 0, 0, 0.0);
  125.             if (Precision.equals(c.get(0).get(0), 0.0, 0)) {
  126.                 c.get(0).set(0, 1.0);
  127.             }
  128.         }

  129.         if ((!okFields) || (c.size() < 1)) {
  130.             String loaderName = getClass().getName();
  131.             loaderName = loaderName.substring(loaderName.lastIndexOf('.') + 1);
  132.             throw new OrekitException(OrekitMessages.UNEXPECTED_FILE_FORMAT_ERROR_FOR_LOADER,
  133.                                       name, loaderName);
  134.         }

  135.         setRawCoefficients(true, toArray(c), toArray(s), name);
  136.         setReadComplete(true);

  137.     }

  138.     /** Get a provider for read spherical harmonics coefficients.
  139.      * <p>
  140.      * EGM fields don't include time-dependent parts, so this method returns
  141.      * directly a constant provider.
  142.      * </p>
  143.      * @param wantNormalized if true, the provider will provide normalized coefficients,
  144.      * otherwise it will provide un-normalized coefficients
  145.      * @param degree maximal degree
  146.      * @param order maximal order
  147.      * @return a new provider
  148.      * @since 6.0
  149.      */
  150.     public RawSphericalHarmonicsProvider getProvider(final boolean wantNormalized,
  151.                                                      final int degree, final int order) {
  152.         return getConstantProvider(wantNormalized, degree, order);
  153.     }

  154. }