Mass Not Changing in DSST

Hi all,

I am currently implementing a custom DSST maneuver as a PythonAbstractGaussianContribution and wrapped around a base maneuver class which uses a custom PythonThrustPropulsionModel. This propulsion model works as intended with a numerical propagator, however when implementing it in the DSST maneuver class, there is no change in satellite mass even though I have a mass derivative and flow rate (the thrust and thrust direction work properly). In fact, it appears that these methods do not get called during the DSST propagation. As an aside, I am wondering if I am implementing the getLLimits method for the DSST maneuver correctly in terms of the lMin and lMax I am returning.

propulsion_model = PropulsionModel(thrustDirectionProvider, self.thrusterAxisInSatelliteFrame, self.thrust_max, self.isp)
maneuver = Maneuver(thrustDirProvider, man_triggers, propulsion_model)
if isinstance(self.propagator,DSSTPropagator):
    maneuver = DSSTManeuver(maneuver)
class DSSTManeuver(PythonAbstractGaussianContribution):
    def __init__(self, maneuver):
        self.maneuver = maneuver
        super(DSSTManeuver, self).__init__("DSST-maneuver-", 1e-8, maneuver, Constants.WGS84_EARTH_MU)
        
    
    def getLLimits(self, state, auxiliaryElements) -> list:

        lMin = state.getLv() - np.pi
        lMax = state.getLv() + np.pi

        return [lMin, lMax]
    
    def getEventsDetectors(self):
        return list(self.maneuver.getEventsDetectors().toArray())
    
    def getParametersDriversWithoutMu(self):
        return self.maneuver.getParametersDrivers()
    
    def getParametersDrivers(self):
        return self.maneuver.getParametersDrivers()
class PropulsionModel(PythonThrustPropulsionModel):
    def __init__(self, thrustDirectionProvider, thrusterAxisInSatelliteFrame, *prop_params):
        super().__init__()
        self.thrustDirectionProvider = thrustDirectionProvider
        self.thrusterAxisInSatelliteFrame = thrusterAxisInSatelliteFrame
        self.prop_params = prop_params
        if prop_params:
            self.thrust_max = prop_params[0]
            self.isp = prop_params[1]

    def init(self, spacecraftState, absoluteDate):
        pass

    def getParametersDrivers(self):
        return Collections.emptyList()

    def getDirection(self, s):
        direction = Vector3D.MINUS_I
        return direction
    
    def getFlowRate(self, s, parameters):
        thrust_mag, _ = self.thrustDirectionProvider.computeThrust(s, self.prop_params)
        if self.prop_params:
            if self.isp > 0:
                flow_rate = - thrust_mag / (self.isp * 9.80665)
            else:
                flow_rate = 0
        else:
            flow_rate = 0

        return float(flow_rate)
    
    def getIsp(self, s):
        if self.prop_params:
            return float(self.isp)
        else:
            return float(0)

    def getMassDerivatives(self, s, doubleArray):
        thrust_mag, _ = self.thrustDirectionProvider.computeThrust(s, self.prop_params)
        flow_rate = - thrust_mag / (self.isp * 9.80665)

        return float(flow_rate)
    
    def getThrust(self, s):
        thrust_mag, _ = self.thrustDirectionProvider.computeThrust(s, self.prop_params)
        return thrust_mag

    def getThrustVector(self, s, parameters):

        thrust_mag, _ = self.thrustDirectionProvider.computeThrust(s, self.prop_params)

        # propulsion vector in spacecraft frame
        thrust_vec_u = self.thrusterAxisInSatelliteFrame.toArray()[:]
        thrust_vec = thrust_mag * np.array(thrust_vec_u)
  
        if thrust_mag == 0:
            thrust_vec = Vector3D(-1e-20,0.0,0.0)
        else:
            thrust_vec = Vector3D(float(thrust_vec[0]),float(thrust_vec[1]),float(thrust_vec[2]))

        return thrust_vec

Hi,

Not knowing the error but, a good way to troubleshoot is to look at the source for the classes. In python all extension points needs to be specified in the wrapper and these are the ones labeled “native”.

For PythonAbstractGaussianContribution the getEventsDetectors is not exposed, so this will use the default implementation in the DSSTForceModel. This is likely not the problem.

Similarly the PythonThrustPropulsionModel is at Link.

Not exposed for subclassing: getDirection, getIsp (calculated from getFlowRate & ThrustVector), getMassDerivatives, getThrust (calculated from ThrustVector), these are automatically derived from ThrustPropulsionModel code.

As it is implemented now, the extension points are basically the getThrustVector and getFlowRate, which is the ones specifically in the ThrustModel without a default implementation.

But looking at your example, not visually clear what is not working, but probably something happens in these methods which is not being called. I would recommend as next step to rewrite with only ThrustVector and FlowRate.

If it is really needed to expose more methods for this class to be usabel, it is fully doable as a fix in a future release but will break exising usages. If that is indeed needed, please file an issue at Issues · Orekit Labs / Orekit Python Wrapper · GitLab with motivation.

Greets

Hi Petrus,

Thanks for the response. I tried your suggestion of just implementing getThrustVector and getFlowRate, however this gives me errors around the other methods not being defined. In fact, I commented out getFlowRate and getMassDerivatives and the propagation ran without error for DSST, however when trying the same with the numerical propagator I get an attribute error since getFlowRate is not defined.

Hi Emery,

Hm strange. Are you using latest orekit v12?

What should be needed for PythonThrustPropulsionModel to implement are:

  • init
  • getControl3DVectorCostType
  • getThrustVector
  • getFlowRate
  • getParametersDrivers

These are also the only methods that the “java side” can access

Similarly for PythonAbstractGaussianContribution :

  • getParametersDriversWithoutMu
  • getLLimits

But this is “should”, haven’t used it myself.

Hi Petrus,

Yes I am using Orekit v12.