LazyLoadedGravityFields.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 java.util.ArrayList;
  19. import java.util.List;
  20. import java.util.Map;

  21. import org.hipparchus.util.FastMath;
  22. import org.orekit.data.DataProvidersManager;
  23. import org.orekit.errors.OrekitException;
  24. import org.orekit.errors.OrekitMessages;
  25. import org.orekit.time.AbsoluteDate;
  26. import org.orekit.time.TimeScale;

  27. /**
  28.  * Loads gravity fields when first requested and can be configured until then. Designed to
  29.  * match the behavior of {@link GravityFieldFactory} in Orekit 10.0.
  30.  *
  31.  * @author Evan Ward
  32.  * @author Fabien Maussion
  33.  * @author Pascal Parraud
  34.  * @author Luc Maisonobe
  35.  * @see GravityFieldFactory
  36.  * @since 10.1
  37.  */
  38. public class LazyLoadedGravityFields implements GravityFields {

  39.     /** Potential readers. */
  40.     private final List<PotentialCoefficientsReader> readers = new ArrayList<>();

  41.     /** Ocean tides readers. */
  42.     private final List<OceanTidesReader> oceanTidesReaders =
  43.             new ArrayList<>();

  44.     /** Ocean load deformation coefficients. */
  45.     private OceanLoadDeformationCoefficients oceanLoadDeformationCoefficients =
  46.             OceanLoadDeformationCoefficients.IERS_2010;

  47.     /** Provides access to auxiliary data files for loading gravity field files. */
  48.     private final DataProvidersManager dataProvidersManager;

  49.     /** Time scale for parsing dates. */
  50.     private final TimeScale timeScale;

  51.     /**
  52.      * Create a factory for gravity fields that uses the given data manager to load the
  53.      * gravity field files.
  54.      *
  55.      * @param dataProvidersManager provides access to auxiliary data files.
  56.      * @param timeScale            use to parse dates for the {@link #addDefaultPotentialCoefficientsReaders()}.
  57.      *                             In Orekit 10.0 it is TT.
  58.      */
  59.     public LazyLoadedGravityFields(final DataProvidersManager dataProvidersManager,
  60.                                    final TimeScale timeScale) {
  61.         this.dataProvidersManager = dataProvidersManager;
  62.         this.timeScale = timeScale;
  63.     }

  64.     /** Add a reader for gravity fields.
  65.      * @param reader custom reader to add for the gravity field
  66.      * @see #addDefaultPotentialCoefficientsReaders()
  67.      * @see #clearPotentialCoefficientsReaders()
  68.      */
  69.     public void addPotentialCoefficientsReader(final PotentialCoefficientsReader reader) {
  70.         synchronized (readers) {
  71.             readers.add(reader);
  72.         }
  73.     }

  74.     /**
  75.      * Add the default readers for gravity fields.
  76.      *
  77.      * <p> The default readers support ICGEM, SHM, EGM, GRGS and SHA formats with the
  78.      * default names {@link GravityFieldFactory#ICGEM_FILENAME}, {@link
  79.      * GravityFieldFactory#SHM_FILENAME}, {@link GravityFieldFactory#EGM_FILENAME}, {@link
  80.      * GravityFieldFactory#GRGS_FILENAME}, {@link GravityFieldFactory#SHA_FILENAME}
  81.      * and don't allow missing coefficients.
  82.      *
  83.      * @see #addPotentialCoefficientsReader(PotentialCoefficientsReader)
  84.      * @see #clearPotentialCoefficientsReaders()
  85.      */
  86.     public void addDefaultPotentialCoefficientsReaders() {
  87.         synchronized (readers) {
  88.             readers.add(new ICGEMFormatReader(GravityFieldFactory.ICGEM_FILENAME, false, timeScale));
  89.             readers.add(new SHMFormatReader(GravityFieldFactory.SHM_FILENAME, false, timeScale));
  90.             readers.add(new EGMFormatReader(GravityFieldFactory.EGM_FILENAME, false));
  91.             readers.add(new GRGSFormatReader(GravityFieldFactory.GRGS_FILENAME, false, timeScale));
  92.             readers.add(new SHAFormatReader(GravityFieldFactory.SHA_FILENAME, false));
  93.         }
  94.     }

  95.     /** Clear gravity field readers.
  96.      * @see #addPotentialCoefficientsReader(PotentialCoefficientsReader)
  97.      * @see #addDefaultPotentialCoefficientsReaders()
  98.      */
  99.     public void clearPotentialCoefficientsReaders() {
  100.         synchronized (readers) {
  101.             readers.clear();
  102.         }
  103.     }

  104.     /** Add a reader for ocean tides.
  105.      * @param reader custom reader to add for the gravity field
  106.      * @see #addDefaultPotentialCoefficientsReaders()
  107.      * @see #clearPotentialCoefficientsReaders()
  108.      */
  109.     public void addOceanTidesReader(final OceanTidesReader reader) {
  110.         synchronized (oceanTidesReaders) {
  111.             oceanTidesReaders.add(reader);
  112.         }
  113.     }

  114.     /** Configure ocean load deformation coefficients.
  115.      * @param oldc ocean load deformation coefficients
  116.      * @see #getOceanLoadDeformationCoefficients()
  117.      */
  118.     public void configureOceanLoadDeformationCoefficients(final OceanLoadDeformationCoefficients oldc) {
  119.         oceanLoadDeformationCoefficients = oldc;
  120.     }

  121.     /** Get the configured ocean load deformation coefficients.
  122.      * <p>
  123.      * If {@link #configureOceanLoadDeformationCoefficients(OceanLoadDeformationCoefficients)
  124.      * configureOceanLoadDeformationCoefficients} has never been called, the default
  125.      * value will be the {@link OceanLoadDeformationCoefficients#IERS_2010 IERS 2010}
  126.      * coefficients.
  127.      * </p>
  128.      * @return ocean load deformation coefficients
  129.      * @see #configureOceanLoadDeformationCoefficients(OceanLoadDeformationCoefficients)
  130.      */
  131.     public OceanLoadDeformationCoefficients getOceanLoadDeformationCoefficients() {
  132.         return oceanLoadDeformationCoefficients;
  133.     }

  134.     /** Add the default readers for ocean tides.
  135.      * <p>
  136.      * The default readers support files similar to the fes2004_Cnm-Snm.dat and
  137.      * fes2004.dat as published by IERS, using the {@link
  138.      * #configureOceanLoadDeformationCoefficients(OceanLoadDeformationCoefficients)
  139.      * configured} ocean load deformation coefficients, which by default are the
  140.      * IERS 2010 coefficients, which are limited to degree 6. If higher degree
  141.      * coefficients are needed, the {@link
  142.      * #configureOceanLoadDeformationCoefficients(OceanLoadDeformationCoefficients)
  143.      * configureOceanLoadDeformationCoefficients} method can be called prior to
  144.      * loading the ocean tides model with the {@link
  145.      * OceanLoadDeformationCoefficients#GEGOUT high degree coefficients} computed
  146.      * by Pascal Gégout.
  147.      * </p>
  148.      * <p>
  149.      * WARNING: the files referenced in the published conventions have some errors.
  150.      * These errors have been corrected and the updated files can be found here:
  151.      * <a href="http://tai.bipm.org/iers/convupdt/convupdt_c6.html">
  152.      * http://tai.bipm.org/iers/convupdt/convupdt_c6.html</a>.
  153.      * </p>
  154.      * @see #addPotentialCoefficientsReader(PotentialCoefficientsReader)
  155.      * @see #clearPotentialCoefficientsReaders()
  156.      * @see #configureOceanLoadDeformationCoefficients(OceanLoadDeformationCoefficients)
  157.      * @see #getOceanLoadDeformationCoefficients()
  158.      */
  159.     public void addDefaultOceanTidesReaders() {
  160.         synchronized (oceanTidesReaders) {

  161.             oceanTidesReaders.add(new FESCnmSnmReader(GravityFieldFactory.FES_CNM_SNM_FILENAME, 1.0e-11));

  162.             final AstronomicalAmplitudeReader aaReader =
  163.                     new AstronomicalAmplitudeReader(GravityFieldFactory.FES_HF_FILENAME, 5, 2, 3, 1.0);
  164.             dataProvidersManager.feed(aaReader.getSupportedNames(), aaReader);
  165.             final Map<Integer, Double> map = aaReader.getAstronomicalAmplitudesMap();
  166.             oceanTidesReaders.add(new FESCHatEpsilonReader(GravityFieldFactory.FES_CHAT_EPSILON_FILENAME,
  167.                     0.01, FastMath.toRadians(1.0),
  168.                     getOceanLoadDeformationCoefficients(),
  169.                     map));


  170.         }
  171.     }

  172.     /** Clear ocean tides readers.
  173.      * @see #addPotentialCoefficientsReader(PotentialCoefficientsReader)
  174.      * @see #addDefaultPotentialCoefficientsReaders()
  175.      */
  176.     public void clearOceanTidesReaders() {
  177.         synchronized (oceanTidesReaders) {
  178.             oceanTidesReaders.clear();
  179.         }
  180.     }

  181.     /** Read a gravity field coefficients provider from the first supported file.
  182.      * <p>
  183.      * If no {@link PotentialCoefficientsReader} has been added by calling {@link
  184.      * #addPotentialCoefficientsReader(PotentialCoefficientsReader)
  185.      * addPotentialCoefficientsReader} or if {@link #clearPotentialCoefficientsReaders()
  186.      * clearPotentialCoefficientsReaders} has been called afterwards, the {@link
  187.      * #addDefaultPotentialCoefficientsReaders() addDefaultPotentialCoefficientsReaders}
  188.      * method will be called automatically.
  189.      * </p>
  190.      * @param maxParseDegree maximal degree to parse
  191.      * @param maxParseOrder maximal order to parse
  192.      * @return a reader containing already loaded data
  193.      * @since 6.0
  194.      */
  195.     public PotentialCoefficientsReader readGravityField(final int maxParseDegree,
  196.                                                         final int maxParseOrder) {

  197.         synchronized (readers) {

  198.             if (readers.isEmpty()) {
  199.                 addDefaultPotentialCoefficientsReaders();
  200.             }

  201.             // test the available readers
  202.             for (final PotentialCoefficientsReader reader : readers) {
  203.                 reader.setMaxParseDegree(maxParseDegree);
  204.                 reader.setMaxParseOrder(maxParseOrder);
  205.                 dataProvidersManager.feed(reader.getSupportedNames(), reader);
  206.                 if (!reader.stillAcceptsData()) {
  207.                     return reader;
  208.                 }
  209.             }
  210.         }

  211.         throw new OrekitException(OrekitMessages.NO_GRAVITY_FIELD_DATA_LOADED);

  212.     }

  213.     /**
  214.      * {@inheritDoc}
  215.      *
  216.      * <p> If no {@link PotentialCoefficientsReader} has been added by calling {@link
  217.      * #addPotentialCoefficientsReader(PotentialCoefficientsReader)
  218.      * addPotentialCoefficientsReader} or if {@link #clearPotentialCoefficientsReaders()
  219.      * clearPotentialCoefficientsReaders} has been called afterwards, the {@link
  220.      * #addDefaultPotentialCoefficientsReaders() addDefaultPotentialCoefficientsReaders}
  221.      * method will be called automatically.
  222.      */
  223.     @Override
  224.     public NormalizedSphericalHarmonicsProvider getConstantNormalizedProvider(final int degree, final int order,
  225.                                                                               final AbsoluteDate freezingDate) {
  226.         final RawSphericalHarmonicsProvider provider;
  227.         synchronized (readers) {
  228.             final PotentialCoefficientsReader reader = readGravityField(degree, order);
  229.             provider = reader.getProvider(true, degree, order);
  230.         }
  231.         final ConstantSphericalHarmonics frozen = new ConstantSphericalHarmonics(freezingDate, provider);
  232.         return new WrappingNormalizedProvider(frozen);
  233.     }

  234.     /**
  235.      * {@inheritDoc}
  236.      *
  237.      * <p>If no {@link PotentialCoefficientsReader} has been added by calling {@link
  238.      * #addPotentialCoefficientsReader(PotentialCoefficientsReader)
  239.      * addPotentialCoefficientsReader} or if {@link #clearPotentialCoefficientsReaders()
  240.      * clearPotentialCoefficientsReaders} has been called afterwards, the {@link
  241.      * #addDefaultPotentialCoefficientsReaders() addDefaultPotentialCoefficientsReaders}
  242.      * method will be called automatically.
  243.      */
  244.     @Override
  245.     public NormalizedSphericalHarmonicsProvider getNormalizedProvider(final int degree,
  246.                                                                       final int order) {
  247.         final RawSphericalHarmonicsProvider provider;
  248.         synchronized (readers) {
  249.             final PotentialCoefficientsReader reader = readGravityField(degree, order);
  250.             provider = reader.getProvider(true, degree, order);
  251.         }
  252.         return new WrappingNormalizedProvider(provider);
  253.     }

  254.     /**
  255.      * {@inheritDoc}
  256.      *
  257.      * <p>If no {@link PotentialCoefficientsReader} has been added by calling {@link
  258.      * #addPotentialCoefficientsReader(PotentialCoefficientsReader)
  259.      * addPotentialCoefficientsReader} or if {@link #clearPotentialCoefficientsReaders()
  260.      * clearPotentialCoefficientsReaders} has been called afterwards, the {@link
  261.      * #addDefaultPotentialCoefficientsReaders() addDefaultPotentialCoefficientsReaders}
  262.      * method will be called automatically.
  263.      */
  264.     @Override
  265.     public UnnormalizedSphericalHarmonicsProvider getConstantUnnormalizedProvider(final int degree, final int order,
  266.                                                                                   final AbsoluteDate freezingDate) {
  267.         final RawSphericalHarmonicsProvider provider;
  268.         synchronized (readers) {
  269.             final PotentialCoefficientsReader reader = readGravityField(degree, order);
  270.             provider = reader.getProvider(false, degree, order);
  271.         }
  272.         final ConstantSphericalHarmonics frozen = new ConstantSphericalHarmonics(freezingDate, provider);
  273.         return new WrappingUnnormalizedProvider(frozen);
  274.     }

  275.     /**
  276.      * {@inheritDoc}
  277.      *
  278.      * <p>If no {@link PotentialCoefficientsReader} has been added by calling {@link
  279.      * #addPotentialCoefficientsReader(PotentialCoefficientsReader)
  280.      * addPotentialCoefficientsReader} or if {@link #clearPotentialCoefficientsReaders()
  281.      * clearPotentialCoefficientsReaders} has been called afterwards, the {@link
  282.      * #addDefaultPotentialCoefficientsReaders() addDefaultPotentialCoefficientsReaders}
  283.      * method will be called automatically.
  284.      */
  285.     @Override
  286.     public UnnormalizedSphericalHarmonicsProvider getUnnormalizedProvider(final int degree,
  287.                                                                           final int order) {
  288.         final RawSphericalHarmonicsProvider provider;
  289.         synchronized (readers) {
  290.             final PotentialCoefficientsReader reader = readGravityField(degree, order);
  291.             provider = reader.getProvider(false, degree, order);
  292.         }
  293.         return new WrappingUnnormalizedProvider(provider);
  294.     }

  295.     /**
  296.      * {@inheritDoc}
  297.      *
  298.      * <p>If no {@link OceanTidesReader} has been added by calling {@link
  299.      * #addOceanTidesReader(OceanTidesReader)
  300.      * addOceanTidesReader} or if {@link #clearOceanTidesReaders()
  301.      * clearOceanTidesReaders} has been called afterwards, the {@link
  302.      * #addDefaultOceanTidesReaders() addDefaultOceanTidesReaders}
  303.      * method will be called automatically.
  304.      */
  305.     @Override
  306.     public List<OceanTidesWave> getOceanTidesWaves(final int degree, final int order) {

  307.         synchronized (oceanTidesReaders) {

  308.             if (oceanTidesReaders.isEmpty()) {
  309.                 addDefaultOceanTidesReaders();
  310.             }

  311.             // test the available readers
  312.             for (final OceanTidesReader reader : oceanTidesReaders) {
  313.                 reader.setMaxParseDegree(degree);
  314.                 reader.setMaxParseOrder(order);
  315.                 dataProvidersManager.feed(reader.getSupportedNames(), reader);
  316.                 if (!reader.stillAcceptsData()) {
  317.                     return reader.getWaves();
  318.                 }
  319.             }
  320.         }

  321.         throw new OrekitException(OrekitMessages.NO_OCEAN_TIDE_DATA_LOADED);

  322.     }

  323. }