Commit 0799a0ed authored by Luc Maisonobe's avatar Luc Maisonobe
Browse files

Merge branch 'issue-737' into develop

parents 46cc7802 525d4d2a
Pipeline #778 passed with stages
in 28 minutes and 25 seconds
......@@ -21,6 +21,9 @@
</properties>
<body>
<release version="10.3" date="TBD" description="TBD">
<action dev="luc" type="add" issue="737">
Added loading of AGI LeapSecond.dat files.
</action>
<action dev="raphael" type="add" issue="686">
Allowed user-defined format for ephemeris data lines in
StreamingAemWriter, AEMWriter, StreamingOemWriter and OEMWriter.
......
/* Copyright 2002-2020 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.time;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.hipparchus.util.FastMath;
import org.orekit.annotation.DefaultDataContext;
import org.orekit.data.AbstractSelfFeedingLoader;
import org.orekit.data.DataContext;
import org.orekit.data.DataProvidersManager;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitMessages;
/** Loader for UTC-TAI extracted from LeapSecond file from AGI.
* <p>
* This class is immutable and hence thread-safe
* </p>
* @see <a href="ftp://ftp.agi.com/pub/STKData/Astro/LeapSecond.dat">LeapSecond.dat</a>
* @author Luc Maisonobe
* @since 10.3
*/
public class AGILeapSecondFilesLoader extends AbstractSelfFeedingLoader
implements UTCTAIOffsetsLoader {
/** Default supported files name pattern. */
public static final String DEFAULT_SUPPORTED_NAMES = "^LeapSecond\\.dat$";
/**
* Build a loader for LeapSecond.dat file from AGI. This constructor uses the {@link
* DataContext#getDefault() default data context}.
*
* @param supportedNames regular expression for supported files names
* @see #TAIUTCDatFilesLoader(String, DataProvidersManager)
*/
@DefaultDataContext
public AGILeapSecondFilesLoader(final String supportedNames) {
this(supportedNames, DataContext.getDefault().getDataProvidersManager());
}
/**
* Build a loader for LeapSecond.dat file from AGI.
*
* @param supportedNames regular expression for supported files names
* @param manager provides access to the {@code tai-utc.dat} file.
*/
public AGILeapSecondFilesLoader(final String supportedNames,
final DataProvidersManager manager) {
super(supportedNames, manager);
}
/** {@inheritDoc} */
@Override
public List<OffsetModel> loadOffsets() {
final UtcTaiOffsetLoader parser = new UtcTaiOffsetLoader(new Parser());
this.feed(parser);
return parser.getOffsets();
}
/** Internal class performing the parsing. */
public static class Parser implements UTCTAIOffsetsLoader.Parser {
/** Regular expression for optional blanks. */
private static final String BLANKS = "\\p{Blank}*";
/** Regular expression for storage start. */
private static final String STORAGE_START = "(";
/** Regular expression for storage end. */
private static final String STORAGE_END = ")";
/** Regular expression for alternative. */
private static final String ALTERNATIVE = "|";
/** Regular expression matching blanks at start of line. */
private static final String LINE_START_REGEXP = "^" + BLANKS;
/** Regular expression matching blanks at end of line. */
private static final String LINE_END_REGEXP = BLANKS + "$";
/** Regular expression matching integers. */
private static final String INTEGER_REGEXP = "[-+]?\\p{Digit}+";
/** Regular expression matching real numbers. */
private static final String REAL_REGEXP = "[-+]?(?:(?:\\p{Digit}+(?:\\.\\p{Digit}*)?)|(?:\\.\\p{Digit}+))(?:[eE][-+]?\\p{Digit}+)?";
/** Regular expression matching an integer field to store. */
private static final String STORED_INTEGER_FIELD = BLANKS + STORAGE_START + INTEGER_REGEXP + STORAGE_END;
/** Regular expression matching a real field to store. */
private static final String STORED_REAL_FIELD = BLANKS + STORAGE_START + REAL_REGEXP + STORAGE_END;
/** Data lines pattern. */
private Pattern dataPattern;
/** Simple constructor.
*/
public Parser() {
// data lines read:
// 28
// 1972 JAN 1 2441317.5 10.0 41317. 0.0
// 1972 JUL 1 2441499.5 11.0 41317. 0.0
// 1973 JAN 1 2441683.5 12.0 41317. 0.0
// 1974 JAN 1 2442048.5 13.0 41317. 0.0
// 1975 JAN 1 2442413.5 14.0 41317. 0.0
// 1976 JAN 1 2442778.5 15.0 41317. 0.0
// 1977 JAN 1 2443144.5 16.0 41317. 0.0
// 1978 JAN 1 2443509.5 17.0 41317. 0.0
// month as a three letters upper case abbreviation
final StringBuilder builder = new StringBuilder(BLANKS + STORAGE_START);
for (final Month month : Month.values()) {
builder.append(month.getUpperCaseAbbreviation());
builder.append(ALTERNATIVE);
}
builder.delete(builder.length() - 1, builder.length());
builder.append(STORAGE_END);
final String monthField = builder.toString();
dataPattern = Pattern.compile(LINE_START_REGEXP +
STORED_INTEGER_FIELD + monthField + STORED_INTEGER_FIELD +
BLANKS + STORED_REAL_FIELD +
BLANKS + STORED_REAL_FIELD +
BLANKS + STORED_REAL_FIELD +
BLANKS + STORED_REAL_FIELD +
LINE_END_REGEXP);
}
/** Load UTC-TAI offsets entries read from some file.
* <p>The time steps are extracted from some {@code LeapSecond.dat} file.
* Since entries are stored in a {@link java.util.SortedMap SortedMap},
* they are chronologically sorted and only one entry remains for a given date.</p>
* @param input data input stream
* @param name name of the file (or zip entry)
* @exception IOException if data can't be read
*/
@Override
public List<OffsetModel> parse(final InputStream input, final String name)
throws IOException {
final List<OffsetModel> offsets = new ArrayList<>();
int lineNumber = 0;
DateComponents lastDate = null;
String line = null;
// set up a reader for line-oriented file
try (BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8))) {
// read all file, ignoring not recognized lines
for (line = reader.readLine(); line != null; line = reader.readLine()) {
++lineNumber;
// check matching for data lines
final Matcher matcher = dataPattern.matcher(line);
if (matcher.matches()) {
// build an entry from the extracted fields
final DateComponents dc1 = new DateComponents(Integer.parseInt(matcher.group(1)),
Month.parseMonth(matcher.group(2)),
Integer.parseInt(matcher.group(3)));
final DateComponents dc2 = new DateComponents(DateComponents.JULIAN_EPOCH,
(int) FastMath.ceil(Double.parseDouble(matcher.group(4))));
if (!dc1.equals(dc2)) {
throw new OrekitException(OrekitMessages.INCONSISTENT_DATES_IN_IERS_FILE,
name, dc1.getYear(), dc1.getMonth(), dc1.getDay(), dc2.getMJD());
}
if ((lastDate != null) && dc1.compareTo(lastDate) <= 0) {
throw new OrekitException(OrekitMessages.NON_CHRONOLOGICAL_DATES_IN_FILE,
name, lineNumber);
}
lastDate = dc1;
final double offset = Double.parseDouble(matcher.group(5));
final double mjdRef = Double.parseDouble(matcher.group(6));
final double slope = Double.parseDouble(matcher.group(7));
offsets.add(new OffsetModel(dc1, (int) FastMath.rint(mjdRef), offset, slope));
}
}
} catch (NumberFormatException nfe) {
throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
lineNumber, name, line);
}
if (offsets.isEmpty()) {
throw new OrekitException(OrekitMessages.NO_ENTRIES_IN_IERS_UTC_TAI_HISTORY_FILE, name);
}
return offsets;
}
}
}
/* Copyright 2002-2020 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.time;
import org.junit.Assert;
import org.junit.Test;
import org.orekit.Utils;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitMessages;
public class AGILeapSecondFilesLoaderTest {
@Test
public void testRegularFile() {
Utils.setDataRoot("AGI");
TimeScalesFactory.addUTCTAIOffsetsLoader(new AGILeapSecondFilesLoader(AGILeapSecondFilesLoader.DEFAULT_SUPPORTED_NAMES));
// we arbitrary put UTC == TAI before 1961-01-01
checkOffset(1950, 1, 1, 0);
// linear models between 1961 and 1972
checkOffset(1961, 1, 2, -(1.422818 + 1 * 0.001296)); // MJD 37300 + 1
checkOffset(1961, 8, 2, -(1.372818 + 213 * 0.001296)); // MJD 37300 + 213
checkOffset(1962, 1, 2, -(1.845858 + 1 * 0.0011232)); // MJD 37665 + 1
checkOffset(1963, 11, 2, -(1.945858 + 670 * 0.0011232)); // MJD 37665 + 670
checkOffset(1964, 1, 2, -(3.240130 - 365 * 0.001296)); // MJD 38761 - 365
checkOffset(1964, 4, 2, -(3.340130 - 274 * 0.001296)); // MJD 38761 - 274
checkOffset(1964, 9, 2, -(3.440130 - 121 * 0.001296)); // MJD 38761 - 121
checkOffset(1965, 1, 2, -(3.540130 + 1 * 0.001296)); // MJD 38761 + 1
checkOffset(1965, 3, 2, -(3.640130 + 60 * 0.001296)); // MJD 38761 + 60
checkOffset(1965, 7, 2, -(3.740130 + 182 * 0.001296)); // MJD 38761 + 182
checkOffset(1965, 9, 2, -(3.840130 + 244 * 0.001296)); // MJD 38761 + 244
checkOffset(1966, 1, 2, -(4.313170 + 1 * 0.002592)); // MJD 39126 + 1
checkOffset(1968, 2, 2, -(4.213170 + 762 * 0.002592)); // MJD 39126 + 762
// since 1972-01-01, offsets are only whole seconds
checkOffset(1972, 3, 5, -10);
checkOffset(1972, 7, 14, -11);
checkOffset(1979, 12, 31, -18);
checkOffset(1980, 1, 22, -19);
checkOffset(2006, 7, 7, -33);
checkOffset(2010, 7, 7, -34);
checkOffset(2012, 7, 7, -35);
checkOffset(2015, 7, 7, -36);
}
@Test
public void testInconsistentDate() {
checkException("LeapSecond-inconsistent-date.dat",
OrekitMessages.INCONSISTENT_DATES_IN_IERS_FILE);
}
@Test
public void testNonChronological() {
checkException("LeapSecond-non-chronological.dat",
OrekitMessages.NON_CHRONOLOGICAL_DATES_IN_FILE);
}
@Test
public void testFormatError() {
checkException("LeapSecond-format-error.dat",
OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE);
}
private void checkOffset(int year, int month, int day, double offset) {
TimeScale utc = TimeScalesFactory.getUTC();
AbsoluteDate date = new AbsoluteDate(year, month, day, utc);
Assert.assertEquals(offset, utc.offsetFromTAI(date), 1.0e-10);
}
private void checkException(String name, OrekitMessages message) {
Utils.setDataRoot("AGI");
TimeScalesFactory.addUTCTAIOffsetsLoader(new AGILeapSecondFilesLoader(name));
try {
TimeScalesFactory.getUTC();
Assert.fail("an exception should have been thrown");
} catch (OrekitException oe) {
Assert.assertEquals(message, oe.getSpecifier());
}
}
}
28
1972 JAN 1 2441317.5 10.0 41317. 0.0
1972 JUL 1 2441499.5 11.0 41317. 0.0
1973 JAN 1 2441683.5 12.0 41317. 0.0
1974 JAN 1 2442048.5 13.0 41317. 0.0
1975 JAN 1 2442413.5 14.0 41317. 0.0
1976 JAN 1 2442778.5 15.0 41317. 0.0
1977 JAN 1 2443144.5 16.0 41317. 0.0
1978 JAN 1 2443509.5 17.0 41317. 0.0
1979 JAN 1 2443874.5 18.0 41317. 0.0
1980 JAN 1 2444239.5 19.0 41317. 0.0
1981 JUL 99999999999999999999999 2444786.5 20.0 41317. 0.0
1982 JUL 1 2445151.5 21.0 41317. 0.0
1983 JUL 1 2445516.5 22.0 41317. 0.0
1985 JUL 1 2446247.5 23.0 41317. 0.0
1988 JAN 1 2447161.5 24.0 41317. 0.0
1990 JAN 1 2447892.5 25.0 41317. 0.0
1991 JAN 1 2448257.5 26.0 41317. 0.0
1992 JUL 1 2448804.5 27.0 41317. 0.0
1993 JUL 1 2449169.5 28.0 41317. 0.0
1994 JUL 1 2449534.5 29.0 41317. 0.0
1996 JAN 1 2450083.5 30.0 41317. 0.0
1997 JUL 1 2450630.5 31.0 41317. 0.0
1999 JAN 1 2451179.5 32.0 41317. 0.0
2006 JAN 1 2453736.5 33.0 41317. 0.0
2009 JAN 1 2454832.5 34.0 41317. 0.0
2012 JUL 1 2456109.5 35.0 41317. 0.0
2015 JUL 1 2457204.5 36.0 41317. 0.0
2017 JAN 1 2457754.5 37.0 41317. 0.0
28
1972 JAN 1 2441317.5 10.0 41317. 0.0
1972 AUG 1 2441499.5 11.0 41317. 0.0
1973 JAN 1 2441683.5 12.0 41317. 0.0
1974 JAN 1 2442048.5 13.0 41317. 0.0
1975 JAN 1 2442413.5 14.0 41317. 0.0
1976 JAN 1 2442778.5 15.0 41317. 0.0
1977 JAN 1 2443144.5 16.0 41317. 0.0
1978 JAN 1 2443509.5 17.0 41317. 0.0
1979 JAN 1 2443874.5 18.0 41317. 0.0
1980 JAN 1 2444239.5 19.0 41317. 0.0
1981 JUL 1 2444786.5 20.0 41317. 0.0
1982 JUL 1 2445151.5 21.0 41317. 0.0
1983 JUL 1 2445516.5 22.0 41317. 0.0
1985 JUL 1 2446247.5 23.0 41317. 0.0
1988 JAN 1 2447161.5 24.0 41317. 0.0
1990 JAN 1 2447892.5 25.0 41317. 0.0
1991 JAN 1 2448257.5 26.0 41317. 0.0
1992 JUL 1 2448804.5 27.0 41317. 0.0
1993 JUL 1 2449169.5 28.0 41317. 0.0
1994 JUL 1 2449534.5 29.0 41317. 0.0
1996 JAN 1 2450083.5 30.0 41317. 0.0
1997 JUL 1 2450630.5 31.0 41317. 0.0
1999 JAN 1 2451179.5 32.0 41317. 0.0
2006 JAN 1 2453736.5 33.0 41317. 0.0
2009 JAN 1 2454832.5 34.0 41317. 0.0
2012 JUL 1 2456109.5 35.0 41317. 0.0
2015 JUL 1 2457204.5 36.0 41317. 0.0
2017 JAN 1 2457754.5 37.0 41317. 0.0
28
2017 JAN 1 2457754.5 37.0 41317. 0.0
2015 JUL 1 2457204.5 36.0 41317. 0.0
2012 JUL 1 2456109.5 35.0 41317. 0.0
2009 JAN 1 2454832.5 34.0 41317. 0.0
2006 JAN 1 2453736.5 33.0 41317. 0.0
1999 JAN 1 2451179.5 32.0 41317. 0.0
1997 JUL 1 2450630.5 31.0 41317. 0.0
1996 JAN 1 2450083.5 30.0 41317. 0.0
1994 JUL 1 2449534.5 29.0 41317. 0.0
1993 JUL 1 2449169.5 28.0 41317. 0.0
1992 JUL 1 2448804.5 27.0 41317. 0.0
1991 JAN 1 2448257.5 26.0 41317. 0.0
1990 JAN 1 2447892.5 25.0 41317. 0.0
1988 JAN 1 2447161.5 24.0 41317. 0.0
1985 JUL 1 2446247.5 23.0 41317. 0.0
1983 JUL 1 2445516.5 22.0 41317. 0.0
1982 JUL 1 2445151.5 21.0 41317. 0.0
1981 JUL 1 2444786.5 20.0 41317. 0.0
1980 JAN 1 2444239.5 19.0 41317. 0.0
1979 JAN 1 2443874.5 18.0 41317. 0.0
1978 JAN 1 2443509.5 17.0 41317. 0.0
1977 JAN 1 2443144.5 16.0 41317. 0.0
1976 JAN 1 2442778.5 15.0 41317. 0.0
1975 JAN 1 2442413.5 14.0 41317. 0.0
1974 JAN 1 2442048.5 13.0 41317. 0.0
1973 JAN 1 2441683.5 12.0 41317. 0.0
1972 JUL 1 2441499.5 11.0 41317. 0.0
1972 JAN 1 2441317.5 10.0 41317. 0.0
28
1972 JAN 1 2441317.5 10.0 41317. 0.0
1972 JUL 1 2441499.5 11.0 41317. 0.0
1973 JAN 1 2441683.5 12.0 41317. 0.0
1974 JAN 1 2442048.5 13.0 41317. 0.0
1975 JAN 1 2442413.5 14.0 41317. 0.0
1976 JAN 1 2442778.5 15.0 41317. 0.0
1977 JAN 1 2443144.5 16.0 41317. 0.0
1978 JAN 1 2443509.5 17.0 41317. 0.0
1979 JAN 1 2443874.5 18.0 41317. 0.0
1980 JAN 1 2444239.5 19.0 41317. 0.0
1981 JUL 1 2444786.5 20.0 41317. 0.0
1982 JUL 1 2445151.5 21.0 41317. 0.0
1983 JUL 1 2445516.5 22.0 41317. 0.0
1985 JUL 1 2446247.5 23.0 41317. 0.0
1988 JAN 1 2447161.5 24.0 41317. 0.0
1990 JAN 1 2447892.5 25.0 41317. 0.0
1991 JAN 1 2448257.5 26.0 41317. 0.0
1992 JUL 1 2448804.5 27.0 41317. 0.0
1993 JUL 1 2449169.5 28.0 41317. 0.0
1994 JUL 1 2449534.5 29.0 41317. 0.0
1996 JAN 1 2450083.5 30.0 41317. 0.0
1997 JUL 1 2450630.5 31.0 41317. 0.0
1999 JAN 1 2451179.5 32.0 41317. 0.0
2006 JAN 1 2453736.5 33.0 41317. 0.0
2009 JAN 1 2454832.5 34.0 41317. 0.0
2012 JUL 1 2456109.5 35.0 41317. 0.0
2015 JUL 1 2457204.5 36.0 41317. 0.0
2017 JAN 1 2457754.5 37.0 41317. 0.0
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment