Icarus
Vehicle Simulation as a Transformable Computational Graph, built on Vulcan and Janus
Loading...
Searching...
No Matches
SymbolicSimulatorCore.hpp
Go to the documentation of this file.
1#pragma once
2
12
17#include <icarus/core/Error.hpp>
23
24#include <janus/core/JanusTypes.hpp>
25
26#include <algorithm>
27#include <memory>
28#include <string>
29#include <unordered_map>
30#include <vector>
31
32namespace icarus::staging {
33
49 public:
50 using Scalar = janus::SymbolicScalar;
51
61 explicit SymbolicSimulatorCore(const SimulatorConfig &config)
62 : config_(config), backplane_(registry_) {
63 CreateComponents();
64 ProvisionComponents();
65 ApplyRouting();
66 AllocateState();
67 StageComponents();
68 }
69
70 // =========================================================================
71 // State Access
72 // =========================================================================
73
80 void SetState(const JanusVector<Scalar> &x) {
81 if (x.size() != state_manager_.GetState().size()) {
82 throw std::invalid_argument("SymbolicSimulatorCore::SetState: size mismatch");
83 }
84 state_manager_.SetState(x);
85 }
86
90 void SetTime(Scalar t) { time_ = t; }
91
101 JanusVector<Scalar> ComputeDerivatives() {
102 state_manager_.ZeroDerivatives();
103
104 Scalar dt = Scalar(config_.dt);
105
106 // Build execution order based on scheduler priority
107 // Components with lower priority values run first
108 std::vector<Component<Scalar> *> exec_order;
109 exec_order.reserve(components_.size());
110
111 // Build component priority map from scheduler config
112 std::unordered_map<std::string, int> priority_map;
113 for (const auto &group : config_.scheduler.groups) {
114 for (const auto &member : group.members) {
115 priority_map[member.component] = group.priority;
116 }
117 }
118
119 // Copy component pointers and sort by priority
120 for (auto &comp : components_) {
121 exec_order.push_back(comp.get());
122 }
123 std::stable_sort(
124 exec_order.begin(), exec_order.end(),
125 [&priority_map](Component<Scalar> *a, Component<Scalar> *b) {
126 int pa = priority_map.count(a->FullName()) ? priority_map[a->FullName()]
127 : 1000; // Default high priority
128 int pb = priority_map.count(b->FullName()) ? priority_map[b->FullName()] : 1000;
129 return pa < pb;
130 });
131
132 // Execute in priority order
133 for (auto *comp : exec_order) {
134 comp->PreStep(time_, dt);
135 }
136 for (auto *comp : exec_order) {
137 comp->Step(time_, dt);
138 }
139 for (auto *comp : exec_order) {
140 comp->PostStep(time_, dt);
141 }
142
143 return state_manager_.GetDerivatives();
144 }
145
149 [[nodiscard]] std::size_t GetStateSize() const { return state_manager_.TotalSize(); }
150
154 [[nodiscard]] JanusVector<Scalar> GetState() const { return state_manager_.GetState(); }
155
159 [[nodiscard]] JanusVector<Scalar> GetDerivatives() const {
160 return state_manager_.GetDerivatives();
161 }
162
163 // =========================================================================
164 // Signal Access
165 // =========================================================================
166
170 [[nodiscard]] Scalar GetSignal(const std::string &name) const {
171 return registry_.GetByName(name);
172 }
173
177 void SetSignal(const std::string &name, Scalar value) { registry_.SetByName(name, value); }
178
182 [[nodiscard]] bool HasSignal(const std::string &name) const {
183 return registry_.HasSignal(name);
184 }
185
189 [[nodiscard]] std::vector<std::string> GetSignalNames() const {
190 return registry_.get_all_signal_names();
191 }
192
196 [[nodiscard]] const std::vector<StateBinding<Scalar>> &GetStateBindings() const {
197 return state_manager_.GetBindings();
198 }
199
203 [[nodiscard]] Component<Scalar> *GetComponent(const std::string &name) const {
204 for (const auto &comp : components_) {
205 if (comp->FullName() == name) {
206 return comp.get();
207 }
208 }
209 return nullptr;
210 }
211
215 [[nodiscard]] std::size_t NumComponents() const { return components_.size(); }
216
217 private:
218 // =========================================================================
219 // Private Methods
220 // =========================================================================
221
222 void CreateComponents() {
223 auto &factory = ComponentFactory<Scalar>::Instance();
224
225 for (const auto &comp_cfg : config_.components) {
226 if (!factory.HasType(comp_cfg.type)) {
227 throw ConfigError("SymbolicSimulatorCore: No symbolic registration for component "
228 "type '" +
229 comp_cfg.type +
230 "'. "
231 "Ensure component uses ICARUS_REGISTER_COMPONENT macro.");
232 }
233 auto component = factory.Create(comp_cfg);
234 components_.push_back(std::move(component));
235 }
236 }
237
238 void ProvisionComponents() {
239 for (auto &comp : components_) {
240 backplane_.set_context(comp->Entity(), comp->Name());
241 backplane_.clear_tracking();
242 comp->Provision(backplane_);
243 // Component marks itself as provisioned internally
244 backplane_.clear_context();
245 }
246 }
247
248 void ApplyRouting() {
249 for (const auto &route : config_.routes) {
250 router_.AddRoute(route);
251 }
252 router_.ApplyRoutes(backplane_);
253 }
254
255 void AllocateState() {
256 // Phase 6: Discover states from registry instead of scanning components
257 state_manager_.DiscoverStates(registry_);
258 }
259
260 void StageComponents() {
261 for (auto &comp : components_) {
262 backplane_.set_context(comp->Entity(), comp->Name());
263 backplane_.clear_tracking();
264 comp->Stage(backplane_);
265 // Component marks itself as staged internally
266 backplane_.clear_context();
267 }
268 }
269
270 // =========================================================================
271 // Private Data
272 // =========================================================================
273
274 SimulatorConfig config_;
275
276 // Components
277 std::vector<std::unique_ptr<Component<Scalar>>> components_;
278
279 // Signal system
280 SignalRegistry<Scalar> registry_;
281 Backplane<Scalar> backplane_;
282 signal::SignalRouter<Scalar> router_;
283
284 // State management
285 StateManager<Scalar> state_manager_;
286
287 // Time
288 Scalar time_{0.0};
289};
290
291} // namespace icarus::staging
Component-facing facade for signal registration and resolution.
Configuration container for components with typed accessors.
Factory for creating components from configuration.
Base class for all simulation components.
Core type definitions, concepts, and configuration for Icarus.
Consolidated error handling for Icarus.
Signal Registry (Backplane) for Icarus.
Centralized signal routing configuration.
Simulator and subsystem configuration structs.
Manages state integration via unified signal model.
static ComponentFactory & Instance()
Get singleton instance.
Definition ComponentFactory.hpp:109
Base class for all simulation components.
Definition Component.hpp:47
Configuration/parsing errors with optional file context.
Definition Error.hpp:185
JanusVector< Scalar > ComputeDerivatives()
Compute derivatives symbolically.
Definition SymbolicSimulatorCore.hpp:101
void SetTime(Scalar t)
Set time (symbolic).
Definition SymbolicSimulatorCore.hpp:90
JanusVector< Scalar > GetDerivatives() const
Get derivative vector (after ComputeDerivatives).
Definition SymbolicSimulatorCore.hpp:159
Component< Scalar > * GetComponent(const std::string &name) const
Get component by name.
Definition SymbolicSimulatorCore.hpp:203
bool HasSignal(const std::string &name) const
Check if signal exists.
Definition SymbolicSimulatorCore.hpp:182
const std::vector< StateBinding< Scalar > > & GetStateBindings() const
Get state bindings (for introspection).
Definition SymbolicSimulatorCore.hpp:196
void SetState(const JanusVector< Scalar > &x)
Set state vector (symbolic).
Definition SymbolicSimulatorCore.hpp:80
std::vector< std::string > GetSignalNames() const
Get all registered signal names.
Definition SymbolicSimulatorCore.hpp:189
void SetSignal(const std::string &name, Scalar value)
Write signal value (symbolic).
Definition SymbolicSimulatorCore.hpp:177
Scalar GetSignal(const std::string &name) const
Read signal value (symbolic).
Definition SymbolicSimulatorCore.hpp:170
std::size_t GetStateSize() const
Get total state size.
Definition SymbolicSimulatorCore.hpp:149
janus::SymbolicScalar Scalar
Definition SymbolicSimulatorCore.hpp:50
JanusVector< Scalar > GetState() const
Get current state vector (copy).
Definition SymbolicSimulatorCore.hpp:154
SymbolicSimulatorCore(const SimulatorConfig &config)
Create from simulator config.
Definition SymbolicSimulatorCore.hpp:61
std::size_t NumComponents() const
Get number of components.
Definition SymbolicSimulatorCore.hpp:215
Definition Simulator.hpp:53
Complete simulation configuration.
Definition SimulatorConfig.hpp:673
std::vector< ComponentConfig > components
Definition SimulatorConfig.hpp:696