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.frames;
18  
19  import java.util.ArrayList;
20  import java.util.HashMap;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.SortedSet;
24  import java.util.TreeSet;
25  import java.util.function.Supplier;
26  
27  import org.orekit.data.DataProvidersManager;
28  import org.orekit.errors.OrekitException;
29  import org.orekit.time.ChronologicalComparator;
30  import org.orekit.time.TimeScale;
31  import org.orekit.time.TimeScales;
32  import org.orekit.utils.Constants;
33  import org.orekit.utils.IERSConventions;
34  
35  /**
36   * Loads Earth Orientation Parameters (EOP) from a configured set of {@link
37   * EOPHistoryLoader}s on demand. Methods are synchronized so it is safe for access from
38   * multiple threads.
39   *
40   * @author Guylaine Prat
41   * @author Luc Maisonobe
42   * @author Pascal Parraud
43   * @author Evan Ward
44   * @see LazyLoadedFrames
45   * @see FramesFactory
46   * @since 10.1
47   */
48  public class LazyLoadedEop {
49  
50      /** Provides access to the EOP data files. */
51      private final DataProvidersManager dataProvidersManager;
52      /** Loaders for Earth Orientation parameters. */
53      private final Map<IERSConventions, List<EOPHistoryLoader>> eopHistoryLoaders;
54      /** Threshold for EOP continuity. */
55      private double eopContinuityThreshold;
56  
57      /**
58       * Create a new instance for loading EOP data from multiple {@link
59       * EOPHistoryLoader}s.
60       *
61       * @param dataProvidersManager provides access to the needed EOP data files.
62       */
63      public LazyLoadedEop(final DataProvidersManager dataProvidersManager) {
64          this.dataProvidersManager = dataProvidersManager;
65          this.eopHistoryLoaders = new HashMap<>();
66          this.eopContinuityThreshold = 5 * Constants.JULIAN_DAY;
67      }
68  
69      /**
70       * Get the data providers manager for this instance.
71       *
72       * @return the provider of EOP data files.
73       */
74      public DataProvidersManager getDataProvidersManager() {
75          return dataProvidersManager;
76      }
77  
78      /**
79       * Add the default loaders EOP history (IAU 1980 precession/nutation).
80       * <p>
81       * The default loaders look for IERS EOP C04 and bulletins B files. They correspond to
82       * {@link IERSConventions#IERS_1996 IERS 1996} conventions.
83       * </p>
84       *
85       * @param rapidDataColumnsSupportedNames regular expression for supported rapid data
86       *                                       columns EOP files names (may be null if the
87       *                                       default IERS file names are used)
88       * @param rapidDataXMLSupportedNames     regular expression for supported rapid data
89       *                                       XML EOP files names (may be null if the
90       *                                       default IERS file names are used)
91       * @param eopC04SupportedNames           regular expression for supported EOP C04
92       *                                       files names (may be null if the default IERS
93       *                                       file names are used)
94       * @param bulletinBSupportedNames        regular expression for supported bulletin B
95       *                                       files names (may be null if the default IERS
96       *                                       file names are used)
97       * @param bulletinASupportedNames        regular expression for supported bulletin A
98       *                                       files names (may be null if the default IERS
99       *                                       file names are used)
100      * @param utcSupplier                    UTC time scale supplier. Value is not
101      *                                       accessed until attempting to load EOP.
102      * @see <a href="http://hpiers.obspm.fr/eoppc/eop/eopc04/">IERS EOP C04 files</a>
103      * @see #addEOPHistoryLoader(IERSConventions, EOPHistoryLoader)
104      * @see #clearEOPHistoryLoaders()
105      * @see #addDefaultEOP2000HistoryLoaders(String, String, String, String, String, Supplier)
106      */
107     public void addDefaultEOP1980HistoryLoaders(final String rapidDataColumnsSupportedNames,
108                                                 final String rapidDataXMLSupportedNames,
109                                                 final String eopC04SupportedNames,
110                                                 final String bulletinBSupportedNames,
111                                                 final String bulletinASupportedNames,
112                                                 final Supplier<TimeScale> utcSupplier) {
113         final String rapidColNames =
114                 (rapidDataColumnsSupportedNames == null) ?
115                         FramesFactory.RAPID_DATA_PREDICTION_COLUMNS_1980_FILENAME :
116                         rapidDataColumnsSupportedNames;
117         addEOPHistoryLoader(IERSConventions.IERS_1996,
118                 new RapidDataAndPredictionColumnsLoader(false, rapidColNames,
119                         dataProvidersManager, utcSupplier));
120         final String rapidXmlNames =
121                 (rapidDataXMLSupportedNames == null) ?
122                         FramesFactory.RAPID_DATA_PREDICTION_XML_1980_FILENAME :
123                         rapidDataXMLSupportedNames;
124         addEOPHistoryLoader(IERSConventions.IERS_1996,
125                 new RapidDataAndPredictionXMLLoader(rapidXmlNames, dataProvidersManager,
126                         utcSupplier));
127         final String eopcNames =
128                 (eopC04SupportedNames == null) ?
129                         FramesFactory.EOPC04_1980_FILENAME : eopC04SupportedNames;
130         addEOPHistoryLoader(IERSConventions.IERS_1996,
131                 new EOPC04FilesLoader(eopcNames, dataProvidersManager, utcSupplier));
132         final String bulBNames =
133                 (bulletinBSupportedNames == null) ?
134                         FramesFactory.BULLETINB_1980_FILENAME : bulletinBSupportedNames;
135         addEOPHistoryLoader(IERSConventions.IERS_1996,
136                 new BulletinBFilesLoader(bulBNames, dataProvidersManager, utcSupplier));
137         final String bulANames =
138                 (bulletinASupportedNames == null) ?
139                         FramesFactory.BULLETINA_FILENAME : bulletinASupportedNames;
140         addEOPHistoryLoader(IERSConventions.IERS_1996,
141                 new BulletinAFilesLoader(bulANames, dataProvidersManager, utcSupplier));
142     }
143 
144     /**
145      * Add the default loaders for EOP history (IAU 2000/2006 precession/nutation).
146      * <p>
147      * The default loaders look for IERS EOP C04 and bulletins B files. They correspond to
148      * both {@link IERSConventions#IERS_2003 IERS 2003} and {@link
149      * IERSConventions#IERS_2010 IERS 2010} conventions.
150      * </p>
151      *
152      * @param rapidDataColumnsSupportedNames regular expression for supported rapid data
153      *                                       columns EOP files names (may be null if the
154      *                                       default IERS file names are used)
155      * @param rapidDataXMLSupportedNames     regular expression for supported rapid data
156      *                                       XML EOP files names (may be null if the
157      *                                       default IERS file names are used)
158      * @param eopC04SupportedNames           regular expression for supported EOP C04
159      *                                       files names (may be null if the default IERS
160      *                                       file names are used)
161      * @param bulletinBSupportedNames        regular expression for supported bulletin B
162      *                                       files names (may be null if the default IERS
163      *                                       file names are used)
164      * @param bulletinASupportedNames        regular expression for supported bulletin A
165      *                                       files names (may be null if the default IERS
166      *                                       file names are used)
167      * @param utcSupplier                    UTC time scale supplier. Value is not
168      *                                       accessed until attempting to load EOP.
169      * @see <a href="http://hpiers.obspm.fr/eoppc/eop/eopc04/">IERS EOP C04 files</a>
170      * @see #addEOPHistoryLoader(IERSConventions, EOPHistoryLoader)
171      * @see #clearEOPHistoryLoaders()
172      * @see #addDefaultEOP1980HistoryLoaders(String, String, String, String, String, Supplier)
173      */
174     public void addDefaultEOP2000HistoryLoaders(final String rapidDataColumnsSupportedNames,
175                                                 final String rapidDataXMLSupportedNames,
176                                                 final String eopC04SupportedNames,
177                                                 final String bulletinBSupportedNames,
178                                                 final String bulletinASupportedNames,
179                                                 final Supplier<TimeScale> utcSupplier) {
180         final String rapidColNames =
181                 (rapidDataColumnsSupportedNames == null) ?
182                         FramesFactory.RAPID_DATA_PREDICITON_COLUMNS_2000_FILENAME :
183                         rapidDataColumnsSupportedNames;
184         addEOPHistoryLoader(IERSConventions.IERS_2003,
185                 new RapidDataAndPredictionColumnsLoader(
186                         true, rapidColNames, dataProvidersManager, utcSupplier));
187         addEOPHistoryLoader(IERSConventions.IERS_2010,
188                 new RapidDataAndPredictionColumnsLoader(
189                         true, rapidColNames, dataProvidersManager, utcSupplier));
190         final String rapidXmlNames =
191                 (rapidDataXMLSupportedNames == null) ?
192                         FramesFactory.RAPID_DATA_PREDICITON_XML_2000_FILENAME :
193                         rapidDataXMLSupportedNames;
194         addEOPHistoryLoader(IERSConventions.IERS_2003,
195                 new RapidDataAndPredictionXMLLoader(
196                         rapidXmlNames, dataProvidersManager, utcSupplier));
197         addEOPHistoryLoader(IERSConventions.IERS_2010,
198                 new RapidDataAndPredictionXMLLoader(
199                         rapidXmlNames, dataProvidersManager, utcSupplier));
200         final String eopcNames =
201                 (eopC04SupportedNames == null) ?
202                         FramesFactory.EOPC04_2000_FILENAME : eopC04SupportedNames;
203         addEOPHistoryLoader(IERSConventions.IERS_2003,
204                 new EOPC04FilesLoader(eopcNames, dataProvidersManager, utcSupplier));
205         addEOPHistoryLoader(IERSConventions.IERS_2010,
206                 new EOPC04FilesLoader(eopcNames, dataProvidersManager, utcSupplier));
207         final String bulBNames =
208                 (bulletinBSupportedNames == null) ?
209                         FramesFactory.BULLETINB_2000_FILENAME : bulletinBSupportedNames;
210         addEOPHistoryLoader(IERSConventions.IERS_2003,
211                 new BulletinBFilesLoader(bulBNames, dataProvidersManager, utcSupplier));
212         addEOPHistoryLoader(IERSConventions.IERS_2010,
213                 new BulletinBFilesLoader(bulBNames, dataProvidersManager, utcSupplier));
214         final String bulANames =
215                 (bulletinASupportedNames == null) ?
216                         FramesFactory.BULLETINA_FILENAME : bulletinASupportedNames;
217         addEOPHistoryLoader(IERSConventions.IERS_2003,
218                 new BulletinAFilesLoader(bulANames, dataProvidersManager, utcSupplier));
219         addEOPHistoryLoader(IERSConventions.IERS_2010,
220                 new BulletinAFilesLoader(bulANames, dataProvidersManager, utcSupplier));
221     }
222 
223     /**
224      * Add a loader for Earth Orientation Parameters history.
225      *
226      * @param conventions IERS conventions to which EOP history applies
227      * @param loader      custom loader to add for the EOP history
228      * @see #addDefaultEOP1980HistoryLoaders(String, String, String, String, String, Supplier)
229      * @see #clearEOPHistoryLoaders()
230      */
231     public void addEOPHistoryLoader(final IERSConventions conventions, final EOPHistoryLoader loader) {
232         synchronized (eopHistoryLoaders) {
233             if (!eopHistoryLoaders.containsKey(conventions)) {
234                 eopHistoryLoaders.put(conventions, new ArrayList<>());
235             }
236             eopHistoryLoaders.get(conventions).add(loader);
237         }
238     }
239 
240     /**
241      * Clear loaders for Earth Orientation Parameters history.
242      *
243      * @see #addEOPHistoryLoader(IERSConventions, EOPHistoryLoader)
244      * @see #addDefaultEOP1980HistoryLoaders(String, String, String, String, String, Supplier)
245      */
246     public void clearEOPHistoryLoaders() {
247         synchronized (eopHistoryLoaders) {
248             eopHistoryLoaders.clear();
249         }
250     }
251 
252     /**
253      * Set the threshold to check EOP continuity.
254      * <p>
255      * The default threshold (used if this method is never called) is 5 Julian days. If
256      * after loading EOP entries some holes between entries exceed this threshold, an
257      * exception will be triggered.
258      * </p>
259      * <p>
260      * One case when calling this method is really useful is for applications that use a
261      * single Bulletin A, as these bulletins have a roughly one month wide hole for the
262      * first bulletin of each month, which contains older final data in addition to the
263      * rapid data and the predicted data.
264      * </p>
265      *
266      * @param threshold threshold to use for checking EOP continuity (in seconds)
267      */
268     public void setEOPContinuityThreshold(final double threshold) {
269         eopContinuityThreshold = threshold;
270     }
271 
272     /**
273      * Get Earth Orientation Parameters history.
274      * <p>
275      * If no {@link EOPHistoryLoader} has been added by calling {@link
276      * #addEOPHistoryLoader(IERSConventions, EOPHistoryLoader) addEOPHistoryLoader} or if
277      * {@link #clearEOPHistoryLoaders() clearEOPHistoryLoaders} has been called
278      * afterwards, the {@link #addDefaultEOP1980HistoryLoaders(String, String, String,
279      * String, String, Supplier)} and {@link #addDefaultEOP2000HistoryLoaders(String,
280      * String, String, String, String, Supplier)} methods will be called automatically
281      * with supported file names parameters all set to null, in order to get the default
282      * loaders configuration.
283      * </p>
284      *
285      * @param conventions conventions for which EOP history is requested
286      * @param simpleEOP   if true, tidal effects are ignored when interpolating EOP
287      * @param timeScales  to use when loading EOP and computing corrections.
288      * @return Earth Orientation Parameters history
289      */
290     public EOPHistory getEOPHistory(final IERSConventions conventions,
291                                     final boolean simpleEOP,
292                                     final TimeScales timeScales) {
293 
294         synchronized (eopHistoryLoaders) {
295 
296             if (eopHistoryLoaders.isEmpty()) {
297                 // set up using default loaders
298                 final Supplier<TimeScale> utcSupplier = timeScales::getUTC;
299                 addDefaultEOP2000HistoryLoaders(null, null, null, null, null, utcSupplier);
300                 addDefaultEOP1980HistoryLoaders(null, null, null, null, null, utcSupplier);
301             }
302 
303             // TimeStamped based set needed to remove duplicates
304             OrekitException pendingException = null;
305             final SortedSet<EOPEntry> data = new TreeSet<>(new ChronologicalComparator());
306 
307             // try to load canonical data if available
308             if (eopHistoryLoaders.containsKey(conventions)) {
309                 for (final EOPHistoryLoader loader : eopHistoryLoaders.get(conventions)) {
310                     try {
311                         loader.fillHistory(
312                                 conventions.getNutationCorrectionConverter(timeScales),
313                                 data);
314                     } catch (OrekitException oe) {
315                         pendingException = oe;
316                     }
317                 }
318             }
319 
320             if (data.isEmpty() && pendingException != null) {
321                 throw pendingException;
322             }
323 
324             final EOPHistory history =
325                     new EOPHistory(conventions, data, simpleEOP, timeScales);
326             history.checkEOPContinuity(eopContinuityThreshold);
327             return history;
328 
329         }
330 
331     }
332 
333 }