Icarus
Vehicle Simulation as a Transformable Computational Graph, built on Vulcan and Janus
Loading...
Searching...
No Matches
PhaseManager.hpp
Go to the documentation of this file.
1#pragma once
2
11
13#include <icarus/core/Error.hpp>
15
16#include <cstdint>
17#include <map>
18#include <optional>
19#include <string>
20#include <vector>
21
22namespace icarus {
23
28 int32_t from_phase = -1;
29 int32_t to_phase = 0;
30 std::string condition;
31
32 PhaseTransition() = default;
33 PhaseTransition(int32_t from, int32_t to, std::string cond)
34 : from_phase(from), to_phase(to), condition(std::move(cond)) {}
35};
36
42 std::map<std::string, int32_t> definitions;
43
45 std::string initial_phase;
46
48 std::vector<PhaseTransition> transitions;
49
51 std::string entity_prefix;
52
54 [[nodiscard]] std::optional<int32_t> GetPhaseValue(const std::string &name) const {
55 auto it = definitions.find(name);
56 if (it != definitions.end()) {
57 return it->second;
58 }
59 return std::nullopt;
60 }
61
63 [[nodiscard]] std::string GetPhaseName(int32_t value) const {
64 for (const auto &[name, val] : definitions) {
65 if (val == value) {
66 return name;
67 }
68 }
69 return "";
70 }
71};
72
100template <typename Scalar> class PhaseManager {
101 public:
102 PhaseManager() = default;
103
110 void Configure(const PhaseConfig &config) {
111 config_ = config;
112
113 // Validate and set initial phase
114 auto initial_value = config_.GetPhaseValue(config_.initial_phase);
115 if (!initial_value.has_value()) {
116 throw ConfigError("PhaseManager", "initial_phase '" + config_.initial_phase +
117 "' not found in definitions");
118 }
119 current_phase_ = *initial_value;
120 previous_phase_ = current_phase_;
121
122 // Pre-compile all transition conditions
124 compiled_conditions_.clear();
125 compiled_conditions_.reserve(config_.transitions.size());
126
127 for (size_t i = 0; i < config_.transitions.size(); ++i) {
128 const auto &trans = config_.transitions[i];
129 try {
130 compiled_conditions_.push_back(parser.Parse(trans.condition));
131 } catch (const ConditionError &e) {
132 throw ConfigError("PhaseManager", "invalid condition in transition " +
133 std::to_string(i) + ": " + e.what());
134 }
135 }
136
137 configured_ = true;
138 }
139
150 if (!configured_) {
151 return;
152 }
153
154 previous_phase_ = current_phase_;
155 phase_changed_ = false;
156
157 for (size_t i = 0; i < config_.transitions.size(); ++i) {
158 const auto &trans = config_.transitions[i];
159
160 // Check if transition applies to current phase
161 if (trans.from_phase != -1 && trans.from_phase != current_phase_) {
162 continue;
163 }
164
165 // Evaluate condition
166 try {
167 if (compiled_conditions_[i].Evaluate(registry)) {
168 // Transition fires
169 current_phase_ = trans.to_phase;
170 phase_changed_ = true;
171 break; // No cascade: stop after first transition
172 }
173 } catch (const SignalNotFoundError &) {
174 // Signal not found - condition cannot be evaluated
175 // Skip this transition silently (signal may not exist yet)
176 }
177 }
178 }
179
183 [[nodiscard]] int32_t CurrentPhase() const { return current_phase_; }
184
188 [[nodiscard]] std::string CurrentPhaseName() const {
189 return config_.GetPhaseName(current_phase_);
190 }
191
195 [[nodiscard]] int32_t PreviousPhase() const { return previous_phase_; }
196
200 [[nodiscard]] bool PhaseChangedThisStep() const { return phase_changed_; }
201
205 [[nodiscard]] bool IsConfigured() const { return configured_; }
206
212 [[nodiscard]] std::string GetPhaseSignalPath() const {
213 if (config_.entity_prefix.empty()) {
214 return "phase";
215 }
216 return config_.entity_prefix + ".phase";
217 }
218
222 [[nodiscard]] const PhaseConfig &GetConfig() const { return config_; }
223
227 void Reset() {
228 if (configured_) {
229 auto initial_value = config_.GetPhaseValue(config_.initial_phase);
230 if (initial_value.has_value()) {
231 current_phase_ = *initial_value;
232 previous_phase_ = current_phase_;
233 phase_changed_ = false;
234 }
235 }
236 }
237
244 void SetPhase(const std::string &phase_name) {
245 auto value = config_.GetPhaseValue(phase_name);
246 if (!value.has_value()) {
247 throw ConfigError("PhaseManager", "phase '" + phase_name + "' not found");
248 }
249 previous_phase_ = current_phase_;
250 current_phase_ = *value;
251 phase_changed_ = (current_phase_ != previous_phase_);
252 }
253
257 void SetPhaseValue(int32_t value) {
258 previous_phase_ = current_phase_;
259 current_phase_ = value;
260 phase_changed_ = (current_phase_ != previous_phase_);
261 }
262
263 private:
264 PhaseConfig config_;
265 std::vector<CompiledCondition<Scalar>> compiled_conditions_;
266
267 int32_t current_phase_ = 0;
268 int32_t previous_phase_ = 0;
269 bool phase_changed_ = false;
270 bool configured_ = false;
271};
272
273} // namespace icarus
Signal-based condition expression parser and evaluator.
Consolidated error handling for Icarus.
Signal Registry (Backplane) for Icarus.
Condition parsing and evaluation errors.
Definition Error.hpp:377
Parser for condition expressions.
Definition ConditionParser.hpp:411
CompiledCondition< Scalar > Parse(const std::string &condition)
Parse a condition string.
Definition ConditionParser.hpp:420
Configuration/parsing errors with optional file context.
Definition Error.hpp:185
std::string GetPhaseSignalPath() const
Get phase signal path for this entity.
Definition PhaseManager.hpp:212
void Reset()
Reset to initial phase.
Definition PhaseManager.hpp:227
std::string CurrentPhaseName() const
Get current phase name.
Definition PhaseManager.hpp:188
void SetPhaseValue(int32_t value)
Force set phase by value (for testing or initialization).
Definition PhaseManager.hpp:257
int32_t CurrentPhase() const
Get current phase value.
Definition PhaseManager.hpp:183
void SetPhase(const std::string &phase_name)
Force set phase (for testing or initialization).
Definition PhaseManager.hpp:244
int32_t PreviousPhase() const
Get previous phase value (before last EvaluateTransitions).
Definition PhaseManager.hpp:195
void EvaluateTransitions(const SignalRegistry< Scalar > &registry)
Evaluate transition conditions and potentially change phase.
Definition PhaseManager.hpp:149
const PhaseConfig & GetConfig() const
Get the phase configuration.
Definition PhaseManager.hpp:222
bool PhaseChangedThisStep() const
Check if phase changed in last EvaluateTransitions call.
Definition PhaseManager.hpp:200
void Configure(const PhaseConfig &config)
Configure phase manager with phase definitions and transitions.
Definition PhaseManager.hpp:110
bool IsConfigured() const
Check if phase manager is configured.
Definition PhaseManager.hpp:205
Definition Error.hpp:456
Central registry for all simulation signals.
Definition Registry.hpp:37
Definition AggregationTypes.hpp:13
Configuration for phase management.
Definition PhaseManager.hpp:40
std::vector< PhaseTransition > transitions
Transition rules.
Definition PhaseManager.hpp:48
std::optional< int32_t > GetPhaseValue(const std::string &name) const
Get phase integer from name, or nullopt if not found.
Definition PhaseManager.hpp:54
std::map< std::string, int32_t > definitions
Phase name to integer mapping (e.g., {"GROUND": 0, "BOOST": 1, ...}).
Definition PhaseManager.hpp:42
std::string entity_prefix
Entity prefix for phase signal (e.g., "Vehicle" -> "Vehicle.phase").
Definition PhaseManager.hpp:51
std::string GetPhaseName(int32_t value) const
Get phase name from integer, or empty string if not found.
Definition PhaseManager.hpp:63
std::string initial_phase
Initial phase name.
Definition PhaseManager.hpp:45
std::string condition
Condition expression (e.g., "fuel_mass < 0.01").
Definition PhaseManager.hpp:30
int32_t from_phase
Source phase (-1 = any phase).
Definition PhaseManager.hpp:28
int32_t to_phase
Destination phase.
Definition PhaseManager.hpp:29
PhaseTransition(int32_t from, int32_t to, std::string cond)
Definition PhaseManager.hpp:33