Skip to main content

v0.13.0 Release Notes

EnerOS v0.13.0

Release Date: January 5, 2025 Codename: Twin Git Tag: v0.13.0 Support Status: Stable Total Crates: 30 (4 new) Test Cases: 4120+ (540 new)

Version Overview

EnerOS v0.13.0 “Twin” is the core version marking EnerOS’s entry into the “virtual-real fusion” phase. The core goal of this version is to introduce the Digital Twin Engine, building high-fidelity real-time mirrors for the physical grid, enabling dispatchers, Agents, and analytical tasks to perform state observation, historical replay, and What-if analysis on the digital twin without affecting real grid operations.

Power systems are a typical “cannot trial-and-error on the real system” domain — operations such as switch operations, generator output adjustments, and load shedding produce physical consequences once executed, and incorrect operations may lead to large-scale blackouts. Traditional approaches rely on offline simulation tools (such as PSS/E, BPA), but offline simulation data lags behind real-time status and cannot collaborate with online Agents. v0.13.0 brings digital twin capabilities down to operating system kernel first-class citizens, enabling the twin to stay synchronized with the physical grid within seconds, and to be directly invoked by Agents for decision rehearsal.

This version introduces four new crates: eneros-twin (twin engine core), eneros-twin-sync (real-time mirror synchronization), eneros-twin-replay (historical replay), and eneros-twin-whatif (What-if analysis). The design philosophy is “twin is mirror, mirror is verifiable” — the twin is not a simple data copy, but an executable mirror containing complete electrical models, physical constraints, and equipment characteristics; any operation on the twin goes through the same physical constraint validation as the real system.

Key Data

Metricv0.12.0v0.13.0Improvement
Twin sync latencyN/A80msReal-time level
Historical replay accuracyN/A99.97%High fidelity
What-if computation timeOffline minutes1.2sOnline level
State estimation accuracy92%99.2%+7.2pp
Twin scaleN/A100,000 nodesProvincial grid

New Features

1. Digital Twin Engine

Introduces the eneros-twin crate, providing complete digital twin lifecycle management. The twin is an executable mirror of the physical grid, containing four types of data: topology model, equipment parameters, real-time state, and historical trajectory, with a built-in physical constraint engine ensuring twin state always satisfies electrical laws.

Twin Creation

use eneros_twin::{Twin, TwinId, TwinConfig};
use eneros_topology::Network;

// Create twin based on existing topology
let twin = Twin::new(TwinId::from("grid-province-a"))
    .source_network(&network)
    .config(TwinConfig {
        fidelity: Fidelity::High,
        sync_mode: SyncMode::Realtime,
        state_estimation: true,
        physics_engine: PhysicsEngine::NewtonRaphson,
        history_depth: Duration::days(30),
    })?;

// Start twin
twin.start().await?;

Twin Fidelity Levels

Fidelity LevelModel AccuracyState UpdatePhysical ConstraintsApplicable Scenarios
LowTopology level5sTopology connectivityOverview monitoring
MediumEquivalent circuit1sPower flow balanceDispatch training
HighDetailed equipment200msComplete constraintsDecision rehearsal
UltraComponent level50msElectromagnetic transientFault analysis

Twin State Query

// Query twin current state
let state = twin.current_state()?;
println!("Bus 1 voltage: {:.3} pu", state.bus(1).voltage);
println!("Line 12-14 active power: {:.1} MW", state.line(12, 14).p_mw);

// Query equipment state
let transformer = state.transformer(7);
println!("Transformer tap position: {}", transformer.tap_position);
println!("Transformer loading rate: {:.1}%", transformer.loading * 100.0);

2. Real-time Mirror Synchronization

Introduces the eneros-twin-sync crate, continuously synchronizing real-time telemetry data from the physical grid to the twin, maintaining state consistency between the twin and physical grid. Synchronization uses a hybrid mode of incremental updates + state estimation, filling in data gaps through state estimation when data is missing.

Synchronization Configuration

use eneros_twin_sync::{SyncEngine, SyncConfig};

let sync = SyncEngine::new(&twin)
    .config(SyncConfig {
        sync_interval: Duration::milliseconds(200),
        state_estimation: true,
        bad_data_detection: BadDataDetection::ChiSquare,
        observable_check: true,
        pseudo_measurement: true,
    })?;

// Bind telemetry data source
sync.bind_source(telemetry_stream).await?;

State Estimation

use eneros_twin_sync::StateEstimator;

let estimator = StateEstimator::new(&twin)
    .method(EstimationMethod::Wls)  // Weighted Least Squares
    .max_iterations(20)
    .convergence_tolerance(1e-6);

// Execute state estimation
let result = estimator.estimate().await?;
println!("Estimation accuracy: {:.2f}%", result.accuracy * 100.0);
println!("Bad data count: {}", result.bad_data_count);

Synchronization Performance Metrics

Data SourceData PointsSync PeriodEnd-to-end LatencyLoss Rate
SCADA telemetry480001s80ms< 0.01%
PMU phasor120020ms25ms< 0.05%
Fault recording256Event-triggered50ms0%

3. State Snapshots

The twin supports periodic and on-demand state snapshots, serializing the complete grid state into immutable snapshots for historical replay and comparative analysis. Snapshots use columnar compression storage, with a single snapshot occupying only 2-8MB.

Snapshot Operations

use eneros_twin::snapshot::{Snapshot, SnapshotId};

// Create manual snapshot
let snapshot = twin.snapshot()
    .tag("pre-dispatch-check")
    .metadata("operator", "zhang")
    .capture()
    .await?;

// List historical snapshots
let snapshots: Vec<Snapshot> = twin.snapshots()
    .range(now() - Duration::hours(24), now())
    .list()?;

// Restore twin state from snapshot
twin.restore(&snapshot).await?;

Snapshot Storage Strategy

Snapshot TypeTriggerRetentionCompression RatioSingle Size
Real-time snapshotEvery 200ms7 days8:12-4MB
Minute snapshotEvery 1min90 days12:14-6MB
Hourly snapshotEvery 1h1 year15:16-8MB
Event snapshotBefore operationsPermanent10:14-6MB

4. Historical Replay

Introduces the eneros-twin-replay crate, supporting replay of grid operation processes from any historical time point, with adjustable replay speed, viewpoint, and granularity, for incident analysis, training exercises, and compliance audits.

Replay Control

use eneros_twin_replay::{Replay, ReplayConfig, Speed};

let replay = Replay::new(&twin)
    .config(ReplayConfig {
        start_time: "2025-01-03T14:30:00Z".parse()?,
        end_time: "2025-01-03T15:00:00Z".parse()?,
        speed: Speed::Realtime,
        focus_area: Some(BusId::from(110).into()),
    })?;

// Start replay
replay.play().await?;

// Pause / Fast forward / Rewind
replay.pause().await?;
replay.set_speed(Speed::Fast(10.0)).await?;
replay.seek("2025-01-03T14:45:00Z").await?;

Replay Event Tracking

// Listen to events during replay
replay.on_event(|event| {
    match event {
        ReplayEvent::SwitchOperated(switch_id, state) => {
            log::info!("Switch {} operated to {}", switch_id, state);
        }
        ReplayEvent::FaultDetected(fault) => {
            log::warn!("Fault detected: {:?}", fault);
        }
        ReplayEvent::VoltageViolation(bus, value) => {
            log::warn!("Bus {} voltage violation: {:.3} pu", bus, value);
        }
    }
});

5. What-if Analysis

Introduces the eneros-twin-whatif crate, supporting hypothetical operations on the twin and predicting their consequences without affecting the real grid. What-if analysis is the core capability for Agent decision rehearsal — Agents validate operation safety on the twin before executing real operations.

What-if Scenarios

use eneros_twin_whatif::{WhatIf, Scenario, Action};

// Construct a What-if scenario
let scenario = Scenario::new("open-line-12-14")
    .initial_state(&twin.current_state()?)
    .action(Action::OpenLine { from: 12, to: 14 })
    .action(Action::AdjustGeneration { bus: 5, delta_mw: 50.0 })
    .duration(Duration::minutes(10))
    .step(Duration::seconds(1));

// Execute What-if analysis
let result = WhatIf::run(&scenario).await?;

// View prediction results
println!("Power flow converged: {}", result.converged);
println!("Max voltage deviation: {:.3} pu", result.max_voltage_deviation);
println!("Violation equipment count: {}", result.violations.len());

for violation in &result.violations {
    println!("  - {:?}: {:.3} (limit {:.3})",
        violation.equipment, violation.value, violation.limit);
}

What-if Decision Rehearsal

// Agent rehearses before executing real operations
async fn safe_dispatch(ctx: &Context, cmd: DispatchCommand) -> Result<()> {
    // 1. Rehearse on twin
    let scenario = Scenario::from_current(&ctx.twin)
        .action(Action::Dispatch(cmd.clone()))
        .duration(Duration::minutes(5));
    
    let result = WhatIf::run(&scenario).await?;
    
    // 2. Validate whether rehearsal results are safe
    if !result.is_safe() {
        return Err(DispatchError::UnsafePrediction(result.violations));
    }
    
    // 3. Rehearsal passed, execute real operation
    ctx.syscall(ExecuteDispatch(cmd)).await?;
    Ok(())
}

What-if Performance Metrics

Scenario ScaleNode CountSimulation DurationComputation TimeSpeedup
Small10010min80ms7500x
Medium100010min450ms1333x
Large1000010min1.2s500x
Provincial5000010min6.8s88x

Improvements

  • Topology Engine: eneros-topology supports incremental topology change notifications; the twin can sense physical topology changes within 50ms
  • State Estimation: Introduced PMU phasor data fusion, improving state estimation accuracy from 92% to 99.2%
  • Storage Compression: Twin snapshots use ZSTD columnar compression, reducing storage footprint by 70%
  • API: Added GraphQL twin query interface, supporting complex state retrieval

Bug Fixes

  • Fixed eneros-twin state estimation divergence during topology changes (#1305)
  • Fixed eneros-twin-sync state jumps due to out-of-order PMU data arrival (#1312)
  • Fixed eneros-twin-replay event loss during cross-snapshot replay (#1319)
  • Fixed eneros-twin-whatif power flow non-convergence on large grids (#1325)

Breaking Changes

  • Twin::new must specify source_network: Original default empty network behavior removed
  • Snapshot::capture changed to async: Original sync signature moved to capture_blocking
  • StateEstimator::estimate: Return type adds bad_data field

Performance Improvements

  • Twin sync latency reduced from 500ms to 80ms (6.3x improvement)
  • What-if computation time reduced from offline minutes to 1.2s (online level)
  • State estimation accuracy improved from 92% to 99.2%
  • Snapshot storage compression ratio improved from 4:1 to 12:1

Contributors

This version was completed by 24 contributors with 412 commits. Special thanks to:

  • @twin-engine: Digital twin engine core architecture
  • @state-estimator: WLS state estimation and PMU fusion
  • @replay-master: Historical replay and event tracking
  • @whatif-arch: What-if analysis and decision rehearsal

Upgrade Guide

Upgrading from v0.12.0

1. Update Dependencies

# Cargo.toml
[dependencies]
eneros-twin = { version = "0.13", features = ["high-fidelity"] }
eneros-twin-sync = { version = "0.13" }
eneros-twin-replay = { version = "0.13" }
eneros-twin-whatif = { version = "0.13" }

2. Initialize Twin

use eneros_twin::Twin;

// Create default twin based on existing topology
let twin = Twin::new(TwinId::from("default"))
    .source_network(&network)
    .config(TwinConfig {
        fidelity: Fidelity::High,
        sync_mode: SyncMode::Realtime,
        ..Default::default()
    })?;

twin.start().await?;

3. Enable State Estimation

# eneros.toml
[twin]
enabled = true
fidelity = "high"
state_estimation = true
estimation_method = "wls"
history_depth_days = 30

4. Configure Agent Decision Rehearsal

It is recommended to enable What-if rehearsal for critical operation-type Agents to ensure operation safety:

Agent::new("dispatcher", tenant)
    .preflight_check(PreflightConfig {
        what_if_enabled: true,
        scenario_duration: Duration::minutes(5),
        safety_threshold: 0.99,
    })
    .spawn()?;