Covariance inconsistency with BoundedPropagator and different initial state epoch

Hi everyone,

We recently stumbled upon an issue related to the StateCovarianceMatrixProvider in combination with a generated ephemeris (BoundedPropagator). The problem is that the initial state of the BoundedPropagator might be at a different epoch than the initial covariance. When propagate is called, the StateCovarianceMatrixProvider is initialised again, based on the wrong initial state.

Below is a minimal example to reproduce the problem, but I’ll list the steps as well:

  • Create an initial state and Cartesian covariance at time t_0.
  • Create a numerical propagator with EQUINOCTIAL orbit type
  • Set up MatricesHarvester and add StateCovarianceMatrixProvider to the propagator
  • Now generate an ephemeris for the interval [t_0 - \Delta t, t_0 + \Delta t]
    • This correctly calls init on the StateCovarianceMatrixProvider, which internally converts the initial covariance to EQUINOCTIAL elements using the initial state at time t_0
  • From the ephemeris, get the covariance matrix at time t_0 – this should be the same as the initial covariance that was originally provided.
    • BoundedPropagator.propagate(t_0) incorrectly calls init again, passing its initial state (which is at t_0 - \Delta t) and the initial covariance (provided at t_0) is now wrongly converted to EQUINOCTIAL elements again.
   @Test
  void testInconsistentCovarianceBoundedPropagator() {

    // Some constants
    final Frame frame = FramesFactory.getGCRF();
    final PositionAngleType angleType = PositionAngleType.MEAN;
    final AbsoluteDate initialDate = AbsoluteDate.ARBITRARY_EPOCH;
    final double mu = Constants.GRS80_EARTH_MU;
    final String stmName = "STM";
    final String covName = "CART_COV";
    final double dt = 3600.0; // seconds

    // Setup initial state and covariance
    final Orbit initOrbit = new KeplerianOrbit(7.0e6, 1.e-4, 0.1, 0., 0., 0., angleType, frame, initialDate, mu);
    final SpacecraftState initState = new SpacecraftState(initOrbit);
    final RealMatrix initCartCovariance = MatrixUtils.createRealDiagonalMatrix(new double[]{1., 1., 1., 1.e-3, 1.e-3, 1.e-3});
    final StateCovariance initStateCovariance =
        new StateCovariance(initCartCovariance, initialDate, frame, OrbitType.CARTESIAN, angleType);

    // Numerical propagator with EQUINOCTIAL ELEMENTS
    NumericalPropagator propagator = new NumericalPropagator(new ClassicalRungeKuttaIntegrator(60.));
    propagator.setOrbitType(OrbitType.EQUINOCTIAL);
    propagator.setInitialState(initState);

    // Create covariance matrix provider with initial covariance in CARTESIAN elements
    final MatricesHarvester harvester =
        propagator.setupMatricesComputation(stmName, null, null);
    final StateCovarianceMatrixProvider provider =
        new StateCovarianceMatrixProvider(covName, stmName, harvester, initStateCovariance);
    propagator.addAdditionalDataProvider(provider);

    // Propagate and store ephemeris on [t0 - dt, t0 + dt]
    final EphemerisGenerator generator = propagator.getEphemerisGenerator();
    propagator.propagate(initialDate.shiftedBy(-dt), initialDate.shiftedBy(dt));
    final BoundedPropagator ephemeris = generator.getGeneratedEphemeris();

    // Propagate ephemeris
    SpacecraftState propagated = ephemeris.propagate(initState.getDate());
    final StateCovariance propagatedStateCov = provider.getStateCovariance(propagated);

    // Verify that both covariances are equal
    Assertions.assertEquals(initState.getDate(), propagatedStateCov.getDate());
    Assertions.assertEquals(provider.getCovarianceOrbitType(), propagatedStateCov.getOrbitType());
    compareCovariance(initCartCovariance, propagatedStateCov.getMatrix(), 1.e-4);
  }

This produces the following error:

[ERROR] org.orekit.propagation.covariance.TmpTest.testInconsistentCovarianceBoundedPropagator -- Time elapsed: 0.602 s <<< FAILURE!
org.opentest4j.AssertionFailedError: expected: <1.0> but was: <10805.9618930703>

A minimal fix that makes the test pass could be to add an early return in StateCovarianceMatrixProvider.init(...) if it was already initialised before. However, I’m wondering if there might be reasons why this would be a bad idea.

Best,
Simon