1   /* Copyright 2002-2022 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.time;
18  
19  
20  import java.io.ByteArrayInputStream;
21  import java.io.ByteArrayOutputStream;
22  import java.io.IOException;
23  import java.io.ObjectInputStream;
24  import java.io.ObjectOutputStream;
25  import java.util.ArrayList;
26  import java.util.List;
27  import java.util.concurrent.Callable;
28  import java.util.concurrent.ExecutionException;
29  import java.util.concurrent.Executors;
30  import java.util.concurrent.Future;
31  
32  import org.junit.After;
33  import org.junit.Assert;
34  import org.junit.Before;
35  import org.junit.Test;
36  import org.orekit.Utils;
37  import org.orekit.frames.EOPHistory;
38  import org.orekit.frames.ITRFVersion;
39  import org.orekit.utils.Constants;
40  import org.orekit.utils.IERSConventions;
41  
42  public class UT1ScaleTest {
43  
44      @Test
45      public void testLeap2006() {
46          TimeScale utc = TimeScalesFactory.getUTC();
47          AbsoluteDate dateA = new AbsoluteDate(2005, 12, 30, 23, 59,  0.0, utc);
48          AbsoluteDate dateB = new AbsoluteDate(2006,  1,  2,  0,  1,  0.0, utc);
49          double deltaAUT1 = ut1.offsetFromTAI(dateA);
50          double deltaAUTC = utc.offsetFromTAI(dateA);
51          double deltaBUT1 = ut1.offsetFromTAI(dateB);
52          double deltaBUTC = utc.offsetFromTAI(dateB);
53  
54          // there is a leap second between the two dates
55          Assert.assertEquals(deltaAUTC - 1.0, deltaBUTC, 1.0e-15);
56  
57          // the leap second induces UTC goes from above UT1 to below UT1
58          Assert.assertTrue(deltaAUTC > deltaAUT1);
59          Assert.assertTrue(deltaBUTC < deltaBUT1);
60  
61          // UT1 is continuous, so change should be very small in two days
62          Assert.assertEquals(deltaAUT1, deltaBUT1, 3.0e-4);
63  
64      }
65  
66      /** Issue #636 */
67      @Test
68      public void testContinuousDuringLeap() {
69          // setup
70          TimeScale utc = TimeScalesFactory.getUTC();
71          AbsoluteDate dateA = new AbsoluteDate(2005, 12, 31, 23, 59, 0.0, utc);
72          AbsoluteDate dateB = new AbsoluteDate(2006, 1, 1, 0, 1, 0.0, utc);
73          EOPHistory eopHistory = ut1.getEOPHistory();
74  
75          // verify
76          // there is a leap second and jump in UT1-UTC
77          Assert.assertEquals(eopHistory.getUT1MinusUTC(new AbsoluteDate(2005, 12, 31, utc)), -0.6611333, 0);
78          Assert.assertEquals(eopHistory.getUT1MinusUTC(new AbsoluteDate(2006, 1, 1, utc)), 0.338829, 1e-16);
79  
80          // check UT1-TAI is still smooth
81          double dt = 0.5;
82          double tol = 0.001 * dt / Constants.JULIAN_DAY;
83          double previous = ut1.offsetFromTAI(dateA.shiftedBy(-dt));
84          for (AbsoluteDate d = dateA; d.compareTo(dateB) < 0; d = d.shiftedBy(dt)) {
85              double actual = ut1.offsetFromTAI(d);
86              Assert.assertEquals("at " + d.toString(utc), 0, actual - previous, tol);
87              previous = actual;
88          }
89      }
90  
91      @Test
92      public void testSymmetry() {
93          for (double dt = -10000; dt < 10000; dt += 123.456789) {
94              AbsoluteDate date = AbsoluteDate.J2000_EPOCH.shiftedBy(dt * Constants.JULIAN_DAY);
95              double dt1 = ut1.offsetFromTAI(date);
96              DateTimeComponents components = date.getComponents(ut1);
97              double dt2 = ut1.offsetToTAI(components.getDate(), components.getTime());
98              Assert.assertEquals( 0.0, dt1 + dt2, 1.0e-10);
99          }
100     }
101 
102     @Test
103     public void testConcurrent() throws InterruptedException, ExecutionException {
104         // set up
105         final AbsoluteDate date = AbsoluteDate.J2000_EPOCH;
106         final int threads = 10;
107         final int timesPerThread = 100;
108         final double dt = 123.456789 * Constants.JULIAN_DAY;
109 
110         // calculate expected values in single-thread mode
111         final double[] expected = new double[timesPerThread];
112         for (int i = 0; i < timesPerThread; i++) {
113             expected[i] = ut1.offsetFromTAI(date.shiftedBy(i * dt));
114         }
115 
116         // build jobs for concurrent execution
117         final List<Callable<Boolean>> jobs = new ArrayList<Callable<Boolean>>();
118         for (int i = 0; i < threads; i++) {
119             jobs.add(new Callable<Boolean>() {
120                 public Boolean call() throws Exception {
121                     for (int j = 0; j < timesPerThread; j++) {
122                         final double actual = ut1.offsetFromTAI(date.shiftedBy(j * dt));
123                         Assert.assertEquals(expected[j], actual, 0);
124                     }
125                     return true;
126                 }
127             });
128         }
129 
130         // action
131         final List<Future<Boolean>> futures = Executors.newFixedThreadPool(threads).invokeAll(jobs);
132 
133         // verify - necessary to throw AssertionErrors from the Callable
134         for (Future<Boolean> future : futures) {
135             Assert.assertEquals(true, future.get());
136         }
137     }
138 
139     @Test
140     public void testAAS06134() {
141 
142         // this reference test has been extracted from the following paper:
143         // Implementation Issues Surrounding the New IAU Reference Systems for Astrodynamics
144         // David A. Vallado, John H. Seago, P. Kenneth Seidelmann
145         // http://www.centerforspace.com/downloads/files/pubs/AAS-06-134.pdf
146         // Note that the dUT1 here is -0.439962, whereas it is -0.4399619 in the book
147         Utils.setLoaders(IERSConventions.IERS_1996,
148                          Utils.buildEOPList(IERSConventions.IERS_1996, ITRFVersion.ITRF_2008, new double[][] {
149                              { 53098, -0.439962, 0.0015563, -0.140682, 0.333309, -0.052195, -0.003875, Double.NaN, Double.NaN },
150                              { 53099, -0.439962, 0.0015563, -0.140682, 0.333309, -0.052195, -0.003875, Double.NaN, Double.NaN },
151                              { 53100, -0.439962, 0.0015563, -0.140682, 0.333309, -0.052195, -0.003875, Double.NaN, Double.NaN },
152                              { 53101, -0.439962, 0.0015563, -0.140682, 0.333309, -0.052195, -0.003875, Double.NaN, Double.NaN },
153                              { 53102, -0.439962, 0.0015563, -0.140682, 0.333309, -0.052195, -0.003875, Double.NaN, Double.NaN },
154                              { 53103, -0.439962, 0.0015563, -0.140682, 0.333309, -0.052195, -0.003875, Double.NaN, Double.NaN },
155                              { 53104, -0.439962, 0.0015563, -0.140682, 0.333309, -0.052195, -0.003875, Double.NaN, Double.NaN },
156                              { 53105, -0.439962, 0.0015563, -0.140682, 0.333309, -0.052195, -0.003875, Double.NaN, Double.NaN }
157                          }));
158         AbsoluteDate date =
159                 new AbsoluteDate(2004, 4, 6, 7, 51, 28.386009, TimeScalesFactory.getUTC());
160         DateTimeComponents components = date.getComponents(TimeScalesFactory.getUT1(IERSConventions.IERS_1996, true));
161         Assert.assertEquals(2004,        components.getDate().getYear());
162         Assert.assertEquals(   4,        components.getDate().getMonth());
163         Assert.assertEquals(   6,        components.getDate().getDay());
164         Assert.assertEquals(   7,        components.getTime().getHour());
165         Assert.assertEquals(  51,        components.getTime().getMinute());
166         Assert.assertEquals(  27.946047, components.getTime().getSecond(), 1.0e-10);
167     }
168 
169     @Test
170     public void testSerialization() throws IOException, ClassNotFoundException {
171         UT1Scale ut1 = TimeScalesFactory.getUT1(IERSConventions.IERS_2010, true);
172 
173         ByteArrayOutputStream bos = new ByteArrayOutputStream();
174         ObjectOutputStream    oos = new ObjectOutputStream(bos);
175         oos.writeObject(ut1);
176 
177         Assert.assertTrue(bos.size() > 145000);
178         Assert.assertTrue(bos.size() < 155000);
179 
180         ByteArrayInputStream  bis = new ByteArrayInputStream(bos.toByteArray());
181         ObjectInputStream     ois = new ObjectInputStream(bis);
182         UT1Scale deserialized  = (UT1Scale) ois.readObject();
183         for (double dt = 0; dt < 7 * Constants.JULIAN_DAY; dt += 3600) {
184             AbsoluteDate date = ut1.getEOPHistory().getStartDate().shiftedBy(dt);
185             Assert.assertEquals(ut1.offsetFromTAI(date), deserialized.offsetFromTAI(date), 1.0e-15);
186         }
187 
188     }
189 
190     @Test
191     public void testDuringLeap() {
192         final TimeScale utc   = TimeScalesFactory.getUTC();
193         final TimeScale scale = TimeScalesFactory.getUT1(IERSConventions.IERS_2010, true);
194         final AbsoluteDate before = new AbsoluteDate(new DateComponents(1983, 06, 30),
195                                                      new TimeComponents(23, 59, 59),
196                                                      utc);
197         final AbsoluteDate during = before.shiftedBy(1.25);
198         Assert.assertEquals(61, utc.minuteDuration(during));
199         Assert.assertEquals(1.0, utc.getLeap(during), 1.0e-10);
200         Assert.assertEquals(60, scale.minuteDuration(during));
201         Assert.assertEquals(0.0, scale.getLeap(during), 1.0e-10);
202     }
203 
204     @Before
205     public void setUp() {
206         Utils.setDataRoot("regular-data");
207         ut1 = TimeScalesFactory.getUT1(IERSConventions.IERS_2010, true);
208     }
209 
210     @After
211     public void tearDown() {
212         ut1 = null;
213     }
214 
215     private UT1Scale ut1;
216 
217 }