Icarus
Vehicle Simulation as a Transformable Computational Graph, built on Vulcan and Janus
Loading...
Searching...
No Matches
StateManager.hpp
Go to the documentation of this file.
1#pragma once
2
15
18
19#include <cstddef>
20#include <string>
21#include <unordered_set>
22#include <vector>
23
24namespace icarus {
25
26// =============================================================================
27// StateBinding (Phase 6)
28// =============================================================================
29
35template <typename Scalar> struct StateBinding {
36 std::string name;
37 std::string component_name;
38 Scalar *value_ptr = nullptr;
39 Scalar *derivative_ptr = nullptr;
40};
41
42// =============================================================================
43// StateManager (Phase 6: Unified Signal Model)
44// =============================================================================
45
55template <typename Scalar> class StateManager {
56 public:
57 StateManager() = default;
58
67 void DiscoverStates(const SignalRegistry<Scalar> &registry) {
68 bindings_.clear();
69
70 // Get all state pairs from the registry
71 const auto &pairs = registry.get_state_pairs();
72
73 for (const auto &pair : pairs) {
75 binding.name = pair.value_name;
76 binding.component_name = ExtractComponentName(pair.value_name);
77 binding.value_ptr = static_cast<Scalar *>(pair.value_ptr);
78 binding.derivative_ptr = static_cast<Scalar *>(pair.derivative_ptr);
79 bindings_.push_back(binding);
80 }
81
82 discovered_ = true;
83 }
84
91 for (auto &binding : bindings_) {
92 *binding.derivative_ptr = Scalar{0};
93 }
94 }
95
99 [[nodiscard]] std::size_t TotalSize() const { return bindings_.size(); }
100
106 [[nodiscard]] JanusVector<Scalar> GetState() const {
107 JanusVector<Scalar> X(static_cast<Eigen::Index>(bindings_.size()));
108 for (std::size_t i = 0; i < bindings_.size(); ++i) {
109 X(static_cast<Eigen::Index>(i)) = *bindings_[i].value_ptr;
110 }
111 return X;
112 }
113
121 void SetState(const JanusVector<Scalar> &X) {
122 if (static_cast<std::size_t>(X.size()) != bindings_.size()) {
123 throw std::invalid_argument("State vector size mismatch: expected " +
124 std::to_string(bindings_.size()) + ", got " +
125 std::to_string(X.size()));
126 }
127 for (std::size_t i = 0; i < bindings_.size(); ++i) {
128 *bindings_[i].value_ptr = X(static_cast<Eigen::Index>(i));
129 }
130 }
131
137 [[nodiscard]] JanusVector<Scalar> GetDerivatives() const {
138 JanusVector<Scalar> X_dot(static_cast<Eigen::Index>(bindings_.size()));
139 for (std::size_t i = 0; i < bindings_.size(); ++i) {
140 X_dot(static_cast<Eigen::Index>(i)) = *bindings_[i].derivative_ptr;
141 }
142 return X_dot;
143 }
144
155 [[nodiscard]] JanusVector<Scalar>
156 GetDerivatives(const std::unordered_set<std::string> &active_components) const {
157 JanusVector<Scalar> X_dot(static_cast<Eigen::Index>(bindings_.size()));
158 for (std::size_t i = 0; i < bindings_.size(); ++i) {
159 bool is_active = active_components.empty() ||
160 active_components.contains(bindings_[i].component_name);
161 if (is_active) {
162 X_dot(static_cast<Eigen::Index>(i)) = *bindings_[i].derivative_ptr;
163 } else {
164 X_dot(static_cast<Eigen::Index>(i)) = Scalar{0}; // Freeze state
165 }
166 }
167 return X_dot;
168 }
169
173 [[nodiscard]] const std::vector<StateBinding<Scalar>> &GetBindings() const { return bindings_; }
174
178 [[nodiscard]] bool IsAllocated() const { return discovered_; }
179
180 private:
181 std::vector<StateBinding<Scalar>> bindings_;
182 bool discovered_ = false;
183
193 [[nodiscard]] static std::string ExtractComponentName(const std::string &signal_name) {
194 // Signal name format: "Entity.Component.signal" or "Entity.Component.signal.axis"
195 // We need to extract "Entity.Component" for scheduler matching
196 // e.g., "Rocket.FuelTank.fuel_mass" -> "Rocket.FuelTank"
197 auto first_dot = signal_name.find('.');
198 if (first_dot == std::string::npos) {
199 return signal_name; // No dot, entire name is component
200 }
201 auto second_dot = signal_name.find('.', first_dot + 1);
202 if (second_dot == std::string::npos) {
203 return signal_name.substr(0, first_dot); // Only one dot
204 }
205 return signal_name.substr(0, second_dot);
206 }
207};
208
209} // namespace icarus
Core type definitions, concepts, and configuration for Icarus.
Signal Registry (Backplane) for Icarus.
Central registry for all simulation signals.
Definition Registry.hpp:37
const auto & get_state_pairs() const
Get all integrable state pairs.
Definition Registry.hpp:268
std::size_t TotalSize() const
Get total state vector size.
Definition StateManager.hpp:99
void ZeroDerivatives()
Zero all derivatives.
Definition StateManager.hpp:90
JanusVector< Scalar > GetDerivatives(const std::unordered_set< std::string > &active_components) const
Get derivatives with phase-based gating.
Definition StateManager.hpp:156
bool IsAllocated() const
Check if states have been discovered.
Definition StateManager.hpp:178
void SetState(const JanusVector< Scalar > &X)
Set state from external vector.
Definition StateManager.hpp:121
void DiscoverStates(const SignalRegistry< Scalar > &registry)
Discover integrable states from the registry.
Definition StateManager.hpp:67
JanusVector< Scalar > GetDerivatives() const
Get copy of current derivatives as a vector.
Definition StateManager.hpp:137
JanusVector< Scalar > GetState() const
Get copy of current state as a vector.
Definition StateManager.hpp:106
const std::vector< StateBinding< Scalar > > & GetBindings() const
Get state bindings (for introspection).
Definition StateManager.hpp:173
Definition AggregationTypes.hpp:13
Binding to a single scalar state value and its derivative.
Definition StateManager.hpp:35
std::string component_name
Owning component name (e.g., "Vehicle.Body").
Definition StateManager.hpp:37
Scalar * value_ptr
Pointer to state value.
Definition StateManager.hpp:38
Scalar * derivative_ptr
Pointer to derivative.
Definition StateManager.hpp:39
std::string name
Signal name (for debugging).
Definition StateManager.hpp:36