CustomDynamicModel#

class CustomDynamicModel(name: str, acceleration, parameters: list | None = None, partial_by_position=None, partial_by_velocity=None, depends_on_position: bool | None = None, depends_on_velocity: bool | None = None, position_step: float | None = None, velocity_step: float | None = None)#

Bases: DynamicModel

User-supplied force model, defined entirely from a script.

CustomDynamicModel turns a plain Python function into a first-class Scarabaeus force model: its acceleration is summed into the equations of motion alongside the built-in models, and the parameters it declares are propagated, differentiated, and estimated exactly like eta_srp or a_fogm. Adding a force therefore requires no change to the library source — build the model in the script and hand it to ForceModelTranslation through custom_models.

The acceleration enters the equation of motion as one more term of

\[\ddot{\mathbf r} = \sum_i \mathbf a_i(\mathbf r,\,\dot{\mathbf r},\,\mathbf p,\,t)\]

and the model supplies the blocks of \(\partial \mathbf f / \partial \mathbf p\) needed by the variational equations: \(\partial \mathbf a / \partial \mathbf r\), \(\partial \mathbf a / \partial \dot{\mathbf r}\) and, for each declared CustomParameter, \(\partial \mathbf a / \partial p\). Any Jacobian the user does not provide analytically is evaluated by central finite differences of the user functions, so a model is usable from its acceleration alone.

Calling convention. Every user callable is invoked with keyword arguments; declare only the ones you need, in any order. The available names are:

position

(3,) position of body w.r.t. the propagation origin, km

velocity

(3,) inertial velocity of body, km/s

epoch

current epoch, TDB seconds past J2000

params

dict mapping this model’s parameter names to their current values (estimated value when in the state, else the parameter default)

state

full propagated state, keyed by (name, spice_id)

body

the body the acceleration acts on

spacecraft

primary_body of the owning force model

origin

central body of the propagation

frame

base Frame of the propagation

mass

mass of spacecraft at epoch, kg

model

this CustomDynamicModel instance

A callable declaring **kwargs receives all of them.

Parameters:
namestr

Identifier of the model. Appears in dynamics_mode_list and must be unique among the active force models.

accelerationcallable

Returns the (3,) acceleration contribution, in km/s^2. Required.

parameterslist, optional

Solve-for parameters consumed by this model, given as CustomParameter objects or as plain names (which are registered as scalar, dimensionless parameters).

partial_by_positioncallable, optional

Returns \(\partial \mathbf a / \partial \mathbf r\) as (3, 3). Defaults to a central finite difference of acceleration.

partial_by_velocitycallable, optional

Returns \(\partial \mathbf a / \partial \dot{\mathbf r}\) as (3, 3). Defaults to a central finite difference of acceleration.

depends_on_positionbool, optional

Whether the acceleration depends on position. Inferred from the signature of acceleration when None (the default); set it explicitly when the dependence is hidden, e.g. read out of state.

depends_on_velocitybool, optional

Same, for the velocity dependence. When it resolves to False the (structurally zero) \(\partial \mathbf a / \partial \dot{\mathbf r}\) block is skipped entirely.

position_stepfloat, optional

Absolute finite-difference step on position, in km. Defaults to 1e-6 * max(|r_i|, 1) per component.

velocity_stepfloat, optional

Absolute finite-difference step on velocity, in km/s. Defaults to 1e-9 * max(|v_i|, 1) per component.

Attributes:
base_frame

Reference frame of the propagation, or None before binding.

depends_on_position

True when the acceleration is a function of position.

depends_on_velocity

True when the acceleration is a function of velocity.

dynamic_parameters

Declared parameters that carry their own equation of motion.

name

Identifier of the model within the force model aggregator.

origin

Central body of the propagation, or None before binding.

parameters

Declared solve-for parameters, keyed by name.

primary_body

Spacecraft the owning force model acts on, or None before binding.

Methods

compute_acceleration(position, ...)

Evaluate the user-supplied acceleration contribution.

See also

scarabaeus.CustomParameter

Declaration of an estimable custom parameter.

scarabaeus.ForceModelTranslation

Aggregator that hosts custom models.

scarabaeus.DynamicModel

Abstract base class of all force model components.

Notes

The model is bound to a concrete state and frame when the owning ForceModelTranslation is initialized by the Propagator. Build one instance per force model: sharing an instance between force models built on different spacecraft (e.g. a truth run and a filter reference) raises RebindError.

Accelerations must be returned in km/s^2 and positions/velocities are handed over in km and km/s — the internal units of the propagator.

Examples

An exponential-atmosphere drag force with an estimated drag coefficient:

import numpy as np
import scarabaeus as scb

cd = scb.CustomParameter("drag_cd", default=2.2)

def drag(position, velocity, params, spacecraft):
    h = np.linalg.norm(position) - 6378.0
    rho = 3.6e-4 * np.exp(-h / 88.667)          # kg/km**3
    area_over_mass = 1e-5                        # km**2/kg
    speed = np.linalg.norm(velocity)

    return -0.5 * params["drag_cd"][0] * area_over_mass * rho * speed * velocity

drag_model = scb.CustomDynamicModel("Drag", drag, parameters=[cd])

force_model = scb.ForceModelTranslation(
    primary_body=sc,
    custom_models=[drag_model],
)

The parameter is estimated by adding it to the state definition:

state_def = (scb.StateDefinition()
    .position(sc, pos_0)
    .velocity(sc, vel_0)
    .custom_param("drag_cd", sc, scb.ArrayWFrame(2.2, None, None))
)
compute_acceleration(position: ndarray, current_state: dict, epoch: float, body: CelestialBody) → ndarray#

Evaluate the user-supplied acceleration contribution.

Parameters:
positionnumpy.ndarray

3x1 position of the body relative to the central body, in kilometers.

current_statedict

Dictionary containing the current state parameters.

epochfloat

Current simulation epoch in seconds.

bodyCelestialBody

Body the acceleration acts on.

Returns:
numpy.ndarray

3x1 acceleration contribution, in \(\frac{km}{s^2}\).

property base_frame: Frame | None#

Reference frame of the propagation, or None before binding.

property depends_on_position: bool#

True when the acceleration is a function of position.

property depends_on_velocity: bool#

True when the acceleration is a function of velocity.

property dynamic_parameters: dict#

Declared parameters that carry their own equation of motion.

property name: str#

Identifier of the model within the force model aggregator.

property origin#

Central body of the propagation, or None before binding.

property parameters: dict#

Declared solve-for parameters, keyed by name.

property primary_body#

Spacecraft the owning force model acts on, or None before binding.

exception DuplicateParameterError#

Bases: ValueError

Raised when the same parameter name is declared twice by one model.

exception NotBoundError#

Bases: RuntimeError

Raised when the model is used before the force model initializes it.

exception RebindError#

Bases: RuntimeError

Raised when one model instance is shared between two different spacecraft.

exception ShapeError#

Bases: ValueError

Raised when a user callable returns an array of unexpected shape.