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      /** Degree for EOP interpolation.
57       * @since 12.0
58       */
59      private int interpolationDegree;
60  
61      /**
62       * Create a new instance for loading EOP data from multiple {@link
63       * EopHistoryLoader}s.
64       *
65       * @param dataProvidersManager provides access to the needed EOP data files.
66       */
67      public LazyLoadedEop(final DataProvidersManager dataProvidersManager) {
68          this.dataProvidersManager   = dataProvidersManager;
69          this.eopHistoryLoaders      = new HashMap<>();
70          this.eopContinuityThreshold = 5 * Constants.JULIAN_DAY;
71          this.interpolationDegree    = EOPHistory.DEFAULT_INTERPOLATION_DEGREE;
72      }
73  
74      /**
75       * Get the data providers manager for this instance.
76       *
77       * @return the provider of EOP data files.
78       */
79      public DataProvidersManager getDataProvidersManager() {
80          return dataProvidersManager;
81      }
82  
83      /**
84       * Add the default loaders EOP history (IAU 1980 precession/nutation).
85       * <p>
86       * The default loaders look for IERS EOP C04 and bulletins B files. They correspond to
87       * {@link IERSConventions#IERS_1996 IERS 1996} conventions.
88       * </p>
89       *
90       * @param rapidDataColumnsSupportedNames regular expression for supported rapid data
91       *                                       columns EOP files names (may be null if the
92       *                                       default IERS file names are used)
93       * @param xmlSupportedNames              regular expression for supported XML EOP
94       *                                       files names (may be null if the
95       *                                       default IERS file names are used)
96       * @param eopC04SupportedNames           regular expression for supported EOP C04
97       *                                       files names (may be null if the default IERS
98       *                                       file names are used)
99       * @param bulletinBSupportedNames        regular expression for supported bulletin B
100      *                                       files names (may be null if the default IERS
101      *                                       file names are used)
102      * @param bulletinASupportedNames        regular expression for supported bulletin A
103      *                                       files names (may be null if the default IERS
104      *                                       file names are used)
105      * @param csvSupportedNames              regular expression for supported csv files names
106      *                                       (may be null if the default IERS file names are used)
107      * @param utcSupplier                    UTC time scale supplier. Value is not
108      *                                       accessed until attempting to load EOP.
109      * @see <a href="https://datacenter.iers.org/products/eop/">IERS https data download</a>
110      * @see #addEOPHistoryLoader(IERSConventions, EopHistoryLoader)
111      * @see #clearEOPHistoryLoaders()
112      * @see #addDefaultEOP2000HistoryLoaders(String, String, String, String, String, String, Supplier)
113      * @since 12.0
114      */
115     public void addDefaultEOP1980HistoryLoaders(final String rapidDataColumnsSupportedNames,
116                                                 final String xmlSupportedNames,
117                                                 final String eopC04SupportedNames,
118                                                 final String bulletinBSupportedNames,
119                                                 final String bulletinASupportedNames,
120                                                 final String csvSupportedNames,
121                                                 final Supplier<TimeScale> utcSupplier) {
122         final String rapidColNames =
123                 (rapidDataColumnsSupportedNames == null) ?
124                         FramesFactory.RAPID_DATA_PREDICTION_COLUMNS_1980_FILENAME :
125                         rapidDataColumnsSupportedNames;
126         addEOPHistoryLoader(IERSConventions.IERS_1996,
127                 new RapidDataAndPredictionColumnsLoader(false, rapidColNames,
128                         dataProvidersManager, utcSupplier));
129         final String xmlNames = (xmlSupportedNames == null) ?
130                                 FramesFactory.XML_1980_FILENAME :
131                                 xmlSupportedNames;
132         addEOPHistoryLoader(IERSConventions.IERS_1996,
133                             new EopXmlLoader(xmlNames, dataProvidersManager, utcSupplier));
134         final String eopcNames =
135                 (eopC04SupportedNames == null) ?
136                         FramesFactory.EOPC04_1980_FILENAME : eopC04SupportedNames;
137         addEOPHistoryLoader(IERSConventions.IERS_1996,
138                 new EopC04FilesLoader(eopcNames, dataProvidersManager, utcSupplier));
139         final String bulBNames =
140                 (bulletinBSupportedNames == null) ?
141                         FramesFactory.BULLETINB_1980_FILENAME : bulletinBSupportedNames;
142         addEOPHistoryLoader(IERSConventions.IERS_1996,
143                 new BulletinBFilesLoader(bulBNames, dataProvidersManager, utcSupplier));
144         final String bulANames =
145                 (bulletinASupportedNames == null) ?
146                         FramesFactory.BULLETINA_FILENAME : bulletinASupportedNames;
147         addEOPHistoryLoader(IERSConventions.IERS_1996,
148                 new BulletinAFilesLoader(bulANames, dataProvidersManager, utcSupplier));
149         final String csvNames = (csvSupportedNames == null) ?
150                                 FramesFactory.CSV_FILENAME : csvSupportedNames;
151         addEOPHistoryLoader(IERSConventions.IERS_1996,
152                             new EopCsvFilesLoader(csvNames, dataProvidersManager, utcSupplier));
153     }
154 
155     /**
156      * Add the default loaders for EOP history (IAU 2000/2006 precession/nutation).
157      * <p>
158      * The default loaders look for IERS EOP C04 and bulletins B files. They correspond to
159      * both {@link IERSConventions#IERS_2003 IERS 2003} and {@link
160      * IERSConventions#IERS_2010 IERS 2010} conventions.
161      * </p>
162      *
163      * @param rapidDataColumnsSupportedNames regular expression for supported rapid data
164      *                                       columns EOP files names (may be null if the
165      *                                       default IERS file names are used)
166      * @param xmlSupportedNames              regular expression for supported XML EOP
167      *                                       files names (may be null if the
168      *                                       default IERS file names are used)
169      * @param eopC04SupportedNames           regular expression for supported EOP C04
170      *                                       files names (may be null if the default IERS
171      *                                       file names are used)
172      * @param bulletinBSupportedNames        regular expression for supported bulletin B
173      *                                       files names (may be null if the default IERS
174      *                                       file names are used)
175      * @param bulletinASupportedNames        regular expression for supported bulletin A
176      *                                       files names (may be null if the default IERS
177      *                                       file names are used)
178      * @param csvSupportedNames              regular expression for supported csv files names
179      *                                       (may be null if the default IERS file names are used)
180      * @param utcSupplier                    UTC time scale supplier. Value is not
181      *                                       accessed until attempting to load EOP.
182      * @see <a href="https://datacenter.iers.org/products/eop/">IERS https data download</a>
183      * @see #addEOPHistoryLoader(IERSConventions, EopHistoryLoader)
184      * @see #clearEOPHistoryLoaders()
185      * @see #addDefaultEOP1980HistoryLoaders(String, String, String, String, String, String, Supplier)
186      * @since 12.0
187      */
188     public void addDefaultEOP2000HistoryLoaders(final String rapidDataColumnsSupportedNames,
189                                                 final String xmlSupportedNames,
190                                                 final String eopC04SupportedNames,
191                                                 final String bulletinBSupportedNames,
192                                                 final String bulletinASupportedNames,
193                                                 final String csvSupportedNames,
194                                                 final Supplier<TimeScale> utcSupplier) {
195         final String rapidColNames =
196                 (rapidDataColumnsSupportedNames == null) ?
197                         FramesFactory.RAPID_DATA_PREDICTION_COLUMNS_2000_FILENAME :
198                         rapidDataColumnsSupportedNames;
199         addEOPHistoryLoader(IERSConventions.IERS_2003,
200                             new RapidDataAndPredictionColumnsLoader(true, rapidColNames, dataProvidersManager, utcSupplier));
201         addEOPHistoryLoader(IERSConventions.IERS_2010,
202                             new RapidDataAndPredictionColumnsLoader(true, rapidColNames, dataProvidersManager, utcSupplier));
203         final String xmlNames = (xmlSupportedNames == null) ?
204                                 FramesFactory.XML_2000_FILENAME :
205                                 xmlSupportedNames;
206         addEOPHistoryLoader(IERSConventions.IERS_2003,
207                             new EopXmlLoader(xmlNames, dataProvidersManager, utcSupplier));
208         addEOPHistoryLoader(IERSConventions.IERS_2010,
209                             new EopXmlLoader(xmlNames, dataProvidersManager, utcSupplier));
210         final String eopcNames = (eopC04SupportedNames == null) ?
211                                  FramesFactory.EOPC04_2000_FILENAME : eopC04SupportedNames;
212         addEOPHistoryLoader(IERSConventions.IERS_2003,
213                 new EopC04FilesLoader(eopcNames, dataProvidersManager, utcSupplier));
214         addEOPHistoryLoader(IERSConventions.IERS_2010,
215                 new EopC04FilesLoader(eopcNames, dataProvidersManager, utcSupplier));
216         final String bulBNames = (bulletinBSupportedNames == null) ?
217                                  FramesFactory.BULLETINB_2000_FILENAME : bulletinBSupportedNames;
218         addEOPHistoryLoader(IERSConventions.IERS_2003,
219                 new BulletinBFilesLoader(bulBNames, dataProvidersManager, utcSupplier));
220         addEOPHistoryLoader(IERSConventions.IERS_2010,
221                 new BulletinBFilesLoader(bulBNames, dataProvidersManager, utcSupplier));
222         final String bulANames = (bulletinASupportedNames == null) ?
223                                  FramesFactory.BULLETINA_FILENAME : bulletinASupportedNames;
224         addEOPHistoryLoader(IERSConventions.IERS_2003,
225                             new BulletinAFilesLoader(bulANames, dataProvidersManager, utcSupplier));
226         addEOPHistoryLoader(IERSConventions.IERS_2010,
227                             new BulletinAFilesLoader(bulANames, dataProvidersManager, utcSupplier));
228         final String csvNames = (csvSupportedNames == null) ?
229                                 FramesFactory.CSV_FILENAME : csvSupportedNames;
230         addEOPHistoryLoader(IERSConventions.IERS_2003,
231                             new EopCsvFilesLoader(csvNames, dataProvidersManager, utcSupplier));
232         addEOPHistoryLoader(IERSConventions.IERS_2010,
233                             new EopCsvFilesLoader(csvNames, dataProvidersManager, utcSupplier));
234     }
235 
236     /**
237      * Add a loader for Earth Orientation Parameters history.
238      *
239      * @param conventions IERS conventions to which EOP history applies
240      * @param loader      custom loader to add for the EOP history
241      * @see #addDefaultEOP1980HistoryLoaders(String, String, String, String, String, String, Supplier)
242      * @see #clearEOPHistoryLoaders()
243      */
244     public void addEOPHistoryLoader(final IERSConventions conventions, final EopHistoryLoader loader) {
245         synchronized (eopHistoryLoaders) {
246             if (!eopHistoryLoaders.containsKey(conventions)) {
247                 eopHistoryLoaders.put(conventions, new ArrayList<>());
248             }
249             eopHistoryLoaders.get(conventions).add(loader);
250         }
251     }
252 
253     /**
254      * Clear loaders for Earth Orientation Parameters history.
255      *
256      * @see #addEOPHistoryLoader(IERSConventions, EopHistoryLoader)
257      * @see #addDefaultEOP1980HistoryLoaders(String, String, String, String, String, String, Supplier)
258      */
259     public void clearEOPHistoryLoaders() {
260         synchronized (eopHistoryLoaders) {
261             eopHistoryLoaders.clear();
262         }
263     }
264 
265     /**
266      * Set the threshold to check EOP continuity.
267      * <p>
268      * The default threshold (used if this method is never called) is 5 Julian days. If
269      * after loading EOP entries some holes between entries exceed this threshold, an
270      * exception will be triggered.
271      * </p>
272      * <p>
273      * One case when calling this method is really useful is for applications that use a
274      * single Bulletin A, as these bulletins have a roughly one month wide hole for the
275      * first bulletin of each month, which contains older final data in addition to the
276      * rapid data and the predicted data.
277      * </p>
278      *
279      * @param threshold threshold to use for checking EOP continuity (in seconds)
280      */
281     public void setEOPContinuityThreshold(final double threshold) {
282         eopContinuityThreshold = threshold;
283     }
284 
285     /**
286      * Set the degree for interpolation degree.
287      * <p>
288      * The default threshold (used if this method is never called) is {@link EOPHistory#DEFAULT_INTERPOLATION_DEGREE}.
289      * </p>
290      *
291      * @param interpolationDegree interpolation degree, must be of the form 4k-1
292      * @since 12.0
293      */
294     public void setInterpolationDegree(final int interpolationDegree) {
295         this.interpolationDegree = interpolationDegree;
296     }
297 
298     /**
299      * Get Earth Orientation Parameters history.
300      * <p>
301      * If no {@link EopHistoryLoader} has been added by calling {@link
302      * #addEOPHistoryLoader(IERSConventions, EopHistoryLoader) addEOPHistoryLoader} or if
303      * {@link #clearEOPHistoryLoaders() clearEOPHistoryLoaders} has been called
304      * afterwards, the {@link #addDefaultEOP1980HistoryLoaders(String, String, String,
305      * String, String, String, Supplier)} and {@link #addDefaultEOP2000HistoryLoaders(String,
306      * String, String, String, String, String, Supplier)} methods will be called automatically
307      * with supported file names parameters all set to null, in order to get the default
308      * loaders configuration.
309      * </p>
310      *
311      * @param conventions conventions for which EOP history is requested
312      * @param simpleEOP   if true, tidal effects are ignored when interpolating EOP
313      * @param timeScales  to use when loading EOP and computing corrections.
314      * @return Earth Orientation Parameters history
315      */
316     public EOPHistory getEOPHistory(final IERSConventions conventions,
317                                     final boolean simpleEOP,
318                                     final TimeScales timeScales) {
319 
320         synchronized (eopHistoryLoaders) {
321 
322             if (eopHistoryLoaders.isEmpty()) {
323                 // set up using default loaders
324                 final Supplier<TimeScale> utcSupplier = timeScales::getUTC;
325                 addDefaultEOP2000HistoryLoaders(null, null, null, null, null, null, utcSupplier);
326                 addDefaultEOP1980HistoryLoaders(null, null, null, null, null, null, utcSupplier);
327             }
328 
329             // TimeStamped based set needed to remove duplicates
330             OrekitException pendingException = null;
331             final SortedSet<EOPEntry> data = new TreeSet<>(new ChronologicalComparator());
332 
333             // try to load canonical data if available
334             if (eopHistoryLoaders.containsKey(conventions)) {
335                 for (final EopHistoryLoader loader : eopHistoryLoaders.get(conventions)) {
336                     try {
337                         loader.fillHistory(conventions.getNutationCorrectionConverter(timeScales),
338                                            data);
339                     } catch (OrekitException oe) {
340                         pendingException = oe;
341                     }
342                 }
343             }
344 
345             if (data.isEmpty() && pendingException != null) {
346                 throw pendingException;
347             }
348 
349             final EOPHistory history = new EOPHistory(conventions, interpolationDegree, data, simpleEOP, timeScales);
350             history.checkEOPContinuity(eopContinuityThreshold);
351             return history;
352 
353         }
354 
355     }
356 
357 }