LazyLoadedGeoMagneticFields.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.models.earth;

  18. import java.util.Collection;
  19. import java.util.NavigableMap;
  20. import java.util.SortedMap;
  21. import java.util.TreeMap;

  22. import org.hipparchus.util.FastMath;
  23. import org.orekit.data.DataProvidersManager;
  24. import org.orekit.errors.OrekitException;
  25. import org.orekit.errors.OrekitMessages;
  26. import org.orekit.models.earth.GeoMagneticFieldFactory.FieldModel;

  27. /**
  28.  * Loads magnetic fields on request and can be configured after creation. Designed to
  29.  * match the behavior of {@link GeoMagneticFieldFactory} in Orekit 10.0
  30.  *
  31.  * @author Evan Ward
  32.  * @author Thomas Neidhart
  33.  * @since 10.1
  34.  */
  35. public class LazyLoadedGeoMagneticFields implements GeoMagneticFields {

  36.     /** Loaded IGRF models. */
  37.     private NavigableMap<Integer, GeoMagneticField> igrfModels = null;

  38.     /** Loaded WMM models. */
  39.     private NavigableMap<Integer, GeoMagneticField> wmmModels = null;

  40.     /** Provides access to auxiliary data files. */
  41.     private final DataProvidersManager dataProvidersManager;

  42.     /**
  43.      * Create a factory for magnetic fields that uses the given data manager to load
  44.      * magnetic field files.
  45.      *
  46.      * @param dataProvidersManager provides access to auxiliary data files.
  47.      */
  48.     public LazyLoadedGeoMagneticFields(final DataProvidersManager dataProvidersManager) {
  49.         this.dataProvidersManager = dataProvidersManager;
  50.     }

  51.     @Override
  52.     public GeoMagneticField getField(final FieldModel type, final double year) {
  53.         switch (type) {
  54.             case WMM:
  55.                 return getWMM(year);
  56.             case IGRF:
  57.                 return getIGRF(year);
  58.             default:
  59.                 throw new OrekitException(OrekitMessages.NON_EXISTENT_GEOMAGNETIC_MODEL, type.name(), year);
  60.         }
  61.     }

  62.     @Override
  63.     public GeoMagneticField getIGRF(final double year) {
  64.         synchronized (this) {
  65.             if (igrfModels == null) {
  66.                 igrfModels = loadModels("^IGRF\\.COF$");
  67.             }
  68.             return getModel(FieldModel.IGRF, igrfModels, year);
  69.         }
  70.     }

  71.     @Override
  72.     public GeoMagneticField getWMM(final double year) {
  73.         synchronized (this) {
  74.             if (wmmModels == null) {
  75.                 wmmModels = loadModels("^WMM\\.COF$");
  76.             }
  77.             return getModel(FieldModel.WMM, wmmModels, year);
  78.         }
  79.     }

  80.     /** Loads the geomagnetic model files from the given filename. The loaded
  81.      * models are inserted in a {@link NavigableMap} with their epoch as key in order
  82.      * to retrieve them in a sorted manner.
  83.      * @param supportedNames a regular expression for valid filenames
  84.      * @return a {@link NavigableMap} of all loaded models
  85.      */
  86.     private NavigableMap<Integer, GeoMagneticField> loadModels(final String supportedNames) {

  87.         NavigableMap<Integer, GeoMagneticField> loadedModels = null;
  88.         final GeoMagneticModelLoader loader = new GeoMagneticModelLoader();
  89.         dataProvidersManager.feed(supportedNames, loader);

  90.         if (!loader.stillAcceptsData()) {
  91.             final Collection<GeoMagneticField> models = loader.getModels();
  92.             if (models != null) {
  93.                 loadedModels = new TreeMap<>();
  94.                 for (GeoMagneticField model : models) {
  95.                     // round to a precision of two digits after the comma
  96.                     final int epoch = (int) FastMath.round(model.getEpoch() * 100d);
  97.                     loadedModels.put(epoch, model);
  98.                 }
  99.             }
  100.         }

  101.         // if no models could be loaded -> throw exception
  102.         if (loadedModels == null || loadedModels.size() == 0) {
  103.             throw new OrekitException(OrekitMessages.UNABLE_TO_FIND_RESOURCE, supportedNames);
  104.         }

  105.         return loadedModels;
  106.     }

  107.     /** Gets a geomagnetic field model for the given year. In case the specified
  108.      * year does not match an existing model epoch, the resulting field is
  109.      * generated by either time-transforming an existing model using its secular
  110.      * variation coefficients, or by linear interpolating two existing models.
  111.      * @param type the type of the field (e.g. WMM or IGRF)
  112.      * @param models all loaded field models, sorted by their epoch
  113.      * @param year the epoch of the resulting field model
  114.      * @return a {@link GeoMagneticField} model for the given year
  115.      */
  116.     private static GeoMagneticField getModel(final FieldModel type,
  117.                                              final NavigableMap<Integer, GeoMagneticField> models,
  118.                                              final double year) {

  119.         final int epochKey = (int) (year * 100d);
  120.         final SortedMap<Integer, GeoMagneticField> head = models.headMap(epochKey, true);

  121.         if (head.isEmpty()) {
  122.             throw new OrekitException(OrekitMessages.NON_EXISTENT_GEOMAGNETIC_MODEL, type.name(), year);
  123.         }

  124.         GeoMagneticField model = models.get(head.lastKey());
  125.         if (model.getEpoch() < year) {
  126.             if (model.supportsTimeTransform()) {
  127.                 model = model.transformModel(year);
  128.             } else {
  129.                 final SortedMap<Integer, GeoMagneticField> tail = models.tailMap(epochKey, false);
  130.                 if (tail.isEmpty()) {
  131.                     throw new OrekitException(OrekitMessages.NON_EXISTENT_GEOMAGNETIC_MODEL, type.name(), year);
  132.                 }
  133.                 final GeoMagneticField secondModel = models.get(tail.firstKey());
  134.                 if (secondModel != model) {
  135.                     model = model.transformModel(secondModel, year);
  136.                 }
  137.             }
  138.         }
  139.         return model;
  140.     }

  141. }