1   /* Copyright 2002-2025 CS GROUP
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.SortedSet;
20  import java.util.TreeSet;
21  import org.hipparchus.util.FastMath;
22  import org.junit.jupiter.api.Assertions;
23  import org.junit.jupiter.api.Test;
24  import org.orekit.data.AbstractFilesLoaderTest;
25  import org.orekit.errors.OrekitException;
26  import org.orekit.errors.OrekitMessages;
27  import org.orekit.time.AbsoluteDate;
28  import org.orekit.time.ChronologicalComparator;
29  import org.orekit.time.TimeScalesFactory;
30  import org.orekit.utils.Constants;
31  import org.orekit.utils.IERSConventions;
32  
33  public class RapidDataAndPredictionColumnsLoaderTest extends AbstractFilesLoaderTest {
34  
35      @Test
36      public void testStartDateDaily1980() {
37          setRoot("rapid-data-columns");
38          IERSConventions.NutationCorrectionConverter converter = IERSConventions.IERS_1996.getNutationCorrectionConverter();
39          SortedSet<EOPEntry> history = new TreeSet<EOPEntry>(new ChronologicalComparator());
40          new RapidDataAndPredictionColumnsLoader(false, "^finals\\.daily$", manager, () -> utc).fillHistory(converter, history);
41          Assertions.assertEquals(new AbsoluteDate(2011, 4, 9, TimeScalesFactory.getUTC()),
42                                  new EOPHistory(IERSConventions.IERS_1996, EOPHistory.DEFAULT_INTERPOLATION_DEGREE, history, true).getStartDate());
43      }
44  
45      @Test
46      public void testEndDateDaily1980() {
47          setRoot("rapid-data-columns");
48          IERSConventions.NutationCorrectionConverter converter = IERSConventions.IERS_1996.getNutationCorrectionConverter();
49          SortedSet<EOPEntry> history = new TreeSet<EOPEntry>(new ChronologicalComparator());
50          new RapidDataAndPredictionColumnsLoader(false, "^finals\\.daily$", manager, () -> utc).fillHistory(converter, history);
51          Assertions.assertEquals(new AbsoluteDate(2011, 10, 6, TimeScalesFactory.getUTC()),
52                                  new EOPHistory(IERSConventions.IERS_1996, EOPHistory.DEFAULT_INTERPOLATION_DEGREE, history, true).getEndDate());
53      }
54  
55      @Test
56      public void testStartDateDaily2000() {
57          setRoot("rapid-data-columns");
58          IERSConventions.NutationCorrectionConverter converter = IERSConventions.IERS_2003.getNutationCorrectionConverter();
59          SortedSet<EOPEntry> history = new TreeSet<EOPEntry>(new ChronologicalComparator());
60          new RapidDataAndPredictionColumnsLoader(true, "^finals\\.daily$", manager, () -> utc).fillHistory(converter, history);
61          Assertions.assertEquals(new AbsoluteDate(2011, 4, 9, TimeScalesFactory.getUTC()),
62                                  new EOPHistory(IERSConventions.IERS_2003, EOPHistory.DEFAULT_INTERPOLATION_DEGREE, history, true).getStartDate());
63      }
64  
65      @Test
66      public void testMissingColumnsPadding1980() {
67          setRoot("rapid-data-columns");
68          IERSConventions.NutationCorrectionConverter converter = IERSConventions.IERS_1996.getNutationCorrectionConverter();
69          SortedSet<EOPEntry> data = new TreeSet<EOPEntry>(new ChronologicalComparator());
70          new RapidDataAndPredictionColumnsLoader(false, "^finals\\.daily$", manager, () -> utc).fillHistory(converter, data);
71          EOPHistory history = new EOPHistory(IERSConventions.IERS_1996, EOPHistory.DEFAULT_INTERPOLATION_DEGREE, data, true);
72  
73          // check parsing for Bulletin B data
74          AbsoluteDate t0 = new AbsoluteDate(2011, 5, 31, TimeScalesFactory.getUTC());
75          Assertions.assertEquals(-67.359, 3600000 * FastMath.toDegrees(history.getEquinoxNutationCorrection(t0)[0]), 1.0e-10);
76          Assertions.assertEquals(-11.755, 3600000 * FastMath.toDegrees(history.getEquinoxNutationCorrection(t0)[1]), 1.0e-10);
77          Assertions.assertEquals(-0.016455, 3600 * FastMath.toDegrees(history.getPoleCorrection(t0).getXp()), 1.0e-10);
78          Assertions.assertEquals(0.401976, 3600 * FastMath.toDegrees(history.getPoleCorrection(t0).getYp()), 1.0e-10);
79          Assertions.assertEquals(-0.2772868, history.getUT1MinusUTC(t0), 1.0e-10);
80          Assertions.assertEquals(EopDataType.FINAL, history.getEopDataType(t0));
81  
82          // after 2011-05-31, the example daily file has no columns for Bulletin B data
83          // we don't see anything since we fall back to bulletin A
84          AbsoluteDate t1Inf = new AbsoluteDate(2011, 6, 1, TimeScalesFactory.getUTC());
85          Assertions.assertEquals(-67.724, 3600000 * FastMath.toDegrees(history.getEquinoxNutationCorrection(t1Inf)[0]), 1.0e-10);
86          Assertions.assertEquals(-11.807, 3600000 * FastMath.toDegrees(history.getEquinoxNutationCorrection(t1Inf)[1]), 1.0e-10);
87          Assertions.assertEquals(-0.015313, 3600 * FastMath.toDegrees(history.getPoleCorrection(t1Inf).getXp()), 1.0e-10);
88          Assertions.assertEquals(0.403214, 3600 * FastMath.toDegrees(history.getPoleCorrection(t1Inf).getYp()), 1.0e-10);
89          Assertions.assertEquals(-0.2778790, history.getUT1MinusUTC(t1Inf), 1.0e-10);
90          Assertions.assertEquals(0.5773, 1000 * history.getLOD(t1Inf), 1.0e-10);
91          Assertions.assertEquals(EopDataType.RAPID, history.getEopDataType(t1Inf));
92          AbsoluteDate t1Sup = t1Inf.shiftedBy(Constants.JULIAN_DAY);
93          Assertions.assertEquals(-67.800, 3600000 * FastMath.toDegrees(history.getEquinoxNutationCorrection(t1Sup)[0]), 1.0e-10);
94          Assertions.assertEquals(-11.810, 3600000 * FastMath.toDegrees(history.getEquinoxNutationCorrection(t1Sup)[1]), 1.0e-10);
95          Assertions.assertEquals(-0.2784173, history.getUT1MinusUTC(t1Sup), 1.0e-10);
96          Assertions.assertEquals(0.5055, 1000 * history.getLOD(t1Sup), 1.0e-10);
97  
98          // after 2011-07-06, the example daily file has no columns for LOD, but it is interpolated
99          AbsoluteDate t2Inf = new AbsoluteDate(2011, 7, 6, TimeScalesFactory.getUTC());
100         Assertions.assertEquals(-72.717, 3600000 * FastMath.toDegrees(history.getEquinoxNutationCorrection(t2Inf)[0]), 1.0e-10);
101         Assertions.assertEquals(-10.620, 3600000 * FastMath.toDegrees(history.getEquinoxNutationCorrection(t2Inf)[1]), 1.0e-10);
102         Assertions.assertEquals(-0.2915826, history.getUT1MinusUTC(t2Inf), 1.0e-10);
103         Assertions.assertEquals(0.5020, 1000 * history.getLOD(t2Inf), 1.0e-10);
104         Assertions.assertEquals(EopDataType.RAPID, history.getEopDataType(t2Inf));
105         AbsoluteDate t2Sup = t2Inf.shiftedBy(Constants.JULIAN_DAY);
106         Assertions.assertEquals(-73.194, 3600000 * FastMath.toDegrees(history.getEquinoxNutationCorrection(t2Sup)[0]), 1.0e-10);
107         Assertions.assertEquals(-10.535, 3600000 * FastMath.toDegrees(history.getEquinoxNutationCorrection(t2Sup)[1]), 1.0e-10);
108         Assertions.assertEquals(-0.2920866, history.getUT1MinusUTC(t2Sup), 1.0e-10);
109         Assertions.assertEquals(5.3509e-6, 1000 * history.getLOD(t2Sup), 1.0e-10);
110 
111         // after 2011-09-19, the example daily file has no columns for nutation
112         AbsoluteDate t3Inf = new AbsoluteDate(2011, 9, 19, TimeScalesFactory.getUTC());
113         Assertions.assertEquals(-79.889, 3600000 * FastMath.toDegrees(history.getEquinoxNutationCorrection(t3Inf)[0]), 1.0e-10);
114         Assertions.assertEquals(-11.125, 3600000 * FastMath.toDegrees(history.getEquinoxNutationCorrection(t3Inf)[1]), 1.0e-10);
115         Assertions.assertEquals(-0.3112849, history.getUT1MinusUTC(t3Inf), 1.0e-10);
116         Assertions.assertEquals(3.2137e-6, 1000 * history.getLOD(t3Inf), 1.0e-10);
117         Assertions.assertEquals(EopDataType.PREDICTED, history.getEopDataType(t3Inf));
118         AbsoluteDate t3Sup = t3Inf.shiftedBy(Constants.JULIAN_DAY);
119         Assertions.assertEquals(0.0, 3600000 * FastMath.toDegrees(history.getEquinoxNutationCorrection(t3Sup)[0]), 1.0e-10);
120         Assertions.assertEquals(0.0, 3600000 * FastMath.toDegrees(history.getEquinoxNutationCorrection(t3Sup)[1]), 1.0e-10);
121         Assertions.assertEquals(-0.3115675, history.getUT1MinusUTC(t3Sup), 1.0e-10);
122         Assertions.assertEquals(3.4186e-6, 1000 * history.getLOD(t3Sup), 1.0e-10);
123     }
124 
125     @Test
126     public void testMissingColumnsPadding2000() {
127         setRoot("rapid-data-columns");
128         IERSConventions.NutationCorrectionConverter converter = IERSConventions.IERS_2003.getNutationCorrectionConverter();
129         SortedSet<EOPEntry> data = new TreeSet<EOPEntry>(new ChronologicalComparator());
130         new RapidDataAndPredictionColumnsLoader(true, "^finals2000A\\.daily$", manager, () -> utc).fillHistory(converter, data);
131         EOPHistory history = new EOPHistory(IERSConventions.IERS_2003, EOPHistory.DEFAULT_INTERPOLATION_DEGREE, data, true);
132 
133         // check parsing for Bulletin B data
134         AbsoluteDate t0 = new AbsoluteDate(2011, 5, 31, TimeScalesFactory.getUTC());
135         Assertions.assertEquals(-0.211, 3600000 * FastMath.toDegrees(history.getNonRotatinOriginNutationCorrection(t0)[0]), 1.0e-10);
136         Assertions.assertEquals(-0.171, 3600000 * FastMath.toDegrees(history.getNonRotatinOriginNutationCorrection(t0)[1]), 1.0e-10);
137         Assertions.assertEquals(-0.016455, 3600 * FastMath.toDegrees(history.getPoleCorrection(t0).getXp()), 1.0e-10);
138         Assertions.assertEquals(0.401976, 3600 * FastMath.toDegrees(history.getPoleCorrection(t0).getYp()), 1.0e-10);
139         Assertions.assertEquals(-0.2772868, history.getUT1MinusUTC(t0), 1.0e-10);
140         Assertions.assertEquals(EopDataType.FINAL, history.getEopDataType(t0));
141 
142         // after 2011-05-31, the example daily file has no columns for Bulletin B data
143         // we don't see anything since we fall back to bulletin A
144         AbsoluteDate t1Inf = new AbsoluteDate(2011, 6, 1, TimeScalesFactory.getUTC());
145         Assertions.assertEquals(-0.279, 3600000 * FastMath.toDegrees(history.getNonRotatinOriginNutationCorrection(t1Inf)[0]), 1.0e-10);
146         Assertions.assertEquals(-0.125, 3600000 * FastMath.toDegrees(history.getNonRotatinOriginNutationCorrection(t1Inf)[1]), 1.0e-10);
147         Assertions.assertEquals(-0.015313, 3600 * FastMath.toDegrees(history.getPoleCorrection(t1Inf).getXp()), 1.0e-10);
148         Assertions.assertEquals(0.403214, 3600 * FastMath.toDegrees(history.getPoleCorrection(t1Inf).getYp()), 1.0e-10);
149         Assertions.assertEquals(-0.2778790, history.getUT1MinusUTC(t1Inf), 1.0e-10);
150         Assertions.assertEquals(0.5773, 1000 * history.getLOD(t1Inf), 1.0e-10);
151         Assertions.assertEquals(EopDataType.RAPID, history.getEopDataType(t1Inf));
152         AbsoluteDate t1Sup = t1Inf.shiftedBy(Constants.JULIAN_DAY);
153         Assertions.assertEquals(-0.014222, 3600 * FastMath.toDegrees(history.getPoleCorrection(t1Sup).getXp()), 1.0e-10);
154         Assertions.assertEquals(0.404430, 3600 * FastMath.toDegrees(history.getPoleCorrection(t1Sup).getYp()), 1.0e-10);
155         Assertions.assertEquals(-0.2784173, history.getUT1MinusUTC(t1Sup), 1.0e-10);
156         Assertions.assertEquals(0.5055, 1000 * history.getLOD(t1Sup), 1.0e-10);
157 
158         // after 2011-07-06, the example daily file has no columns for LOD, but it is interpolated
159         AbsoluteDate t2Inf = new AbsoluteDate(2011, 7, 6, TimeScalesFactory.getUTC());
160         Assertions.assertEquals(0.052605, 3600 * FastMath.toDegrees(history.getPoleCorrection(t2Inf).getXp()), 1.0e-10);
161         Assertions.assertEquals(0.440076, 3600 * FastMath.toDegrees(history.getPoleCorrection(t2Inf).getYp()), 1.0e-10);
162         Assertions.assertEquals(-0.2915826, history.getUT1MinusUTC(t2Inf), 1.0e-10);
163         Assertions.assertEquals(0.5020, 1000 * history.getLOD(t2Inf), 1.0e-10);
164         Assertions.assertEquals(EopDataType.RAPID, history.getEopDataType(t2Inf));
165         AbsoluteDate t2Sup = t2Inf.shiftedBy(Constants.JULIAN_DAY);
166         Assertions.assertEquals(0.055115, 3600 * FastMath.toDegrees(history.getPoleCorrection(t2Sup).getXp()), 1.0e-10);
167         Assertions.assertEquals(0.440848, 3600 * FastMath.toDegrees(history.getPoleCorrection(t2Sup).getYp()), 1.0e-10);
168         Assertions.assertEquals(-0.2920866, history.getUT1MinusUTC(t2Sup), 1.0e-10);
169         Assertions.assertEquals(5.3509e-6, 1000 * history.getLOD(t2Sup), 1.0e-10);
170 
171         // after 2011-09-19, the example daily file has no columns for nutation
172         AbsoluteDate t3Inf = new AbsoluteDate(2011, 9, 19, TimeScalesFactory.getUTC());
173         Assertions.assertEquals(-0.437, 3600000 * FastMath.toDegrees(history.getNonRotatinOriginNutationCorrection(t3Inf)[0]), 1.0e-10);
174         Assertions.assertEquals(0.010, 3600000 * FastMath.toDegrees(history.getNonRotatinOriginNutationCorrection(t3Inf)[1]), 1.0e-10);
175         Assertions.assertEquals(-0.3112849, history.getUT1MinusUTC(t3Inf), 1.0e-10);
176         Assertions.assertEquals(3.2137e-6, 1000 * history.getLOD(t3Inf), 1.0e-10);
177         Assertions.assertEquals(EopDataType.PREDICTED, history.getEopDataType(t3Inf));
178     }
179 
180     @Test
181     public void testEndDateDaily2000() {
182         setRoot("rapid-data-columns");
183         IERSConventions.NutationCorrectionConverter converter = IERSConventions.IERS_2003.getNutationCorrectionConverter();
184         SortedSet<EOPEntry> history = new TreeSet<EOPEntry>(new ChronologicalComparator());
185         new RapidDataAndPredictionColumnsLoader(true, "^finals2000A\\.daily$", manager, () -> utc).fillHistory(converter, history);
186         Assertions.assertEquals(new AbsoluteDate(2011, 10, 6, TimeScalesFactory.getUTC()),
187                                 new EOPHistory(IERSConventions.IERS_2003, EOPHistory.DEFAULT_INTERPOLATION_DEGREE, history, true).getEndDate());
188     }
189 
190     @Test
191     public void testNoColumns() {
192         setRoot("rapid-data-columns");
193         IERSConventions.NutationCorrectionConverter converter = IERSConventions.IERS_2010.getNutationCorrectionConverter();
194         SortedSet<EOPEntry> history = new TreeSet<EOPEntry>(new ChronologicalComparator());
195         new RapidDataAndPredictionColumnsLoader(true, "^finals2000A-no-columns\\.daily$", manager, () -> utc).fillHistory(converter, history);
196         EOPHistory eopH = new EOPHistory(IERSConventions.IERS_2010, EOPHistory.DEFAULT_INTERPOLATION_DEGREE, history, true);
197         Assertions.assertEquals(new AbsoluteDate(2011, 4, 16, TimeScalesFactory.getUTC()), eopH.getEndDate());
198         AbsoluteDate testDate = eopH.getEndDate().shiftedBy(-2 * Constants.JULIAN_DAY);
199         Assertions.assertEquals(0.0, eopH.getPoleCorrection(testDate).getXp(), 1.0e-15);
200         Assertions.assertEquals(0.0, eopH.getPoleCorrection(testDate).getYp(), 1.0e-15);
201         Assertions.assertEquals(0.0, eopH.getUT1MinusUTC(testDate), 1.0e-15);
202         Assertions.assertEquals(0.0, eopH.getLOD(testDate), 1.0e-15);
203         Assertions.assertEquals(0.0, eopH.getNonRotatinOriginNutationCorrection(testDate)[0], 1.0e-15);
204         Assertions.assertEquals(0.0, eopH.getNonRotatinOriginNutationCorrection(testDate)[1], 1.0e-15);
205     }
206 
207     @Test
208     public void testPost2070() {
209         setRoot("rapid-data-columns");
210         IERSConventions.NutationCorrectionConverter converter = IERSConventions.IERS_2010.getNutationCorrectionConverter();
211         SortedSet<EOPEntry> history = new TreeSet<EOPEntry>(new ChronologicalComparator());
212         new RapidDataAndPredictionColumnsLoader(true, "^finals2000A-post-2070\\.daily$", manager, () -> utc).fillHistory(converter, history);
213         Assertions.assertEquals(new AbsoluteDate(2075, 4, 16, TimeScalesFactory.getUTC()),
214                                 new EOPHistory(IERSConventions.IERS_2010, EOPHistory.DEFAULT_INTERPOLATION_DEGREE, history, true).getEndDate());
215     }
216 
217     @Test
218     public void testTruncatedLine() {
219         doTestWrongFile("^finals2000A-truncated-line\\.daily$", 3);
220     }
221 
222     @Test
223     public void testWrongDateFormat() {
224         doTestWrongFile("^finals2000A-wrong-date-format\\.daily$", 3);
225     }
226 
227     @Test
228     public void testWrongYear() {
229         doTestWrongFile("^finals2000A-wrong-year\\.daily$", 6);
230     }
231 
232     @Test
233     public void testWrongMonth() {
234         doTestWrongFile("^finals2000A-wrong-month\\.daily$", 5);
235     }
236 
237     @Test
238     public void testWrongDay() {
239         doTestWrongFile("^finals2000A-wrong-day\\.daily$", 4);
240     }
241 
242     @Test
243     public void testWrongPoleAFormat() {
244         doTestWrongFile("^finals2000A-wrong-pole-A-format\\.daily$", 7);
245     }
246 
247     @Test
248     public void testWrongPoleBFormat() {
249         doTestWrongFile("^finals2000A-wrong-pole-B-format\\.daily$", 7);
250     }
251 
252     @Test
253     public void testWrongUT1UTCAFormat() {
254         doTestWrongFile("^finals2000A-wrong-ut1-utc-A-format\\.daily$", 7);
255     }
256 
257     @Test
258     public void testWrongUT1UTCBFormat() {
259         doTestWrongFile("^finals2000A-wrong-ut1-utc-B-format\\.daily$", 7);
260     }
261 
262     @Test
263     public void testWrongLODAFormat() {
264         doTestWrongFile("^finals2000A-wrong-lod-A-format\\.daily$", 7);
265     }
266 
267     @Test
268     public void testWrongNutationAFormat() {
269         doTestWrongFile("^finals2000A-wrong-nutation-A-format\\.daily$", 7);
270     }
271 
272     @Test
273     public void testWrongNutationBFormat() {
274         doTestWrongFile("^finals2000A-wrong-nutation-B-format\\.daily$", 7);
275     }
276 
277     @Test
278     public void testWrongEopDataType() {
279         doTestWrongFile("^finals-wrong-eop-data-type\\.daily$", 4);
280     }
281 
282     private void doTestWrongFile(String fileName, int lineNumber) {
283         setRoot("rapid-data-columns");
284         IERSConventions.NutationCorrectionConverter converter = IERSConventions.IERS_2010.getNutationCorrectionConverter();
285         SortedSet<EOPEntry> history = new TreeSet<EOPEntry>(new ChronologicalComparator());
286         try {
287             new RapidDataAndPredictionColumnsLoader(true, fileName, manager, () -> utc).fillHistory(converter, history);
288             Assertions.fail("an exception should have been thrown");
289         }
290         catch (OrekitException oe) {
291             Assertions.assertEquals(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE, oe.getSpecifier());
292             Assertions.assertEquals(lineNumber, ((Integer) oe.getParts()[0]).intValue());
293         }
294     }
295 }