Adding attitude sequence to numerical propagator causes NullPointerException

Hello all,

I’ve been trying to add an AttitudesSequence to a numerical propagation, to no avail so far. The symptoms are a nullPointerException raised upon calling getAttitude on the provided sequence within the integrator. Attached is a minimal code snippet demonstrating the behavior (the path to the orekit-data folder will need to be modified to reflect your local install).

The error trace is as follows :

  File "/home/benjamin/sequence_error.py", line 91, in <module>
    propagateOrbit()
  File "/home/benjamin/sequence_error.py", line 87, in propagateOrbit
    end_state = propagator_num.propagate(date, date.shiftedBy(1000.0))
orekit.JavaError: <super: <class 'JavaError'>, <JavaError object>>
    Java stacktrace:
java.lang.NullPointerException
	at org.orekit.attitudes.AttitudesSequence.getAttitude(AttitudesSequence.java:312)
	at org.orekit.propagation.numerical.NumericalPropagator$OsculatingMapper.mapArrayToState(NumericalPropagator.java:874)
	at org.orekit.propagation.integration.StateMapper.mapArrayToState(StateMapper.java:169)
	at org.orekit.propagation.integration.AbstractIntegratedPropagator$ConvertedMainStateEquations.init(AbstractIntegratedPropagator.java:768)
	at org.hipparchus.ode.ExpandableODE.init(ExpandableODE.java:110)
	at org.hipparchus.ode.AbstractIntegrator.initIntegration(AbstractIntegrator.java:199)
	at org.hipparchus.ode.nonstiff.EmbeddedRungeKuttaIntegrator.integrate(EmbeddedRungeKuttaIntegrator.java:195)
	at org.orekit.propagation.integration.AbstractIntegratedPropagator.integrateDynamics(AbstractIntegratedPropagator.java:509)
	at org.orekit.propagation.integration.AbstractIntegratedPropagator.propagate(AbstractIntegratedPropagator.java:440)

Below is the minimum example that can be run to replicate this error

import numpy as np
import orekit
import datetime
from orekit.pyhelpers import setup_orekit_curdir
orekit.initVM()

setup_orekit_curdir("path-to-orekit-data")

def propagateOrbit():
    '''
    Propagate orbit

    '''

    from org.orekit.propagation.numerical import NumericalPropagator
    from org.orekit.propagation.events import DateDetector
    from org.hipparchus.ode.nonstiff import DormandPrince853Integrator
    from org.hipparchus.geometry.euclidean.threed import Vector3D
    from org.orekit.propagation import SpacecraftState
    from org.orekit.bodies import OneAxisEllipsoid
    from org.orekit.utils import IERSConventions,PVCoordinates,AbsolutePVCoordinates,Constants,AngularDerivativesFilter
    from org.orekit.forces.gravity.potential import GravityFieldFactory
    from org.orekit.forces.gravity import HolmesFeatherstoneAttractionModel
    from org.orekit.forces.maneuvers import ConstantThrustManeuver
    from org.orekit.orbits import CartesianOrbit,OrbitType
    from org.orekit.frames import FramesFactory,LOFType,LocalOrbitalFrame
    from org.orekit.attitudes import LofOffset,AttitudesSequence
    from org.hipparchus.geometry.euclidean.threed import RotationOrder
    from org.orekit.time import AbsoluteDate,TimeScalesFactory # checks that everything went well

    from orekit import JArray_double

   
    orekitFrame = FramesFactory.getGCRF()
    inertial_frame = FramesFactory.getGCRF()
    datetimeObj = datetime.datetime.now()
    date = AbsoluteDate(datetimeObj.year, datetimeObj.month, datetimeObj.day, datetimeObj.hour, datetimeObj.minute, float(datetimeObj.second), TimeScalesFactory.getUTC())

    # 
    position_N = np.array([5689777.60262529, 3939299.31643386,       0])      
    velocity_N = np.array([ 526.7766245 , -760.85658867, 7536.91547998])      

    # Set initial orbit
    position_N_orekit  = Vector3D(float(position_N[0]),float(position_N[1]),float(position_N[2]))
    velocity_N_orekit  = Vector3D(float(velocity_N[0]),float(velocity_N[1]),float(velocity_N[2]))
    absPvCoordinates = AbsolutePVCoordinates(inertial_frame, date, position_N_orekit, velocity_N_orekit)
    initialOrbit = CartesianOrbit(absPvCoordinates,orekitFrame, date, Constants.WGS84_EARTH_MU)

    # Set integrator parameters
    minStep = 0.001
    maxstep = 1000.0
    initStep = 60.0
    tolerances = NumericalPropagator.tolerances(1e-3, 
                                        initialOrbit, 
                                        initialOrbit.getType())

    integrator = DormandPrince853Integrator(minStep, maxstep, 
    JArray_double.cast_(tolerances[0]),  # Double array of doubles needs to be casted in Python
    JArray_double.cast_(tolerances[1]))
    integrator.setInitialStepSize(initStep)

    # Initial state
    initialState = SpacecraftState(initialOrbit,  100.0) 

    # Setup integrator
    propagator_num = NumericalPropagator(integrator)
    propagator_num.setOrbitType(OrbitType.CARTESIAN)
    propagator_num.setInitialState(initialState)

    # Load force model
    gravityProvider = GravityFieldFactory.getNormalizedProvider(10, 10)

    forceModel = HolmesFeatherstoneAttractionModel(FramesFactory.getITRF(IERSConventions.IERS_2010, True), gravityProvider)

    propagator_num.addForceModel(forceModel)

    attitude_sequence = AttitudesSequence()
    
    propagator_num.setAttitudeProvider(attitude_sequence)

    OrbitType.KEPLERIAN.convertType(propagator_num.getInitialState().getOrbit())

    # Save ephemeris
    generator = propagator_num.getEphemerisGenerator()

    # Propagate orbit
    end_state = propagator_num.propagate(date, date.shiftedBy(1000.0))

    return

propagateOrbit()

Looking more closely as the implementation of AttitudesSequence, I admit it is expected that a NullPointerException must ensue should the sequence be empty (hence activated == null when getAttitude is called) . However, I’m still encountering this issue when the sequence is not empty

Hi,

I assume you’re using Orekit <= 12.2.

You need to call

attitude_sequence.registerSwitchEvents(propagator)

This need has been lifted with Orekit 13.0 (and there is also an alternative with instantaneous switches).

Cheers,
Romain.

1 Like