Power-Native First
Power-Native First is EnerOS’s most core design philosophy: the domain knowledge of power systems is not a bolt-on library or configuration file, but a native abstraction of the OS kernel. This means that core power domain concepts such as grid topology, power flow calculation, security constraints, equipment models, and time-series data enjoy first-class kernel-space citizenship, just like traditional OS concepts such as file systems, process management, and network stacks.
Design Motivation
The Dilemma of Traditional Power Software
Traditional power software places grid domain knowledge at the application layer, leading to a series of long-standing problems:
- Redundant Modeling: Each application (EMS, DMS, SCADA, distribution automation) maintains its own grid model, with redundant and inconsistent data
- Validation Omissions: Physical constraint validation is scattered across applications, easily omitted during deployment, and only exposed after accidents
- Agent Silos: Agents cannot share a unified grid worldview; cross-application collaboration requires complex interface integration
- Performance Loss: Each operation needs to rebuild grid context at the application layer, unable to leverage kernel-space optimization
- Difficult Evolution: Grid model changes require synchronous modifications to multiple applications, with long iteration cycles
Power-Native Solution
EnerOS pushes power domain knowledge down to the OS kernel, and all upper-layer applications access the same grid abstraction via system calls:
┌──────────────────────────────────────────────────┐
│ Application Layer (Agents) │
│ DispatchAgent / SelfHealingAgent / TradingAgent │
├──────────────────────────────────────────────────┤
│ Agent Runtime │
│ eneros-agent / eneros-tool / eneros-reasoning │
├──────────────────────────────────────────────────┤
│ Power-Native Core │
│ ├─ NetworkGraph (Topology graph) │
│ ├─ PowerFlowSolver (Power flow solver) │
│ ├─ ConstraintEngine (Constraint engine) │
│ ├─ EquipmentLibrary (Equipment model library) │
│ ├─ TimeSeriesEngine (Time-series storage) │
│ └─ TopologyAwareBus (Event bus) │
├──────────────────────────────────────────────────┤
│ Infrastructure Layer │
│ eneros-os / eneros-trust / eneros-multiregion │
└──────────────────────────────────────────────────┘
Four Pillars of Power-Native
1. Grid Topology as First-Class Citizen
Grid topology is no longer a CIM/XML file on disk or a data structure in application memory, but a graph structure in kernel space. All Agents and all applications share the same topology view and perceive its changes.
Kernel Topology Data Structure
use eneros_topology::{NetworkGraph, Bus, Branch, BusType, Voltage};
// The topology graph is a kernel first-class citizen, loaded at process startup
let mut network = NetworkGraph::new();
// Add buses (nodes)
network.add_bus(Bus::new(1, BusType::PQ, Voltage::new(1.0, 0.0)))?;
network.add_bus(Bus::new(2, BusType::PV, Voltage::new(1.02, 0.0)))?;
network.add_bus(Bus::new(3, BusType::Slack, Voltage::new(1.05, 0.0)))?;
// Add branches (edges)
network.add_branch(Branch::new(1, 2, BranchParams::line(r=0.01, x=0.05, b=0.02)))?;
network.add_branch(Branch::new(2, 3, BranchParams::transformer(r=0.0, x=0.1, ratio=1.0)))?;
// The kernel maintains topology consistency: add/delete/modify automatically triggers connectivity analysis
let topology = network.topology();
let islands = topology.find_islands();
let reachable = topology.reachable(bus_id_1, bus_id_2);
// All Agents share the same topology view, modifications are broadcast in real time
let snapshot = network.snapshot(); // CoW snapshot, zero-copy read
Topology-Aware System Calls
// Agents access topology via system calls, no need to rebuild it themselves
impl Agent for DispatchAgent {
async fn run(&mut self, ctx: &mut AgentContext) -> AgentResult<()> {
// Get the electrical island it belongs to
let island = ctx.syscall(TopologySyscall::GetIsland {
bus: self.bus_id,
}).await?;
// Enumerate all generators in the island
let generators = ctx.syscall(TopologySyscall::ListGenerators {
island_id: island.id,
}).await?;
// Perform economic dispatch
let dispatch = self.economic_dispatch(&generators, &island.load)?;
ctx.syscall(TopologySyscall::ApplyDispatch(dispatch)).await?;
Ok(())
}
}
2. Physical Constraints as Law
Physical constraints (voltage limit violations, branch overloads, frequency deviations) are not optional validation steps at the application layer, but laws enforced by the kernel. Any operation that violates a constraint is directly rejected in kernel space, and when necessary, projected to the nearest feasible solution.
use eneros_constraint::{ConstraintEngine, Constraint, Violation};
// The constraint engine is bound to the kernel topology, automatically validating all write operations
let constraint_engine = ConstraintEngine::new(&network);
// Register constraints (can also be batch loaded via configuration file)
constraint_engine.register(Constraint::voltage()
.min(0.95).max(1.05)
.buses(network.all_buses()))?;
constraint_engine.register(Constraint::thermal()
.branch(branch_id)
.limit_mva(100.0))?;
constraint_engine.register(Constraint::frequency()
.min_hz(49.5).max_hz(50.5))?;
// Any Agent command is automatically validated when passing through the kernel
let command = Command::SetGeneration { bus: 1, mw: 80.0 };
match constraint_engine.check(&command) {
CheckResult::Ok => { /* Passed, execute */ }
CheckResult::Violated(v) => {
// Automatically project to the nearest feasible solution
let feasible = constraint_engine.project(&command)?;
log::warn!("Command projected: {:?} -> {:?}", command, feasible);
}
CheckResult::Rejected(reason) => {
return Err(EnerOSError::ConstraintRejected(reason));
}
}
3. Standardized Equipment Models
EnerOS has a built-in unified equipment model library covering mainstream power system equipment types, with all Agents sharing the same set of parameterized models:
| Equipment Type | Model | Key Parameters | Applicable Scenario |
|---|---|---|---|
| Transmission Line | π-type equivalent circuit | R, X, B/2, length | Transmission grid power flow |
| Transformer | Ideal ratio + magnetizing branch | Ratio, R, X, magnetizing conductance/susceptance | Substation power flow |
| Generator | Synchronous machine 6th-order model | Xd, Xq, Xd’, Xq’, Td0’, Tq0’, H, D | Transient stability |
| Load | ZIP + exponential model | Z%, I%, P%, exponents α, β | Static/dynamic load |
| SVC | Static Var Compensator | K, T, Xc, Xl, Vref | Voltage reactive power control |
| Wind Turbine | Doubly-fed/direct-drive turbine | Cp(λ,β), electrical parameters | Renewable energy integration |
use eneros_equipment::{EquipmentLibrary, LineParams, TransformerParams};
let library = EquipmentLibrary::new();
// Standardized equipment parameters
let line = library.create_line(LineParams {
r_per_km: 0.08,
x_per_km: 0.40,
b_per_km: 2.5e-6,
length_km: 50.0,
rating_mva: 100.0,
nominal_kv: 110.0,
})?;
let transformer = library.create_transformer(TransformerParams {
sn_mva: 63.0,
vn_hv_kv: 110.0,
vn_lv_kv: 10.0,
uk_percent: 10.5,
pk_kw: 280.0,
i0_percent: 0.5,
p0_kw: 50.0,
})?;
// Equipment models are automatically injected into the topology
network.add_branch(Branch::from_equipment(line.id(), bus_a, bus_b))?;
network.add_branch(Branch::from_equipment(transformer.id(), bus_c, bus_d))?;
4. Time-Series Data Native
All operating states of a power system (voltage, current, power, frequency) are inherently time-series data. EnerOS builds the time-series storage engine into a kernel component, providing nanosecond-precision writes and queries, without depending on external time-series databases like InfluxDB or TimescaleDB.
use eneros_timeseries::{TimeSeriesEngine, Measurement, Aggregation, Duration};
// The time-series engine is a kernel component, ready at startup
let ts = TimeSeriesEngine::open("data/eneros.db")?;
// High-throughput writes (batch interface)
ts.batch_write(&[
Measurement::new("bus_1_voltage", 1.02, now!()),
Measurement::new("bus_1_frequency", 50.00, now!()),
Measurement::new("line_1_power", 45.50, now!()),
Measurement::new("bus_2_voltage", 0.99, now!()),
])?;
// Aggregation query + downsampling integrated
let result = ts.query()
.point("bus_1_voltage")
.range(now!() - Duration::hours(24), now!())
.aggregation(Aggregation::Avg, Duration::minutes(15))
.downsample(Downsample::LTTB, 1000)
.execute()?;
// Agents query directly via system calls
let history = ctx.syscall(TimeSeriesSyscall::Query {
point: "total_load",
range: (now!() - Duration::days(7), now!()),
}).await?;
Complete Comparison: Traditional vs Power-Native
| Dimension | Traditional Power Software | EnerOS Power-Native |
|---|---|---|
| Topology Modeling | Application-layer data structure (CIM/XML) | Kernel first-class citizen (graph structure) |
| Topology Consistency | Manual sync per application | Kernel auto-maintained |
| Constraint Validation | Optional at application layer, easily omitted | Kernel-enforced |
| Constraint Projection | Unsupported or self-implemented | Kernel auto-projection |
| Equipment Model | Custom per application | Unified model library |
| Time-Series Data | External database (InfluxDB, etc.) | Kernel storage engine |
| Agent Sharing | Manual synchronization | Auto-share same view |
| Security & Compliance | Bolt-on module | Kernel-enforced |
| Cross-Application Collaboration | Complex interface integration | System calls suffice |
| Performance | Application-layer rebuilds context | Kernel-space zero-copy |
Performance Comparison
Comparison in a standard test environment (4 cores / 8GB / Ubuntu 22.04, IEEE 118-bus system):
| Operation | Traditional Solution | EnerOS Power-Native | Improvement |
|---|---|---|---|
| Topology Loading | 500-1000ms (XML parsing) | < 5ms (kernel binary) | 100x |
| Topology Analysis (118 nodes) | 50-100ms | < 1ms | 50x |
| Power Flow Calculation (Newton method) | 100-300ms | < 30ms | 5x |
| Constraint Validation (single command) | 1-5ms (application layer) | < 10μs (kernel space) | 500x |
| Time-Series Write | 10-50K points/sec (network round-trip) | 1M points/sec (kernel space) | 50x |
| Agent Context Build | 50-200ms (rebuild model) | < 10μs (system call) | 5000x |
| Cross-Application Event Broadcast | 10-50ms (message queue) | < 10μs (kernel bus) | 1000x |
Applicable Scenarios
The Power-Native architecture is particularly suitable for the following scenarios:
- Large Interconnected Grids: Unified modeling and coordinated control across regions and voltage levels
- High Renewable Penetration: The stochastic nature of wind and solar requires real-time power flow and constraint validation
- Distribution Network Intelligence: Coordinated management of distributed energy, storage, and electric vehicles
- Digital Twin: Real-time synchronization and mirror inference between the physical grid and its twin
- Multi-Agent Collaboration: Dispatch, self-healing, trading, and other multi-agents sharing a grid worldview
- Power Market Operation: Market clearing and settlement based on real-time topology and power flow
Limitations and Trade-offs
The Power-Native architecture is not a silver bullet and involves the following trade-offs:
| Trade-off | Description | Mitigation Strategy |
|---|---|---|
| High Kernel Complexity | Power domain knowledge in the kernel increases kernel code volume | Strict modularization, 56 crates decoupled |
| Deployment Threshold | Requires power domain knowledge to configure correctly | Provide standard model library and configuration templates |
| Reduced Generality | Optimized for power scenarios, not suitable for general IoT | Extend non-power scenarios via plugin framework |
| Memory Usage | Kernel resident topology and time-series cache | Supports memory cap configuration and LRU eviction |
| Cross-Platform Limitations | Real-time domain depends on PREEMPT_RT or bare metal | General domain can be deployed independently on regular Linux |
| Upgrade Complexity | Kernel upgrades require coordinating all Agents | CoW snapshots ensure hot-upgrade consistency |
Kernel Architecture Layers
The layered design of the Power-Native kernel:
┌─────────────────────────────────────────┐
│ System Call Interface (Syscall ABI) │ ← Agents access via syscall
├─────────────────────────────────────────┤
│ Power-Native Service Layer │
│ ├─ TopologyService (Topology R/W) │
│ ├─ PowerFlowService (Power flow) │
│ ├─ ConstraintService (Constraint check)│
│ ├─ EquipmentService (Equipment model) │
│ └─ TimeSeriesService (Time-series) │
├─────────────────────────────────────────┤
│ Power Domain Kernel │
│ ├─ NetworkGraph (CIM graph) │
│ ├─ Solver (Newton/PQ decomp)│
│ ├─ ConstraintEngine (Constraint proj) │
│ ├─ EquipmentLibrary (Equipment proto) │
│ └─ TimeSeriesEngine (LSM-WAL storage) │
├─────────────────────────────────────────┤
│ General OS Abstraction Layer │
│ └─ Scheduler / Memory / IPC / Network │
└─────────────────────────────────────────┘
System Call Examples
Agents access kernel power services via system calls, without rebuilding any domain models themselves:
use eneros_os::syscall::*;
// Topology query
let bus = ctx.syscall(GetBus { id: bus_id }).await?;
let neighbors = ctx.syscall(GetNeighbors { bus: bus_id }).await?;
let island = ctx.syscall(GetIsland { bus: bus_id }).await?;
// Power flow trigger
let result = ctx.syscall(SolvePowerFlow {
method: PowerFlowMethod::NewtonRaphson,
max_iter: 20,
tolerance: 1e-6,
}).await?;
// Constraint validation
let check = ctx.syscall(CheckConstraint {
command: command.clone(),
}).await?;
// Time-series query
let series = ctx.syscall(QueryTimeSeries {
point: "bus_1_voltage",
range: (start, end),
aggregation: Some((Aggregation::Avg, Duration::minutes(5))),
}).await?;
// Equipment operations
ctx.syscall(SetTapPosition { transformer_id, position: 5 }).await?;
ctx.syscall(SetGeneratorOutput { bus: 1, mw: 80.0 }).await?;
Comparison with Traditional OS
| Concept | General OS | EnerOS Power-Native |
|---|---|---|
| First-Class Citizens | Files, processes, sockets | Buses, branches, equipment, constraints |
| System Calls | open/read/write/socket | GetBus/SolvePowerFlow/CheckConstraint |
| Scheduling Objects | Processes/threads | Agents (bound to electrical nodes) |
| Enforced Protection | Memory isolation, permission bits | Physical constraint enforcement |
| Persistence | File system | Time-series storage engine |
| Event Mechanism | Signals, epoll | Topology-aware event bus |
Next Steps
- Agent-as-Grid-Node - Agent as grid node, understand how Agents bind to electrical nodes
- Constraint as Law - How the constraint engine works and projection algorithms
- Time-Series Native - Architecture and API of the time-series storage engine
- Real-Time Determinism - How the dual-execution domain guarantees microsecond-level response for protection logic