C++ Module: dynamicObject

DynamicObject is the base for models whose continuous states are integrated, including spacecraft and MuJoCo scenes. It owns a DynParamManager and an integrator, coordinates synchronized objects, and provides drift, diffusion, pre-integration, and post-integration extension hooks.

Subclass responsibilities

Reset() declares and initializes states, calls finalizeStates(), and finishes model setup. Later resets reuse those states and update values directly. An initialization exception may leave partial values; complete setup successfully before integrating.

UpdateState() normally delegates propagation to integrateState(). The subclass defines equationsOfMotion() and, for stochastic models, equationsOfMotionDiffusion(). These callbacks read candidate states and write derivatives or noise tangents. They may run several times within one requested interval.

preIntegration() and postIntegration() perform model-specific work around the integrator call. Configure topology and synchronization before the first integration step. Callbacks must not change ownership, destroy participating objects, or replace the integrator.

Synchronization and ownership

syncDynamicsIntegration() adds another object to the primary object’s integration group before binding. The primary owns the group’s integrator. setIntegrator() transfers the dynamics list and destroys the old numerical method; borrowed pointers to it expire. Both setIntegrator(method) and Python integrator = method transfer ownership of a new method, including when it is rejected. Reinstalling the active method is a no-op. Keep the dynamics object alive while using its borrowed manager or integrator.

Python retains synchronized secondaries. Native connections are detached when either object is destroyed. A surviving primary rebuilds its workspace before the next step; a surviving secondary resumes independent integration. Repeating an existing connection is a no-op.

See Creating DynamicObject Basilisk Modules for a Reset example and Dynamics state and integrator architecture for the storage and workspace design.


Model lifecycle, synchronized integration, and protected dynamics extension hooks.

class DynamicObject : public SysModel
#include <dynamicObject.h>

A model that owns continuous states and coordinates their integration.

Reset registers and initializes states, then calls DynParamManager::finalizeStates(). Dynamics callbacks write drift and diffusion; the integrator advances the values in fixed contiguous storage. One primary object can integrate several synchronized objects. Configure this group before its first step. Python retains synchronized secondaries; native connections are detached when either object is destroyed. Reset and integration exceptions propagate to callers.

Public Functions

DynamicObject() = default
DynamicObject(const DynamicObject&) = delete
DynamicObject &operator=(const DynamicObject&) = delete
DynamicObject(DynamicObject&&) = delete
DynamicObject &operator=(DynamicObject&&) = delete
virtual ~DynamicObject()
virtual void UpdateState(uint64_t callTime) = 0

Hooks the dyn-object into Basilisk architecture

virtual void equationsOfMotion(double t, double timeStep) = 0

Computes the time derivative of the states:

\[ dx = f(t,x)\,dt \]

equationsOfMotion computes \(f(t,x)\) in the equation above.

inline virtual void equationsOfMotionDiffusion(double t, double timeStep)

Computes the diffusion of the states:

\[ dx = f(t,x)\,dt + g_0(t,x)\,dW_0 + g_1(t,x)\,dW_1 + \cdots + g_{n-1}(t,x)\,dW_{n-1} \]

equationsOfMotionDiffusion is equivalent to evaluating \(g_0(t,x), g_1(t,x), \ldots, g_{n-1}(t,x)\) in the equation above.

Note that not all DynamicObjects may support this functionality.

virtual void preIntegration(uint64_t callTimeNanos) = 0

Performs pre-integration steps

virtual void postIntegration(uint64_t callTimeNanos) = 0

Performs post-integration steps

inline virtual void computeEnergyMomentum(double t)

Computes energy and momentum of the system

void integrateState(uint64_t t)

Prepares the dynamic object to be integrated, integrates the states forward in time, and finally performs the post-integration steps.

This is only done if the DynamicObject integration is not sync’d to another DynamicObject

void setIntegrator(std::unique_ptr<StateVecIntegrator> newIntegrator)

Take exclusive ownership of a replacement integrator from C++.

Note

Ownership is consumed even when the replacement is rejected. A null pointer or an integrator with missing or mismatched dynamics raises BasiliskError. A synchronized secondary instead logs a warning and discards the replacement. The current integrator remains installed in each rejection case.

Note

Replacing a primary’s integrator preserves its synchronized dynamics and invalidates borrowed pointers to the previous integrator.

Parameters:

newIntegrator – Owning pointer to an integrator constructed for this dynamics object.

void setIntegrator(StateVecIntegrator *newIntegrator)

Transfer a raw integrator pointer through the Python and compatibility interface.

Note

A newly supplied integrator is destroyed if it is rejected. Passing the active integrator again is a no-op. C++ callers must not pass an integrator owned by another object; prefer the unique_ptr overload for new integrators.

Parameters:

newIntegrator – Integrator constructed for this dynamics object, with ownership available for transfer, or its currently active integrator.

StateVecIntegrator *getIntegrator() const noexcept

Borrow the active integrator until its replacement or this object’s destruction.

Returns:

Active integrator, or nullptr if no integrator has been installed.

void syncDynamicsIntegration(DynamicObject *dynPtr)

Integrate another dynamics object with this object’s numerical method.

Note

Repeating an existing connection is a no-op. Configure new connections before the first integration step and outside dynamics callbacks. Python calls require an owning primary proxy and retain the supplied secondary for its lifetime. Borrowed primary proxies are rejected before creating a connection. Native connections are removed during destruction.

Parameters:

dynPtr – Secondary object; must be independent, non-null, and different from this object.

DynamicObject *getIntegrationOwner() const noexcept

Borrow the primary object, or return nullptr for independent integration.

Note

The returned pointer does not retain the primary.

Public Members

DynParamManager dynManager

Dynamics parameter manager for all effectors

BSKLogger bskLogger

BSK Logging

double timeStep = 0.0

[s] integration time step

double timeBefore = 0.0

[s] prior time value

uint64_t timeBeforeNanos = 0

[ns] prior time value

Protected Functions

void requireMutableTopology(const char *operation) const

Reject changes that would invalidate the fixed state layout.

Private Members

std::unique_ptr<StateVecIntegrator> integrator

Owned numerical method and workspaces.

DynamicObject *integrationOwner = nullptr

Borrowed primary object, or null for independent integration.

Friends

friend class StateVecIntegrator