/* Copyright 2002-2017 CS Systèmes d'Information
* Licensed to CS Systèmes d'Information (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.frames;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import org.hipparchus.RealFieldElement;
import org.hipparchus.analysis.UnivariateVectorFunction;
import org.hipparchus.analysis.differentiation.DSFactory;
import org.hipparchus.analysis.differentiation.DerivativeStructure;
import org.hipparchus.analysis.differentiation.FiniteDifferencesDifferentiator;
import org.hipparchus.analysis.differentiation.UnivariateDifferentiableVectorFunction;
import org.hipparchus.geometry.euclidean.threed.Rotation;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.hipparchus.util.Decimal64;
import org.hipparchus.util.Decimal64Field;
import org.hipparchus.util.FastMath;
import org.hipparchus.util.MathArrays;
import org.hipparchus.util.MathUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.orekit.Utils;
import org.orekit.bodies.CelestialBodyFactory;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitExceptionWrapper;
import org.orekit.errors.OrekitIllegalStateException;
import org.orekit.errors.OrekitMessages;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.ChronologicalComparator;
import org.orekit.time.DateComponents;
import org.orekit.time.FieldAbsoluteDate;
import org.orekit.time.TimeComponents;
import org.orekit.time.TimeScalesFactory;
import org.orekit.utils.AngularCoordinates;
import org.orekit.utils.AngularDerivativesFilter;
import org.orekit.utils.CartesianDerivativesFilter;
import org.orekit.utils.Constants;
import org.orekit.utils.IERSConventions;
import org.orekit.utils.IERSConventions.NutationCorrectionConverter;
import org.orekit.utils.PVCoordinates;
public class FramesFactoryTest {
@Test
public void testTreeRoot() throws OrekitException {
Assert.assertNull(FramesFactory.getFrame(Predefined.GCRF).getParent());
}
@Test
public void testWrongSupportedFileNames1980() throws OrekitException {
FramesFactory.addDefaultEOP1980HistoryLoaders("wrong-rapidDataColumns-1980",
"wrong-rapidDataXML-1980",
"wrong-eopC04-1980",
"wrong-bulletinB-1980",
"wrong-bulletinA-1980");
try {
FramesFactory.getEOPHistory(IERSConventions.IERS_1996, true).getStartDate();
Assert.fail("an exception should have been thrown");
} catch (OrekitIllegalStateException oe) {
Assert.assertEquals(OrekitMessages.NO_CACHED_ENTRIES, oe.getSpecifier());
}
}
@Test
public void testWrongSupportedFileNames2000() throws OrekitException {
FramesFactory.addDefaultEOP2000HistoryLoaders("wrong-rapidDataColumns-2000",
"wrong-rapidDataXML-2000",
"wrong-eopC04-2000",
"wrong-bulletinB-2000",
"wrong-bulletinA-2000");
try {
FramesFactory.getEOPHistory(IERSConventions.IERS_2010, true).getStartDate();
Assert.fail("an exception should have been thrown");
} catch (OrekitIllegalStateException oe) {
Assert.assertEquals(OrekitMessages.NO_CACHED_ENTRIES, oe.getSpecifier());
}
}
@Test
public void testWrongConventions() throws OrekitException {
// set up only 1980 conventions
FramesFactory.addDefaultEOP1980HistoryLoaders(null, null, null, null, null);
try {
// attempt to retrieve 2000 conventions
FramesFactory.getEOPHistory(IERSConventions.IERS_2010, true).getStartDate();
Assert.fail("an exception should have been thrown");
} catch (OrekitIllegalStateException oe) {
Assert.assertEquals(OrekitMessages.NO_CACHED_ENTRIES, oe.getSpecifier());
}
}
@Test
public void testEOPLoaderException() {
final boolean[] flags = new boolean[2];
try {
FramesFactory.addEOPHistoryLoader(IERSConventions.IERS_2010, new EOPHistoryLoader() {
@Override
public void fillHistory(NutationCorrectionConverter converter, SortedSet<EOPEntry> history) {
// don't really fill history here
flags[0] = true;
}
});
FramesFactory.addEOPHistoryLoader(IERSConventions.IERS_2010, new EOPHistoryLoader() {
@Override
public void fillHistory(NutationCorrectionConverter converter, SortedSet<EOPEntry> history)
throws OrekitException {
// generate exception
flags[1] = true;
throw new OrekitException(OrekitMessages.NO_DATA_GENERATED, AbsoluteDate.J2000_EPOCH);
}
});
FramesFactory.getEOPHistory(IERSConventions.IERS_2010, true);
Assert.fail("an exception should have been thrown");
} catch (OrekitException oe) {
Assert.assertTrue(flags[0]);
Assert.assertTrue(flags[1]);
Assert.assertEquals(OrekitMessages.NO_DATA_GENERATED, oe.getSpecifier());
}
}
@Test
public void testUnwrapInterpolatingTransformProvider() throws OrekitException {
TransformProvider raw = new TransformProvider() {
private static final long serialVersionUID = 1L;
public Transform getTransform(final AbsoluteDate date) {
double dt = date.durationFrom(AbsoluteDate.J2000_EPOCH);
double sin = FastMath.sin(dt * MathUtils.TWO_PI / Constants.JULIAN_DAY);
return new Transform(date,
new PVCoordinates(new Vector3D(sin, Vector3D.PLUS_I),
Vector3D.ZERO));
}
public <T extends RealFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
throw new UnsupportedOperationException("never called in this test");
}
};
Frame parent = FramesFactory.getGCRF();
Frame frame = new Frame(parent,
new InterpolatingTransformProvider(raw,
CartesianDerivativesFilter.USE_P,
AngularDerivativesFilter.USE_R,
AbsoluteDate.PAST_INFINITY,
AbsoluteDate.FUTURE_INFINITY,
4, Constants.JULIAN_DAY, 10,
Constants.JULIAN_YEAR, 2 * Constants.JULIAN_DAY),
"sine");
double maxErrorNonInterpolating = 0;
double maxErrorInterpolating = 0;
for (double dt = 0; dt < Constants.JULIAN_DAY; dt += 60.0) {
AbsoluteDate date = AbsoluteDate.J2000_EPOCH.shiftedBy(dt);
Transform reference = raw.getTransform(date);
Transform nonInterpolating = FramesFactory.getNonInterpolatingTransform(parent, frame, date);
Transform interpolating = parent.getTransformTo(frame, date);
double errorNonInterpolating = Vector3D.distance(reference.getTranslation(),
nonInterpolating.getTranslation());
maxErrorNonInterpolating = FastMath.max(maxErrorNonInterpolating, errorNonInterpolating);
double errorInterpolating = Vector3D.distance(reference.getTranslation(),
interpolating.getTranslation());
maxErrorInterpolating = FastMath.max(maxErrorInterpolating, errorInterpolating);
}
Assert.assertEquals(0.0, maxErrorNonInterpolating, 1.0e-15);
Assert.assertEquals(1.0, maxErrorInterpolating, 1.0e-15);
}
@Test
public void testUnwrapShiftingTransformProvider() throws OrekitException {
TransformProvider raw = new TransformProvider() {
private static final long serialVersionUID = 1L;
public Transform getTransform(final AbsoluteDate date) {
double dt = date.durationFrom(AbsoluteDate.J2000_EPOCH);
double sin = FastMath.sin(dt * MathUtils.TWO_PI / Constants.JULIAN_DAY);
return new Transform(date,
new PVCoordinates(new Vector3D(sin, Vector3D.PLUS_I),
Vector3D.ZERO));
}
public <T extends RealFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
throw new UnsupportedOperationException("never called in this test");
}
};
Frame parent = FramesFactory.getGCRF();
Frame frame = new Frame(parent,
new ShiftingTransformProvider(raw,
CartesianDerivativesFilter.USE_P,
AngularDerivativesFilter.USE_R,
AbsoluteDate.PAST_INFINITY,
AbsoluteDate.FUTURE_INFINITY,
4, Constants.JULIAN_DAY, 10,
Constants.JULIAN_YEAR, 2 * Constants.JULIAN_DAY),
"sine");
double maxErrorNonShifting = 0;
double maxErrorShifting = 0;
for (double dt = 0; dt < Constants.JULIAN_DAY; dt += 60.0) {
AbsoluteDate date = AbsoluteDate.J2000_EPOCH.shiftedBy(dt);
Transform reference = raw.getTransform(date);
Transform nonShifting = FramesFactory.getNonInterpolatingTransform(parent, frame, date);
Transform shifting = parent.getTransformTo(frame, date);
double errorNonShifting = Vector3D.distance(reference.getTranslation(),
nonShifting.getTranslation());
maxErrorNonShifting = FastMath.max(maxErrorNonShifting, errorNonShifting);
double errorShifting = Vector3D.distance(reference.getTranslation(),
shifting.getTranslation());
maxErrorShifting = FastMath.max(maxErrorShifting, errorShifting);
}
Assert.assertEquals(0.0, maxErrorNonShifting, 1.0e-15);
Assert.assertEquals(1.0, maxErrorShifting, 1.0e-15);
}
@Test
public void testTreeICRF() throws OrekitException {
Frame icrf = FramesFactory.getFrame(Predefined.ICRF);
Transform t = icrf.getTransformTo(FramesFactory.getGCRF(),
new AbsoluteDate(1969, 6, 25, TimeScalesFactory.getTT()));
Assert.assertEquals(0.0, t.getRotation().getAngle(), 1.0e-15);
Assert.assertEquals(CelestialBodyFactory.EARTH_MOON + "/inertial", icrf.getParent().getName());
Assert.assertEquals(Predefined.GCRF.getName(), icrf.getParent().getParent().getName());
}
@Test
public void testTree() throws OrekitException {
Predefined[][] reference = new Predefined[][] {
{ Predefined.EME2000, Predefined.GCRF },
{ Predefined.ITRF_CIO_CONV_1996_ACCURATE_EOP, Predefined.TIRF_CONVENTIONS_1996_ACCURATE_EOP },
{ Predefined.ITRF_CIO_CONV_1996_SIMPLE_EOP, Predefined.TIRF_CONVENTIONS_1996_SIMPLE_EOP },
{ Predefined.ITRF_CIO_CONV_2003_ACCURATE_EOP, Predefined.TIRF_CONVENTIONS_2003_ACCURATE_EOP },
{ Predefined.ITRF_CIO_CONV_2003_SIMPLE_EOP, Predefined.TIRF_CONVENTIONS_2003_SIMPLE_EOP },
{ Predefined.ITRF_CIO_CONV_2010_ACCURATE_EOP, Predefined.TIRF_CONVENTIONS_2010_ACCURATE_EOP },
{ Predefined.ITRF_CIO_CONV_2010_SIMPLE_EOP, Predefined.TIRF_CONVENTIONS_2010_SIMPLE_EOP },
{ Predefined.TIRF_CONVENTIONS_1996_ACCURATE_EOP, Predefined.CIRF_CONVENTIONS_1996_ACCURATE_EOP },
{ Predefined.TIRF_CONVENTIONS_1996_SIMPLE_EOP, Predefined.CIRF_CONVENTIONS_1996_SIMPLE_EOP },
{ Predefined.TIRF_CONVENTIONS_2003_ACCURATE_EOP, Predefined.CIRF_CONVENTIONS_2003_ACCURATE_EOP },
{ Predefined.TIRF_CONVENTIONS_2003_SIMPLE_EOP, Predefined.CIRF_CONVENTIONS_2003_SIMPLE_EOP },
{ Predefined.TIRF_CONVENTIONS_2010_ACCURATE_EOP, Predefined.CIRF_CONVENTIONS_2010_ACCURATE_EOP },
{ Predefined.TIRF_CONVENTIONS_2010_SIMPLE_EOP, Predefined.CIRF_CONVENTIONS_2010_SIMPLE_EOP },
{ Predefined.CIRF_CONVENTIONS_1996_ACCURATE_EOP, Predefined.GCRF },
{ Predefined.CIRF_CONVENTIONS_1996_SIMPLE_EOP, Predefined.GCRF },
{ Predefined.CIRF_CONVENTIONS_2003_ACCURATE_EOP, Predefined.GCRF },
{ Predefined.CIRF_CONVENTIONS_2003_SIMPLE_EOP, Predefined.GCRF },
{ Predefined.CIRF_CONVENTIONS_2010_ACCURATE_EOP, Predefined.GCRF },
{ Predefined.CIRF_CONVENTIONS_2010_SIMPLE_EOP, Predefined.GCRF },
{ Predefined.VEIS_1950, Predefined.GTOD_WITHOUT_EOP_CORRECTIONS },
{ Predefined.ITRF_EQUINOX_CONV_1996_ACCURATE_EOP, Predefined.GTOD_CONVENTIONS_1996_ACCURATE_EOP },
{ Predefined.ITRF_EQUINOX_CONV_1996_SIMPLE_EOP, Predefined.GTOD_CONVENTIONS_1996_SIMPLE_EOP },
{ Predefined.ITRF_EQUINOX_CONV_2003_ACCURATE_EOP, Predefined.GTOD_CONVENTIONS_2003_ACCURATE_EOP },
{ Predefined.ITRF_EQUINOX_CONV_2003_SIMPLE_EOP, Predefined.GTOD_CONVENTIONS_2003_SIMPLE_EOP },
{ Predefined.ITRF_EQUINOX_CONV_2010_ACCURATE_EOP, Predefined.GTOD_CONVENTIONS_2010_ACCURATE_EOP },
{ Predefined.ITRF_EQUINOX_CONV_2010_SIMPLE_EOP, Predefined.GTOD_CONVENTIONS_2010_SIMPLE_EOP },
{ Predefined.GTOD_WITHOUT_EOP_CORRECTIONS, Predefined.TOD_WITHOUT_EOP_CORRECTIONS },
{ Predefined.GTOD_CONVENTIONS_1996_ACCURATE_EOP, Predefined.TOD_CONVENTIONS_1996_ACCURATE_EOP },
{ Predefined.GTOD_CONVENTIONS_1996_SIMPLE_EOP, Predefined.TOD_CONVENTIONS_1996_SIMPLE_EOP },
{ Predefined.GTOD_CONVENTIONS_2003_ACCURATE_EOP, Predefined.TOD_CONVENTIONS_2003_ACCURATE_EOP },
{ Predefined.GTOD_CONVENTIONS_2003_SIMPLE_EOP, Predefined.TOD_CONVENTIONS_2003_SIMPLE_EOP },
{ Predefined.GTOD_CONVENTIONS_2010_ACCURATE_EOP, Predefined.TOD_CONVENTIONS_2010_ACCURATE_EOP },
{ Predefined.GTOD_CONVENTIONS_2010_SIMPLE_EOP, Predefined.TOD_CONVENTIONS_2010_SIMPLE_EOP },
{ Predefined.TOD_WITHOUT_EOP_CORRECTIONS, Predefined.MOD_WITHOUT_EOP_CORRECTIONS },
{ Predefined.TOD_CONVENTIONS_1996_ACCURATE_EOP, Predefined.MOD_CONVENTIONS_1996 },
{ Predefined.TOD_CONVENTIONS_1996_SIMPLE_EOP, Predefined.MOD_CONVENTIONS_1996 },
{ Predefined.TOD_CONVENTIONS_2003_ACCURATE_EOP, Predefined.MOD_CONVENTIONS_2003 },
{ Predefined.TOD_CONVENTIONS_2003_SIMPLE_EOP, Predefined.MOD_CONVENTIONS_2003 },
{ Predefined.TOD_CONVENTIONS_2010_ACCURATE_EOP, Predefined.MOD_CONVENTIONS_2010 },
{ Predefined.TOD_CONVENTIONS_2010_SIMPLE_EOP, Predefined.MOD_CONVENTIONS_2010 },
{ Predefined.MOD_WITHOUT_EOP_CORRECTIONS, Predefined.EME2000 },
{ Predefined.MOD_CONVENTIONS_1996, Predefined.GCRF },
{ Predefined.MOD_CONVENTIONS_2003, Predefined.EME2000 },
{ Predefined.MOD_CONVENTIONS_2010, Predefined.EME2000 },
{ Predefined.TEME, Predefined.TOD_WITHOUT_EOP_CORRECTIONS }
};
for (final Predefined[] pair : reference) {
Frame child = FramesFactory.getFrame(pair[0]);
Frame parent = FramesFactory.getFrame(pair[1]);
Assert.assertEquals("wrong parent for " + child.getName(),
parent.getName(), child.getParent().getName());
}
}
@Test
public void testSerialization()
throws OrekitException, IOException, ClassNotFoundException {
for (Predefined predefined : Predefined.values()) {
Frame original = FramesFactory.getFrame(predefined);
if (predefined == Predefined.ICRF) {
Assert.assertEquals(CelestialBodyFactory.SOLAR_SYSTEM_BARYCENTER + "/inertial", original.getName());
} else {
Assert.assertEquals(predefined.getName(), original.getName());
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(original);
if (predefined == Predefined.GCRF) {
Assert.assertTrue(bos.size() > 50);
Assert.assertTrue(bos.size() < 100);
} else if (predefined == Predefined.ICRF) {
Assert.assertTrue(bos.size() > 430);
Assert.assertTrue(bos.size() < 480);
} else {
Assert.assertTrue(bos.size() > 100);
Assert.assertTrue(bos.size() < 160);
}
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
Frame deserialized = (Frame) ois.readObject();
Assert.assertTrue(original == deserialized);
}
}
@Test
public void testEOPConversionSymetry1980() throws OrekitException {
Utils.setDataRoot("rapid-data-columns");
IERSConventions.NutationCorrectionConverter converter =
IERSConventions.IERS_1996.getNutationCorrectionConverter();
SortedSet<EOPEntry> rawEquinox = new TreeSet<EOPEntry>(new ChronologicalComparator());
new RapidDataAndPredictionColumnsLoader(false, "^finals\\.daily$").fillHistory(converter, rawEquinox);
Assert.assertEquals(181, rawEquinox.size());
for (final EOPEntry entry : rawEquinox) {
final double[] rebuiltEquinox = converter.toEquinox(entry.getDate(),
entry.getDx(), entry.getDy());
Assert.assertEquals(entry.getDdPsi(), rebuiltEquinox[0], 2.0e-22);
Assert.assertEquals(entry.getDdEps(), rebuiltEquinox[1], 2.0e-23);
}
}
@Test
public void testEOPConversionSymetry2003() throws OrekitException {
Utils.setDataRoot("rapid-data-columns");
IERSConventions.NutationCorrectionConverter converter =
IERSConventions.IERS_2003.getNutationCorrectionConverter();
final SortedSet<EOPEntry> rawNRO = new TreeSet<EOPEntry>(new ChronologicalComparator());
new RapidDataAndPredictionColumnsLoader(true, "^finals2000A\\.daily$").fillHistory(converter, rawNRO);
Assert.assertEquals(181, rawNRO.size());
for (final EOPEntry entry : rawNRO) {
final double[] rebuiltNRO = converter.toNonRotating(entry.getDate(),
entry.getDdPsi(), entry.getDdEps());
Assert.assertEquals(entry.getDx(), rebuiltNRO[0], 6.0e-23);
Assert.assertEquals(entry.getDy(), rebuiltNRO[1], 2.0e-23);
}
}
@Test
public void testCIP2003() throws OrekitException {
testCIP(IERSConventions.IERS_2003, 1.2e-11);
}
@Test
public void testCIP2010() throws OrekitException {
testCIP(IERSConventions.IERS_2010, 1.2e-11);
}
private void testCIP(IERSConventions conventions, double threshold) throws OrekitException {
Utils.setLoaders(conventions, new ArrayList<EOPEntry>());
Frame cirf = FramesFactory.getCIRF(conventions, false);
Frame tod = FramesFactory.getTOD(conventions, false);
AbsoluteDate t0 = new AbsoluteDate(new DateComponents(2003, 06, 21), TimeComponents.H00,
TimeScalesFactory.getUTC());
for (double dt = -10 * Constants.JULIAN_DAY; dt < 10 * Constants.JULIAN_DAY; dt += 7200) {
// CIRF and TOD should both have the Celestial Intermediate Pole as their Z axis
AbsoluteDate date = t0.shiftedBy(dt);
Transform t = FramesFactory.getNonInterpolatingTransform(tod, cirf, date);
Vector3D z = t.transformVector(Vector3D.PLUS_K);
Assert.assertEquals(0.0, Vector3D.angle(z, Vector3D.PLUS_K), threshold);
}
}
@Test
public void testEOPConversion() throws OrekitException {
// real data from buletinb-298.txt
// first use case: don't propagate the dx, dy correction to TOD, set dPsi, dEpsilon to 0.0
final List<EOPEntry> forced = Utils.buildEOPList(IERSConventions.IERS_2010, new double[][] {
{ 56202, 0.3726886, 0.0008843, 0.168556, 0.332869, 0.0, 0.0, -0.000118, 0.000091 },
{ 56203, 0.3719108, 0.0007204, 0.168261, 0.331527, 0.0, 0.0, -0.000140, 0.000111 },
{ 56204, 0.3712561, 0.0006217, 0.168218, 0.330668, 0.0, 0.0, -0.000165, 0.000148 },
{ 56205, 0.3706736, 0.0005530, 0.167775, 0.329688, 0.0, 0.0, -0.000188, 0.000189 },
{ 56206, 0.3701593, 0.0005139, 0.166829, 0.328457, 0.0, 0.0, -0.000180, 0.000203 }
});
Utils.setLoaders(IERSConventions.IERS_2010, forced);
Frame cirf = FramesFactory.getCIRF(IERSConventions.IERS_2010, false);
Frame todNoCorrection = FramesFactory.getTOD(IERSConventions.IERS_2010, false);
// second use case: convert dx, dy data into dDPsi, dDEpsilon
final List<EOPEntry> converted = Utils.buildEOPList(IERSConventions.IERS_2010, new double[][] {
{ 56202, 0.3726886, 0.0008843, 0.168556, 0.332869, Double.NaN, Double.NaN, -0.000118, 0.000091 },
{ 56203, 0.3719108, 0.0007204, 0.168261, 0.331527, Double.NaN, Double.NaN, -0.000140, 0.000111 },
{ 56204, 0.3712561, 0.0006217, 0.168218, 0.330668, Double.NaN, Double.NaN, -0.000165, 0.000148 },
{ 56205, 0.3706736, 0.0005530, 0.167775, 0.329688, Double.NaN, Double.NaN, -0.000188, 0.000189 },
{ 56206, 0.3701593, 0.0005139, 0.166829, 0.328457, Double.NaN, Double.NaN, -0.000180, 0.000203 }
});
Utils.setLoaders(IERSConventions.IERS_2010, converted);
Frame todConvertedCorrection = FramesFactory.getTOD(IERSConventions.IERS_2010, false);
for (AbsoluteDate date = forced.get(0).getDate();
date.compareTo(forced.get(forced.size() - 1).getDate()) < 0;
date = date.shiftedBy(3600)) {
Transform tNoCorrection =
FramesFactory.getNonInterpolatingTransform(todNoCorrection, cirf, date);
// when we forget the correction on TOD,
// its Z axis is slightly offset from CIRF Z axis
Vector3D zNoCorrection = tNoCorrection.transformVector(Vector3D.PLUS_K);
Assert.assertTrue(Vector3D.angle(zNoCorrection, Vector3D.PLUS_K) > 7.2e-10);
Transform tConverted =
FramesFactory.getNonInterpolatingTransform(todConvertedCorrection, cirf, date);
// when we convert the correction and apply it to TOD,
// its Z axis is much better aligned with CIRF Z axis
Vector3D zConverted = tConverted.transformVector(Vector3D.PLUS_K);
Assert.assertTrue(Vector3D.angle(zConverted, Vector3D.PLUS_K) < 6e-12);
}
}
@Test
public void testEOPConversionUAI2000Package() throws OrekitException {
// the reference value has been computed using the uai2000.package routines
// provided by Ch. Bizouard on page http://hpiers.obspm.fr/eop-pc/models/models_fr.html
// using the following main program
//
// program test_EOP_conversion
// double precision dmjd,dpsi,deps,dx1,dy1,dx2,dy2
//C 2004-02-14:00:00:00Z, MJD = 53049,
//C UT1-UTC=-0.4093475, LOD = 0.4676,
//C X = -0.076804, Y = 0.204671,
//C dx = -0.075, dy = -0.189
//C values extracted from finals2000A.all file, bulletinA columns
// dmjd = 53049.0
// dx1 = -0.075
// dy1 = -0.189
// call DPSIDEPS2000_DXDY2000(dmjd,dx1,dy1,dpsi,deps)
// write (6, *) 'dPsi = ', dpsi, 'dEpsilon = ', deps
// call DXDY2000_DPSIDEPS2000(dmjd,dpsi,deps,dX2,dY2)
// write (6, *) 'dx = ', dx2, 'dy = ', dy2
// end
//
// the output of this test reads:
// dPsi = -0.18810999708158463 dEpsilon = -0.18906891450729962
// dx = -7.5000002980232239E-002 dy = -0.18899999558925629
IERSConventions.NutationCorrectionConverter converter =
IERSConventions.IERS_2003.getNutationCorrectionConverter();
AbsoluteDate date =
new AbsoluteDate(new DateComponents(DateComponents.MODIFIED_JULIAN_EPOCH, 53049),
TimeScalesFactory.getUTC());
double dx = Constants.ARC_SECONDS_TO_RADIANS * -0.075;
double dy = Constants.ARC_SECONDS_TO_RADIANS * -0.189;
double[] equinox = converter.toEquinox(date, dx, dy);
// The code from uai2000.package uses sin(epsilon0), cos(epsilon0) in the
// formula, whereas IERS conventions use sin(epsilonA), cos(epsilon0), i.e.
// the sine is computed on current date instead of epoch. This explains why
// the following threshold had to be raised to 2e-11.
// We still decided to stick with sin(epsilonA) in our implementation, in
// order to remain consistent with IERS conventions
Assert.assertEquals(Constants.ARC_SECONDS_TO_RADIANS * -0.18810999708158463,
equinox[0], 2.0e-11);
Assert.assertEquals(Constants.ARC_SECONDS_TO_RADIANS * -0.18906891450729962,
equinox[1], 2.2e-14);
double[] nro = converter.toNonRotating(date, equinox[0], equinox[1]);
Assert.assertEquals(dx, nro[0], 1.0e-20);
Assert.assertEquals(dy, nro[1], 1.0e-20);
}
@Test
public void testFieldConsistency() throws OrekitException {
for (final Predefined predefined : Predefined.values()) {
final Frame frame = FramesFactory.getFrame(predefined);
final Frame parent = frame.getParent();
if (parent != null) {
double maxPositionError = 0;
double maxVelocityError = 0;
double maxAccelerationError = 0;
double maxRotationError = 0;
double maxRotationRateError = 0;
double maxRotationAccelerationError = 0;
for (double dt = 0; dt < Constants.JULIAN_DAY; dt += 60.0) {
final AbsoluteDate date = AbsoluteDate.J2000_EPOCH.shiftedBy(dt);
final Transform transformDouble = parent.getTransformTo(frame, date);
final FieldTransform<Decimal64> transformD64 =
parent.getTransformTo(frame, new FieldAbsoluteDate<>(Decimal64Field.getInstance(), date));
maxPositionError = FastMath.max(maxPositionError,
Vector3D.distance(transformDouble.getTranslation(),
transformD64.getTranslation().toVector3D()));
maxVelocityError = FastMath.max(maxVelocityError,
Vector3D.distance(transformDouble.getVelocity(),
transformD64.getVelocity().toVector3D()));
maxAccelerationError = FastMath.max(maxAccelerationError,
Vector3D.distance(transformDouble.getAcceleration(),
transformD64.getAcceleration().toVector3D()));
maxRotationError = FastMath.max(maxRotationError,
Rotation.distance(transformDouble.getRotation(),
transformD64.getRotation().toRotation()));
maxRotationRateError = FastMath.max(maxRotationRateError,
Vector3D.distance(transformDouble.getRotationRate(),
transformD64.getRotationRate().toVector3D()));
maxRotationAccelerationError = FastMath.max(maxRotationAccelerationError,
Vector3D.distance(transformDouble.getRotationAcceleration(),
transformD64.getRotationAcceleration().toVector3D()));
}
Assert.assertEquals(0, maxPositionError, 1.0e-100);
Assert.assertEquals(0, maxVelocityError, 1.0e-100);
Assert.assertEquals(0, maxAccelerationError, 1.0e-100);
Assert.assertEquals(0, maxRotationError, 2.0e-14);
Assert.assertEquals(0, maxRotationRateError, 2.0e-18);
Assert.assertEquals(0, maxRotationAccelerationError, 8.0e-22);
}
}
}
@Test
public void testDerivatives2000WithInterpolation() throws OrekitException {
doTestDerivatives(AbsoluteDate.J2000_EPOCH, Constants.JULIAN_DAY, 60.0, false,
8.0e-5, 2.0e-5, 3.0e-8, 4.0e-11, 7.0e-13, 2.0e-14);
}
@Test
public void testDerivatives2000WithoutInterpolation() throws OrekitException {
// when we forbid interpolation, the test is really slow (almost two hours
// runtime on a very old machine for one day time span and one minute rate),
// we drastically reduce sampling to circumvent this drawback
doTestDerivatives(AbsoluteDate.J2000_EPOCH, Constants.JULIAN_DAY / 4, 3600, true,
8.0e-5, 2.0e-5, 3.0e-8, 4.0e-11, 7.0e-13, 2.0e-14);
}
@Test
public void testDerivatives2003WithInterpolation() throws OrekitException {
doTestDerivatives(AbsoluteDate.J2000_EPOCH.shiftedBy(3 * Constants.JULIAN_YEAR),
Constants.JULIAN_DAY, 60.0, false,
8.0e-5, 2.0e-5, 4.0e-8, 8.0e-12, 3.0e-13, 4.0e-15);
}
@Test
public void testDerivatives2003WithoutInterpolation() throws OrekitException {
// when we forbid interpolation, the test is really slow (almost two hours
// runtime on a very old machine for one day time span and one minute rate),
// we drastically reduce sampling to circumvent this drawback
doTestDerivatives(AbsoluteDate.J2000_EPOCH.shiftedBy(3 * Constants.JULIAN_YEAR),
Constants.JULIAN_DAY / 4, 3600, true,
8.0e-5, 2.0e-5, 4.0e-8, 8.0e-12, 3.0e-13, 4.0e-15);
}
private void doTestDerivatives(AbsoluteDate ref,
double duration, double step, boolean forbidInterpolation,
double cartesianTolerance, double cartesianDotTolerance, double cartesianDotDotTolerance,
double rodriguesTolerance, double rodriguesDotTolerance, double rodriguesDotDotTolerance)
throws OrekitException {
final DSFactory factory = new DSFactory(1, 2);
final FieldAbsoluteDate<DerivativeStructure> refDS = new FieldAbsoluteDate<>(factory.getDerivativeField(), ref);
FiniteDifferencesDifferentiator differentiator = new FiniteDifferencesDifferentiator(8, 60.0);
for (final Predefined predefined : Predefined.values()) {
final Frame frame = FramesFactory.getFrame(predefined);
final Frame parent = frame.getParent();
if (parent != null) {
UnivariateDifferentiableVectorFunction dCartesian = differentiator.differentiate(new UnivariateVectorFunction() {
@Override
public double[] value(double t) {
try {
return forbidInterpolation ?
FramesFactory.getNonInterpolatingTransform(parent, frame, ref.shiftedBy(t)).getTranslation().toArray() :
parent.getTransformTo(frame, ref.shiftedBy(t)).getTranslation().toArray();
} catch (OrekitException oe) {
throw new OrekitExceptionWrapper(oe);
}
}
});
UnivariateDifferentiableVectorFunction dOrientation = differentiator.differentiate(new UnivariateVectorFunction() {
double sign = +1.0;
Rotation previous = Rotation.IDENTITY;
@Override
public double[] value(double t) {
try {
AngularCoordinates ac = forbidInterpolation ?
FramesFactory.getNonInterpolatingTransform(parent, frame, ref.shiftedBy(t)).getAngular() :
parent.getTransformTo(frame, ref.shiftedBy(t)).getAngular();
final double dot = MathArrays.linearCombination(ac.getRotation().getQ0(), previous.getQ0(),
ac.getRotation().getQ1(), previous.getQ1(),
ac.getRotation().getQ2(), previous.getQ2(),
ac.getRotation().getQ3(), previous.getQ3());
sign = FastMath.copySign(1.0, dot * sign);
previous = ac.getRotation();
return ac.getModifiedRodrigues(sign)[0];
} catch (OrekitException oe) {
throw new OrekitExceptionWrapper(oe);
}
}
});
double maxCartesianError = 0;
double maxCartesianDotError = 0;
double maxCartesianDotDotError = 0;
double maxRodriguesError = 0;
double maxRodriguesDotError = 0;
double maxRodriguesDotDotError = 0;
for (double dt = 0; dt < duration; dt += step) {
final DerivativeStructure dtDS = factory.variable(0, dt);
final FieldTransform<DerivativeStructure> tDS = forbidInterpolation ?
FramesFactory.getNonInterpolatingTransform(parent, frame, refDS.shiftedBy(dtDS)) :
parent.getTransformTo(frame, refDS.shiftedBy(dtDS));
final DerivativeStructure[] refCart = dCartesian.value(dtDS);
final DerivativeStructure[] fieldCart = tDS.getTranslation().toArray();
for (int i = 0; i < 3; ++i) {
maxCartesianError = FastMath.max(maxCartesianError, FastMath.abs(refCart[i].getValue() - fieldCart[i].getValue()));
maxCartesianDotError = FastMath.max(maxCartesianDotError, FastMath.abs(refCart[i].getPartialDerivative(1) - fieldCart[i].getPartialDerivative(1)));
maxCartesianDotDotError = FastMath.max(maxCartesianDotDotError, FastMath.abs(refCart[i].getPartialDerivative(2) - fieldCart[i].getPartialDerivative(2)));
}
final DerivativeStructure[] refOr = dOrientation.value(dtDS);
DerivativeStructure[] fieldOr = tDS.getAngular().getModifiedRodrigues(1.0)[0];
final double dot = refOr[0].linearCombination(refOr, fieldOr).getReal();
if (dot < 0 || Double.isNaN(dot)) {
fieldOr = tDS.getAngular().getModifiedRodrigues(-1.0)[0];
}
for (int i = 0; i < 3; ++i) {
maxRodriguesError = FastMath.max(maxRodriguesError, FastMath.abs(refOr[i].getValue() - fieldOr[i].getValue()));
maxRodriguesDotError = FastMath.max(maxRodriguesDotError, FastMath.abs(refOr[i].getPartialDerivative(1) - fieldOr[i].getPartialDerivative(1)));
maxRodriguesDotDotError = FastMath.max(maxRodriguesDotDotError, FastMath.abs(refOr[i].getPartialDerivative(2) - fieldOr[i].getPartialDerivative(2)));
}
}
Assert.assertEquals(frame.getName(), 0, maxCartesianError, cartesianTolerance);
Assert.assertEquals(frame.getName(), 0, maxCartesianDotError, cartesianDotTolerance);
Assert.assertEquals(frame.getName(), 0, maxCartesianDotDotError, cartesianDotDotTolerance);
Assert.assertEquals(frame.getName(), 0, maxRodriguesError, rodriguesTolerance);
Assert.assertEquals(frame.getName(), 0, maxRodriguesDotError, rodriguesDotTolerance);
Assert.assertEquals(frame.getName(), 0, maxRodriguesDotDotError, rodriguesDotDotTolerance);
}
}
}
@Before
public void setUp() {
Utils.setDataRoot("regular-data");
}
}