OpenSWMM Engine  6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
Controls.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2//
3// Copyright 2026 Caleb Buahin
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
36
45
46#ifndef OPENSWMM_CONTROLS_HPP
47#define OPENSWMM_CONTROLS_HPP
48
49#include <cstdint>
50#include <vector>
51#include <string>
52#include <unordered_map>
54#include "../math/MathExpr.hpp"
55
56namespace openswmm {
57
59class SWMMEngine;
60
61namespace controls {
62
63// ============================================================================
64// Comparison and logic operators
65// ============================================================================
66
67enum class CompareOp : int { EQ = 0, NE = 1, LT = 2, LE = 3, GT = 4, GE = 5 };
68enum class LogicOp : int { AND = 0, OR = 1 };
69
70// ============================================================================
71// Condition variable types (matching ALL legacy RuleAttrib values)
72// ============================================================================
73
74enum class ConditionVar : int {
75 // Node attributes
81
82 // Link attributes
94
95 // Gage attributes
96 GAGE_RAIN = 30,
98
99 // System / time
103 SIM_DAY = 43,
106};
107
108// ============================================================================
109// Action attribute (what is being set on the link)
110// ============================================================================
111
112enum class ActionType : int {
114 CURVE = 1,
116 PID = 3
117};
118
119// ============================================================================
120// Rule premise (condition)
121// ============================================================================
122
140
141// ============================================================================
142// Rule action
143// ============================================================================
144
145struct Action {
146 int link_idx = -1;
147 int rule_idx = -1;
149 double value = 0.0;
150 int curve_idx = -1;
151 int tseries_idx = -1;
152 int pid_idx = -1;
153};
154
155// ============================================================================
156// PID controller state (per action)
157// ============================================================================
158
159struct PIDState {
160 double kp = 0.0;
161 double ki = 0.0;
162 double kd = 0.0;
163 double setpoint = 0.0;
164 double e1 = 0.0;
165 double e2 = 0.0;
166 int action_idx = -1;
167};
168
169// ============================================================================
170// Named variable (for rule expressions)
171// ============================================================================
172
174 std::string name;
176 int idx = -1;
177 int param = 0;
178};
179
180// ============================================================================
181// Control rule
182// ============================================================================
183
184struct Rule {
185 std::string name;
186 std::vector<Premise> premises;
187 std::vector<Action> then_actions;
188 std::vector<Action> else_actions;
189 double priority = 0.0;
190};
191
192// ============================================================================
193// Control engine
194// ============================================================================
195
205 int line = -1;
206 std::string message;
207 int code = 0;
208 std::string token;
209};
210
217public:
224 void init(const std::vector<Rule>& rules);
225
245 int evaluate(SimulationContext& ctx, double current_date, double dt,
246 bool rule_time_reached = true);
247
248 // Rule parsing (from [CONTROLS] text)
262 int parseRuleText(const std::string& text, SimulationContext& ctx);
263
268 const ParseError& lastParseError() const noexcept { return last_parse_error_; }
269
274 void clearRules();
275
276 // Named variables
283 void addNamedVariable(const std::string& name, ConditionVar var, int idx, int param = 0);
284
285 // Math expressions
292 int addExpression(const std::string& name, const std::string& formula);
293
298 std::vector<Rule>& rules() { return rules_; }
299
303 int lastActionCount() const { return last_action_count_; }
304
305 // ========================================================================
306 // SoA batch evaluation index (AD-14)
307 // ========================================================================
308
324 struct PremiseSoA {
326 int count = 0;
327
328 // Per-premise SoA (contiguous, aligned for SIMD)
329 std::vector<int> rule_idx;
330 std::vector<int> premise_idx;
331 std::vector<int> obj_idx;
332 std::vector<int> param;
333 std::vector<int> flat_idx;
334 std::vector<int> op;
335 std::vector<double> rhs_value;
336
337 // Per-premise flags
338 std::vector<bool> rhs_is_variable;
339 std::vector<bool> is_expression;
340
341 // Working buffer (reused each evaluate call)
342 std::vector<double> lhs_values;
343 std::vector<bool> results;
344 };
345
351 void buildPremiseSoA();
352
363 void batchEvaluateGroup(PremiseSoA& group, const SimulationContext& ctx, double current_time,
364 double half_step);
365
366private:
368 int last_action_count_ = 0;
369 std::vector<Rule> rules_;
370 std::vector<PIDState> pid_states_;
371 std::vector<NamedVariable> named_vars_;
372 std::vector<mathexpr::Expression> expressions_;
374 std::unordered_map<std::string, int, CiHash, CiEqual> expr_index_;
375 ParseError last_parse_error_;
376
377 // SoA premise groups (one per variable type that has premises)
378 std::vector<PremiseSoA> premise_groups_;
379
380 // ------------------------------------------------------------------
381 // Two-phase evaluator state (§7 of CONTROL_RULES_LEGACY_PARITY_AUDIT)
382 // ------------------------------------------------------------------
383 // Phase 1 batch-evaluates premises (group-major) into the flat cache.
384 // Phase 2 walks each rule's premises in declaration order and applies
385 // legacy AND/OR semantics by reading the flat cache.
386 //
387 // Layout: premise_results_[ rule_premise_offset_[r] + p ] holds the
388 // result of rule r's premise p. uint8_t (not bool) so Phase 1's
389 // compare loops remain SIMD-writable.
390
391 std::vector<uint8_t> premise_results_;
392 std::vector<int> rule_premise_offset_;
393 int total_premises_ = 0;
394
395 // Per-rule premise result tracking (for combining AND/OR)
396 std::vector<bool> rule_results_;
397
398 // TIMEOPEN/TIMECLOSED tracking: when each link's setting last changed.
399 // Stored as absolute date (decimal days) matching legacy Link[j].timeLastSet.
400 // Step 6 of the parity remediation will move this to ctx.links.time_last_set.
401 std::vector<double> link_time_last_set_;
402
403 // Tracked across a single evaluate() call
404 double control_value_ = 0.0;
405 double set_point_ = 0.0;
409 double eval_date_ = 0.0;
410 double cur_date_ = 0.0;
411 double cur_time_ = 0.0;
412 double elapsed_days_ = 0.0;
413
414 // Pending action list (for priority deduplication)
415 struct PendingAction {
416 int link_idx;
417 double value;
418 double priority;
419 int rule_idx;
421 };
422 std::vector<PendingAction> pending_actions_;
427 std::vector<int> action_slots_;
428
442 double getVariableValue(const SimulationContext& ctx, ConditionVar var, int idx,
443 double current_time, int param = 0) const;
444
454 bool evaluatePremise(const SimulationContext& ctx, const Premise& p, double current_time,
455 double half_step);
456
462 bool compareValues(double lhs, CompareOp op, double rhs) const;
470 bool compareTimes(double lhs, CompareOp op, double rhs, double half_step) const;
471
483 double computePIDSetting(PIDState& pid, double control_value, double current_setting,
484 bool is_pump, double dt);
485
494 void updateActionValue(Action& a, SimulationContext& ctx, double current_time, double dt);
495
504 int applyPendingActions(SimulationContext& ctx, double current_time);
505
512 double getNamedVariableValue(const std::string& name, const SimulationContext& ctx,
513 double current_time) const;
514};
515
516} // namespace controls
517} // namespace openswmm
518
519#endif // OPENSWMM_CONTROLS_HPP
Mathematical expression parser and evaluator.
Case-insensitive string helpers matching legacy SWMM name semantics.
Mutable compiled control rules and per-action PID history. Use one owning simulation thread....
Definition Controls.hpp:216
void clearRules()
Discard rules, PID/named-expression state, caches and parser diagnostic. Use before recompiling a com...
Definition Controls.cpp:1170
int parseRuleText(const std::string &text, SimulationContext &ctx)
Append rules, named variables and expressions from control-section text.
Definition Controls.cpp:1186
std::vector< Rule > & rules()
Borrow the mutable compiled rule sequence.
Definition Controls.hpp:298
void buildPremiseSoA()
Rebuild flattened premise offsets, variable-type groups and work buffers. Call after any premise/rule...
Definition Controls.cpp:68
int addExpression(const std::string &name, const std::string &formula)
Parse and register a named arithmetic expression.
Definition Controls.cpp:736
const ParseError & lastParseError() const noexcept
Borrow the most recent parser diagnostic without clearing it.
Definition Controls.hpp:268
void init(const std::vector< Rule > &rules)
Copy compiled rules, reindex actions and rebuild premise caches.
Definition Controls.cpp:49
int lastActionCount() const
Read the target-change count of the last returned evaluate() call.
Definition Controls.hpp:303
void addNamedVariable(const std::string &name, ConditionVar var, int idx, int param=0)
Append a named binding without resolving or validating its object.
Definition Controls.cpp:731
friend class openswmm::SWMMEngine
Definition Controls.hpp:367
void batchEvaluateGroup(PremiseSoA &group, const SimulationContext &ctx, double current_time, double half_step)
Gather and compare one homogeneous ordinary-variable premise group.
Definition Controls.cpp:152
int evaluate(SimulationContext &ctx, double current_date, double dt, bool rule_time_reached=true)
Evaluate premises, arbitrate actions and update link target settings.
Definition Controls.cpp:200
int compareValues(double lhsValue, int relation, double rhsValue)
Compares two values.
Definition controls.c:1879
int compareTimes(double lhsValue, int relation, double rhsValue, double halfStep)
Compares two times.
Definition controls.c:1858
int evaluatePremise(struct TPremise *p, double tStep)
Evaluates premise clause of a control rule.
Definition controls.c:1671
void updateActionValue(struct TAction *a, DateTime currentTime, double dt)
Updates the value of a control action.
Definition controls.c:1527
double getNamedVariableValue(int varIndex)
Gets named variable value.
Definition controls.c:1007
double getVariableValue(struct TVariable v)
Gets the value of a variable.
Definition controls.c:1712
Definition Controls.cpp:47
ConditionVar
Definition Controls.hpp:74
@ LINK_TIMECLOSED
Definition Controls.hpp:93
@ SIM_TIME
Definition Controls.hpp:100
@ LINK_FULLFLOW
Definition Controls.hpp:87
@ CLOCK_TIME
Definition Controls.hpp:102
@ GAGE_RAIN_PAST
Past n-hours rainfall (n stored in parameter field)
Definition Controls.hpp:97
@ NODE_INFLOW
Definition Controls.hpp:80
@ LINK_FULLDEPTH
Definition Controls.hpp:88
@ LINK_STATUS
Definition Controls.hpp:86
@ LINK_VELOCITY
Definition Controls.hpp:89
@ NODE_VOLUME
Definition Controls.hpp:79
@ NODE_DEPTH
Definition Controls.hpp:76
@ LINK_DEPTH
Definition Controls.hpp:84
@ NODE_MAXDEPTH
Definition Controls.hpp:77
@ SIM_MONTH
Month (1-12)
Definition Controls.hpp:104
@ LINK_SETTING
Definition Controls.hpp:85
@ SIM_DATE
Definition Controls.hpp:101
@ LINK_TIMEOPEN
Definition Controls.hpp:92
@ NODE_HEAD
Definition Controls.hpp:78
@ GAGE_RAIN
Current rainfall intensity.
Definition Controls.hpp:96
@ LINK_LENGTH
Definition Controls.hpp:90
@ LINK_SLOPE
Definition Controls.hpp:91
@ SIM_DAYOFYEAR
Day of year (1-365)
Definition Controls.hpp:105
@ LINK_FLOW
Definition Controls.hpp:83
@ SIM_DAY
Day of week (1-7, Sun=1)
Definition Controls.hpp:103
LogicOp
Definition Controls.hpp:68
@ OR
Definition Controls.hpp:68
@ AND
Definition Controls.hpp:68
CompareOp
Definition Controls.hpp:67
@ EQ
Definition Controls.hpp:67
@ LT
Definition Controls.hpp:67
@ GT
Definition Controls.hpp:67
@ LE
Definition Controls.hpp:67
@ NE
Definition Controls.hpp:67
@ GE
Definition Controls.hpp:67
ActionType
Definition Controls.hpp:112
@ CURVE
Setting from curve lookup(ControlValue)
Definition Controls.hpp:114
@ PID
PID controller output.
Definition Controls.hpp:116
@ TIMESERIES
Setting from timeseries lookup(currentTime)
Definition Controls.hpp:115
@ NUMERIC
Direct numeric setting value.
Definition Controls.hpp:113
Definition ExchangeLaw.hpp:60
Central, reentrant simulation context.
Definition SimulationContext.hpp:390
Definition Controls.hpp:145
int rule_idx
Parent rule index (for priority lookup)
Definition Controls.hpp:147
int link_idx
Link being controlled.
Definition Controls.hpp:146
ActionType type
Definition Controls.hpp:148
int curve_idx
Curve index (for CURVE type)
Definition Controls.hpp:150
int pid_idx
PID state index (for PID type)
Definition Controls.hpp:152
double value
Direct value or computed result.
Definition Controls.hpp:149
int tseries_idx
Timeseries index (for TIMESERIES type)
Definition Controls.hpp:151
Pre-sorted premise index for batch evaluation.
Definition Controls.hpp:324
ConditionVar var_type
All premises in this group test this variable.
Definition Controls.hpp:325
std::vector< bool > rhs_is_variable
True if RHS is a variable (not batch-able)
Definition Controls.hpp:338
std::vector< int > premise_idx
Position within the rule's premise list.
Definition Controls.hpp:330
std::vector< int > flat_idx
Position in flat premise_results_ cache.
Definition Controls.hpp:333
std::vector< int > op
CompareOp as int.
Definition Controls.hpp:334
std::vector< bool > results
Comparison results.
Definition Controls.hpp:343
std::vector< bool > is_expression
True if LHS is an expression.
Definition Controls.hpp:339
std::vector< double > rhs_value
RHS threshold value.
Definition Controls.hpp:335
std::vector< double > lhs_values
Gathered LHS values.
Definition Controls.hpp:342
std::vector< int > param
Requested gage history hours.
Definition Controls.hpp:332
std::vector< int > obj_idx
Object index (node/link/gage)
Definition Controls.hpp:331
std::vector< int > rule_idx
Which rule this premise belongs to.
Definition Controls.hpp:329
int count
Definition Controls.hpp:326
Definition Controls.hpp:173
int idx
Definition Controls.hpp:176
ConditionVar var
Definition Controls.hpp:175
std::string name
Definition Controls.hpp:174
int param
Definition Controls.hpp:177
Definition Controls.hpp:159
double kd
Definition Controls.hpp:162
double kp
Definition Controls.hpp:160
double e2
Error two steps back.
Definition Controls.hpp:165
double ki
Integral time (minutes, 0=disable)
Definition Controls.hpp:161
int action_idx
Associated action index.
Definition Controls.hpp:166
double setpoint
Definition Controls.hpp:163
double e1
Previous error.
Definition Controls.hpp:164
Diagnostic for the most recent parseRuleText() rejection.
Definition Controls.hpp:204
int line
1-based line in the submitted text; -1 if unknown
Definition Controls.hpp:205
std::string token
Offending token legacy names in its message.
Definition Controls.hpp:208
std::string message
Human-readable reason for the rejection.
Definition Controls.hpp:206
int code
Legacy error code for the same rejection.
Definition Controls.hpp:207
Definition Controls.hpp:123
int rhs_param
Extra parameter for RHS gage depth.
Definition Controls.hpp:137
int lhs_param
Extra parameter (e.g. n-hours for GAGE_RAIN_PAST)
Definition Controls.hpp:130
double rhs_value
Definition Controls.hpp:138
ConditionVar lhs_var
Definition Controls.hpp:128
int expr_idx
Index into expressions_ (-1 if N/A)
Definition Controls.hpp:126
int lhs_idx
Object index (node/link/gage)
Definition Controls.hpp:129
bool is_expression
True if LHS is a math expression.
Definition Controls.hpp:125
ConditionVar rhs_var
Definition Controls.hpp:135
int rhs_idx
Definition Controls.hpp:136
bool rhs_is_variable
Definition Controls.hpp:134
LogicOp logic
Definition Controls.hpp:124
CompareOp op
Definition Controls.hpp:132
Definition Controls.hpp:184
std::string name
Definition Controls.hpp:185
double priority
Definition Controls.hpp:189
std::vector< Action > else_actions
Definition Controls.hpp:188
std::vector< Action > then_actions
Definition Controls.hpp:187
std::vector< Premise > premises
Definition Controls.hpp:186