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