Stateful Transform Bug?

A coworker of mine has discovered some stateful behavior in Frame Transforms.

As noted below in the reproducer, disabling a call to ecfFrame.getTransformTo(eciFrame, date); causes a later call ecfFrame.getTransformTo(eciFrame, date) to change its output.

This feels like an issue with lazy-initialization boundaries in the Frame data; i.e., if I had to guess, I’d say that the if-block (in the reproducer below) changes that data that’s used to extrapolate the Transform (if there is extrapolation in the first place, of course).

Minimal reproducer:

    /**
     * Demonstration test to show that ECF/ECI transforms appear to be stateful
     */
    @Test
    public void demoTest() {
        
        final Frame ecfFrame = FramesFactory.getITRF(ITRFVersion.ITRF_2014, IERSConventions.IERS_2010, false);
        final Frame eciFrame = FramesFactory.getTOD(true);
        
        // If you disable this if-block, the test fails.
        if (true) {
            // Alternatively, if you change the number of seconds from 15.67996291606687 to just 15, the test fails
            AbsoluteDate date = new AbsoluteDate(2023, 10, 10, 05, 46, 15.67996291606687, TimeScalesFactory.getUTC());
            ecfFrame.getTransformTo(eciFrame, date);
        }
        
        Vector3D ecf = new Vector3D(-652298315.6863569, -757962339.0068545, 0);
        AbsoluteDate date = new AbsoluteDate(2023, 10, 10, 0, 0, 0, TimeScalesFactory.getUTC());
        final Transform ecf2eci = ecfFrame.getTransformTo(eciFrame, date);
        final Vector3D eci = ecf2eci.transformPosition(ecf);
        assertEquals("{-380,637,848.80629563; -924,724,190.2622101; -123.9723276174}", eci.toString());
        //                               ^^^                    ^^            ^^^^^
        //            {-380,637,848.80629265; -924,724,190.2622116; -123.9723240995}
    }

Hi @Ryan,

I think what you’re observing is indeed due to the interpolation of the transforms used to get ITRF in Orekit.
Interpolation is done to save processing time.
If you want to focus on accuracy and not interpolate the transforms you can use:

final Transform ecf2eci = FramesFactory.getNonInterpolatingTransform(ecefFrame, eciFrame, date);

Instead of:

final Transform ecf2eci = ecfFrame.getTransformTo(eciFrame, date);

But the performances will be affected.

Hope this helps,
Maxime

Thanks for the help, @MaximeJ ! I’ll give that a shot.

We try to stick to one Frame and limit the conversions between Frames to built-in functionality (e.g., myOrbit.getPVCoordinates(aDifferentFrame)), so we should be safe for the most part.

Such high precision is unnecessary for our application, but we go to great lengths to guarantee absolute reproducibility of the software (as it seems Orekit does, too!), and small precision inconsistencies like this can definitely snowball into strange irreproducibilities.

I’d be a bit surprised if there wasn’t a way to guarantee reproducibility in the Frame interpolations. Could you point me to where that caching happens? Just so I can look around for curiosity’s sake.

Thanks again!

Ah, here is another post a coworker of mine found regarding this topic, FWIW: