Skip to main content

v0.22.0 Release Notes

EnerOS v0.22.0 Release Notes

Release Date: July 13, 2025 Codename: Physics Git Tag: v0.22.0 Support Status: Stable Total Crates: 52 (4 new) Test Cases: 6600+ (500+ new)

Overview

EnerOS v0.22.0 “Physics” is a specialized release for physics-constrained decision-making, upgrading power system physical constraints from “post-event validation” to a full-lifecycle decision framework of “pre-event awareness, in-event constraint, post-event traceability.” The fundamental characteristic that distinguishes power systems from general IT systems is that they are governed by physical laws: Kirchhoff’s laws constrain power flow distribution, thermodynamic laws constrain equipment current-carrying capacity, and voltage stability limits constrain operating boundaries. v0.22.0 builds these physical constraints as first-class inputs to the decision engine, making every Agent decision naturally physically feasible.

This version introduces four core capabilities: Physics-Constrained Decision framework, Power Flow Constraint Awareness, Voltage Stability Constraint, and Thermal Stability Constraint, and integrates a Constraint Optimization Solver supporting Linear Programming (LP), Quadratic Programming (QP), and Mixed-Integer Linear Programming (MILP).

In terms of design philosophy, v0.22.0 strengthens the “constraints as law” principle: any Agent decision recommendation must undergo mandatory projection through the ConstraintEngine before execution, with actions violating physical constraints automatically corrected or rejected. This ensures EnerOS maintains grid operational safety even when introducing the uncertainty of AI decision-making.

Key Metrics

MetricValueDescription
Constraint types12Voltage/current/frequency/thermal etc.
Constraint validation latency< 10μsSingle constraint kernel-mode
LP solving (1000 variables)8msSimplex method
QP solving (500 variables)15msInterior point method
MILP solving (100 binary)120msBranch and bound
New Crates4Physics constraint-related
New tests500+Including IEEE standard cases

New Features

1. Physics-Constrained Decision Framework

Introduced the eneros-physics-decision Crate, providing a unified physics-constrained decision framework. All Agent decisions are wrapped through PhysicsAwareDecision, automatically injecting current grid operating state and constraint boundaries.

Decision Wrapper

use eneros_physics_decision::{PhysicsAwareDecision, DecisionContext};

let ctx = DecisionContext::from_snapshot(&network_snapshot)
    .with_voltage_limits(VoltageLimits {
        normal: (0.95, 1.05),  // pu
        emergency: (0.90, 1.07),
    })
    .with_thermal_limits(thermal_limits_from_equipment(&library));

let decision = PhysicsAwareDecision::new(Action::AdjustGenerator {
    gen_id: 1,
    target_mw: 200.0,
}).with_context(&ctx);

// Automatically validate physical constraints before execution
match decision.validate().await {
    Ok(projected) => ctx.syscall(Execute(projected)).await?,
    Err(violations) => {
        for v in violations {
            log::warn!("Constraint violation: {} exceeded by {:.2}%", v.constraint, v.margin_pct);
        }
    }
}

Constraint Type List

Constraint CategoryConstraint ItemValidation Method
Voltage constraintsBus voltage upper/lower limitsAnalytical
Voltage constraintsVoltage change rateAnalytical
Current constraintsLine current-carrying capacityAnalytical
Current constraintsTransformer overloadAnalytical
Frequency constraintsSystem frequency deviationAnalytical
Frequency constraintsFrequency change rateAnalytical
Thermal stability constraintsEquipment temperature riseNumerical integration
Thermal stability constraintsAccumulated heatNumerical integration
Stability constraintsTransient stability marginSimulation
Stability constraintsSmall-signal damping ratioEigenvalue
Reserve constraintsSpinning reserve capacityAnalytical
Topology constraintsElectrical island connectivityGraph theory

2. Power Flow Constraint Awareness

Introduced the eneros-powerflow-aware Crate, enabling Agents to perceive power flow distribution constraints during decision-making. Any action (such as adjusting generator output, shedding load, operating switches) triggers power flow sensitivity analysis to assess impact on the entire network’s power flow.

Power Flow Sensitivity

use eneros_powerflow_aware::{Sensitivity, PowerflowAware};

let aware = PowerflowAware::new(&network);

// Calculate sensitivity of generator output to line power flow
let sens: Sensitivity = aware.sensitivity()
    .factor(Variable::GeneratorMW(1))
    .on(Monitor::LineFlow(line_id))
    .compute().await?;

// Sensitivity coefficient: impact of generator 1's 1MW adjustment on line i power flow
println!("Sensitivity coefficient: {:.6}", sens.coefficient);

Power Flow Constraint Validation

// Validate whether adjusting generator output will cause line overlimits
let action = Action::AdjustGenerator { gen_id: 1, target_mw: 250.0 };
let impact = aware.impact_of(&action).await?;

if impact.max_line_loading > 0.95 {
    return Err(DecisionError::ThermalViolation {
        line: impact.bottleneck_line,
        loading: impact.max_line_loading,
    });
}

Power Flow Constraint Metrics

MetricThresholdTriggered Action
Line load rate> 95%Alarm
Line load rate> 100%Block
Transformer load rate> 90%Alarm
Bus voltage deviation> 5%Alarm
Bus voltage deviation> 7%Block

3. Voltage Stability Constraint

Introduced the eneros-voltage-stability Crate, providing voltage stability margin assessment and constraints. Based on PV/QV curves and Continuation Power Flow (CPF) methods, it calculates system voltage stability margins in real-time.

Stability Margin Calculation

use eneros_voltage_stability::{VoltageStability, LoadingMargin};

let vs = VoltageStability::new(&network);

// Calculate P-V curve and stability margin
let margin: LoadingMargin = vs.loading_margin()
    .at_bus(bus_id)
    .direction(LoadIncrease::Proportional)
    .compute().await?;

println!("Load margin: {:.1} MW ({:.1}%)", margin.mw, margin.percentage);

if margin.percentage < 15.0 {
    return Err(DecisionError::VoltageUnstable {
        margin: margin.percentage,
    });
}

Sensitivity Metrics

// Calculate voltage stability index (L-index)
let l_index = vs.l_index(bus_id).await?;
// L < 0.0 stable, L = 1.0 critical

// Calculate minimum singular value
let min_svd = vs.min_singular_value().await?;
// Larger is more stable

Voltage Stability Levels

LevelMarginStatusResponse
A> 20%AdequateNormal dispatch
B15-20%GoodMonitoring
C10-15%AlertPrepare adjustment
D5-10%WarningActive adjustment
E< 5%EmergencyEmergency control

4. Thermal Stability Constraint

Introduced the eneros-thermal-stability Crate, providing equipment thermal stability constraints. Based on equipment thermal models (IEEE 738 standard), it calculates temperature rise and accumulated heat of lines and transformers in real-time.

Thermal Model

use eneros_thermal_stability::{ThermalModel, Conductor};

let conductor = Conductor::from_library("LGJ-400/35");
let model = ThermalModel::new(&conductor)
    .ambient_temp(35.0)        // Ambient temperature °C
    .wind_speed(0.5)            // Wind speed m/s
    .solar_radiation(800.0);    // Solar radiation W/m²

// Calculate steady-state temperature at current current
let steady_temp = model.steady_state_temp(current_amp: 600.0).await?;

// Calculate short-term overload allowed time
let allowed = model.emergency_rating(
    current_amp: 800.0,
    max_temp: 80.0,
    duration: Duration::minutes(15),
).await?;

println!("Allowed overload duration: {:?}", allowed.duration);

Dynamic Line Rating

// Dynamic Line Rating (DLR) based on weather data
let dlr = model.dynamic_line_rating(&weather).await?;
println!("Dynamic line rating: {:.0} A", dlr.ampacity);

Thermal Stability Parameter Table

Conductor ModelSteady-state Current (A)Emergency Current (A)Allowed Temperature (°C)
LGJ-240/3041055070
LGJ-300/2548064070
LGJ-400/3558078070
LGJ-500/4566088070
LGJ-630/55760102070

5. Constraint Optimization Solver

Introduced the eneros-constraint-solver Crate, integrating LP/QP/MILP solvers, supporting constrained optimization problems such as economic dispatch, optimal power flow, and unit commitment.

LP Solving (Economic Dispatch)

use eneros_constraint_solver::{Problem, Solver, Variable, Constraint, Objective};

let mut problem = Problem::new();

// Decision variables: generator outputs
let g1 = problem.add_var(Variable::continuous().bounds(0.0, 100.0));
let g2 = problem.add_var(Variable::continuous().bounds(0.0, 200.0));
let g3 = problem.add_var(Variable::continuous().bounds(0.0, 150.0));

// Constraint: load balance
problem.add_constraint(Constraint::equal(
    vec![(g1, 1.0), (g2, 1.0), (g3, 1.0)],
    350.0,  // Total load 350MW
));

// Constraint: reserve capacity
problem.add_constraint(Constraint::greater_equal(
    vec![(g1, 1.0), (g2, 1.0), (g3, 1.0)],
    380.0,  // Reserve 30MW
));

// Objective: cost minimization
problem.set_objective(Objective::minimize(vec![
    (g1, 30.0),  // Cost coefficients
    (g2, 25.0),
    (g3, 40.0),
]));

let solution = Solver::simplex().solve(&problem).await?;
println!("Optimal output: G1={:.1}, G2={:.1}, G3={:.1}",
    solution.value(g1), solution.value(g2), solution.value(g3));

QP Solving (Optimal Power Flow)

// Optimal power flow: minimize network losses
let opf = OpfProblem::new(&network)
    .objective(Objective::MinLoss)
    .constraints(Constraints::all())  // Voltage/current/thermal stability
    .solver(Solver::interior_point());

let result = opf.solve().await?;

Solver Performance

Problem TypeScaleSolving TimeAlgorithm
LP1000 variables8msSimplex
LP10000 variables45msDual simplex
QP500 variables15msInterior point
QP5000 variables85msInterior point
MILP100 binary120msBranch and bound
MILP1000 binary1.2sBranch and bound + heuristics

Improvements

  • Constraint Caching: Constraint validation results cached by topology fingerprint, repeated validation reduced from 10μs to 1μs
  • Incremental Validation: Only validates affected areas, reducing large grid validation time by 70%
  • Parallel Solving: QP solver supports multi-threading, 3.2x speedup on 4 cores
  • Constraint Explanation: Outputs human-readable explanations when constraints are violated, facilitating operations troubleshooting

Bug Fixes

  • Fixed eneros-constraint constraint boundaries not updating during electrical island splitting (#2205)
  • Fixed eneros-powerflow Newton method non-convergence in ill-conditioned systems (#2209)
  • Fixed eneros-thermal numerical oscillation during ambient temperature jumps (#2214)
  • Fixed eneros-constraint-solver MILP solver infinite loop in degenerate cases (#2219)

Breaking Changes

  • Constraint::check return type: Changed from Result<bool> to Result<ConstraintReport>, including detailed overlimit information
  • PowerflowSolver::solve: New constraints: &ConstraintSet parameter, can pass &ConstraintSet::default() by default

Upgrade Guide

  1. Run cargo update -p eneros-physics-decision
  2. Update Constraint::check calls to adapt to new ConstraintReport return type
  3. Provide ConstraintSet parameter for PowerflowSolver::solve
  4. Refer to docs/migration/v0.22.0.md for detailed migration steps