EGMFormatReader.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.text.ParseException;
  23. import java.util.ArrayList;
  24. import java.util.List;
  25. import java.util.Locale;

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

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

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

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

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


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

  66.         // reset the indicator before loading any data
  67.         setReadComplete(false);

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

  79.         final String lowerCaseName = name.toLowerCase(Locale.US);
  80.         if (lowerCaseName.contains("2008") || lowerCaseName.contains("zerotide")) {
  81.             setTideSystem(TideSystem.ZERO_TIDE);
  82.         } else {
  83.             setTideSystem(TideSystem.TIDE_FREE);
  84.         }

  85.         final BufferedReader r = new BufferedReader(new InputStreamReader(input, "UTF-8"));
  86.         final List<List<Double>> c = new ArrayList<List<Double>>();
  87.         final List<List<Double>> s = new ArrayList<List<Double>>();
  88.         boolean okFields = true;
  89.         for (String line = r.readLine(); okFields && line != null; line = r.readLine()) {
  90.             if (line.length() >= 15) {

  91.                 // get the fields defining the current the potential terms
  92.                 final String[] tab = line.trim().split("\\s+");
  93.                 if (tab.length != 6) {
  94.                     okFields = false;
  95.                 }

  96.                 final int i = Integer.parseInt(tab[0]);
  97.                 final int j = Integer.parseInt(tab[1]);
  98.                 if (i <= getMaxParseDegree() && j <= getMaxParseOrder()) {
  99.                     for (int k = 0; k <= i; ++k) {
  100.                         extendListOfLists(c, k, FastMath.min(k, getMaxParseOrder()),
  101.                                           missingCoefficientsAllowed() ? 0.0 : Double.NaN);
  102.                         extendListOfLists(s, k, FastMath.min(k, getMaxParseOrder()),
  103.                                           missingCoefficientsAllowed() ? 0.0 : Double.NaN);
  104.                     }
  105.                     parseCoefficient(tab[2], c, i, j, "C", name);
  106.                     parseCoefficient(tab[3], s, i, j, "S", name);
  107.                 }

  108.             }
  109.         }

  110.         if (missingCoefficientsAllowed() && getMaxParseDegree() > 0 && getMaxParseOrder() > 0) {
  111.             // ensure at least the (0, 0) element is properly set
  112.             extendListOfLists(c, 0, 0, 0.0);
  113.             extendListOfLists(s, 0, 0, 0.0);
  114.             if (Precision.equals(c.get(0).get(0), 0.0, 0)) {
  115.                 c.get(0).set(0, 1.0);
  116.             }
  117.         }

  118.         if ((!okFields) || (c.size() < 1)) {
  119.             String loaderName = getClass().getName();
  120.             loaderName = loaderName.substring(loaderName.lastIndexOf('.') + 1);
  121.             throw new OrekitException(OrekitMessages.UNEXPECTED_FILE_FORMAT_ERROR_FOR_LOADER,
  122.                                       name, loaderName);
  123.         }

  124.         setRawCoefficients(true, toArray(c), toArray(s), name);
  125.         setReadComplete(true);

  126.     }

  127.     /** Get a provider for read spherical harmonics coefficients.
  128.      * <p>
  129.      * EGM fields don't include time-dependent parts, so this method returns
  130.      * directly a constant provider.
  131.      * </p>
  132.      * @param wantNormalized if true, the provider will provide normalized coefficients,
  133.      * otherwise it will provide un-normalized coefficients
  134.      * @param degree maximal degree
  135.      * @param order maximal order
  136.      * @return a new provider
  137.      * @exception OrekitException if the requested maximal degree or order exceeds the
  138.      * available degree or order or if no gravity field has read yet
  139.      * @since 6.0
  140.      */
  141.     public RawSphericalHarmonicsProvider getProvider(final boolean wantNormalized,
  142.                                                      final int degree, final int order)
  143.         throws OrekitException {
  144.         return getConstantProvider(wantNormalized, degree, order);
  145.     }

  146. }