Skip to content

Conversation

Jerry-Jinfeng-Guo
Copy link
Member

Implement Meshed Network Observability Check

Summary

This PR implements #1085 a comprehensive observability checking algorithm for meshed power grid networks without voltage phasor sensors. The implementation adds a spanning tree algorithm based on nodal measurements and connectivity analysis to determine network observability for non-radial (meshed) topologies.

Key Changes

Algorithm Implementation

New Spanning Tree Algorithm for Meshed Networks

  • sufficient_condition_meshed_without_voltage_phasor(): Main entry point for meshed network observability checking
  • starting_from_node(): Core spanning tree construction algorithm that attempts to build a spanning tree using available measurements
  • prepare_starting_nodes(): Smart starting point selection algorithm that prioritizes nodes without measurements and no edge measurements

Data Structures

New Connectivity Status Enum

  • ConnectivityStatus enum with 7 states to track measurement usage:
    • is_not_connected (-1): Not connected, redundant
    • has_no_measurement (0): Connected but no measurement available
    • node_measured (0b010): Node has unused measurement
    • node_downstream_measured (0b001): Branch discovered with downstream measurement
    • node_upstream_measured (0b100): Branch discovered with upstream measurement
    • branch_native_measured (0b111): Branch has its own measurement, unused
    • branch_measured_used (0b101): Branch measurement already used

New Neighbor Network Structure

  • ObservabilityNNResult: Represents network topology with direct neighbor connections
  • Bidirectional neighbor list expansion via expand_neighbour_list()
  • Integration with Y-bus structure for efficient connectivity analysis

Algorithm Features

Multi-Priority Spanning Tree Construction

  1. Native Edge Measurements (Priority 1): Utilizes branch flow/power sensors directly
  2. Downwind Measurements (Priority 2): Uses nodal measurements in downwind mode
  3. General Connection Rules (Priority 3): Handles complex measurement assignment scenarios
  4. Backtracking with Reassignment (Priority 4): Implements measurement reassignment during backtracking

Smart Measurement Reassignment

  • reassign_nodal_measurement(): Dynamically reassigns nodal measurements during backtracking
  • Optimizes measurement usage when algorithm gets stuck
  • Maintains edge direction consistency through connectivity status updates

Refactored Codfe

Enhanced Network Scanning

  • Renamed count_observability_sensors()scan_network_sensors()
  • Added bus injection counting with early-out optimization
  • Integrated neighbor list construction during network scanning
  • Added comprehensive sensor classification (flow, voltage phasor, bus injection)

Improved Function Organization

  • Renamed necessary_observability_condition()necessary_condition()
  • Renamed sufficient_observability_condition()sufficient_condition_radial_with_voltage_phasor()
  • Added namespace observability for better code organization
  • Eliminated code duplication through parameterized helper functions

Some Performance Optimizations

Early Exit Conditions

  • Sufficient nodal measurements: If bus_injections.back() > n_bus - 2, network is immediately observable
  • Multiple starting points: Algorithm tries different starting nodes to find valid spanning trees
  • Iteration limiting: Prevents infinite loops with max_iterations = n_bus²

Improvements

Variable Naming Consistency

  • Fixed loop variable names: rowbus for clarity
  • Consistent use of n_bus sizing
  • Improved variable scoping and const correctness

Signed-off-by: Jerry Guo <[email protected]>
…observability-check-meshed-network-without-voltage-phasor
Signed-off-by: Jerry Guo <[email protected]>
Signed-off-by: Jerry Guo <[email protected]>
Signed-off-by: Jerry Guo <[email protected]>
@Jerry-Jinfeng-Guo Jerry-Jinfeng-Guo self-assigned this Sep 24, 2025
@Jerry-Jinfeng-Guo Jerry-Jinfeng-Guo added feature New feature or request do-not-merge This should not be merged labels Sep 24, 2025
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements a comprehensive observability checking algorithm for meshed power grid networks without voltage phasor sensors. The implementation adds a spanning tree algorithm based on nodal measurements and connectivity analysis to determine network observability for non-radial (meshed) topologies.

  • Adds new meshed network observability algorithm with spanning tree construction
  • Introduces bidirectional neighbor network structure and connectivity status tracking
  • Refactors existing functions for better organization and adds observability namespace

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
test_observability.cpp Updates test calls to use new observability namespace
observability.hpp Core implementation with new meshed network algorithm, data structures, and refactored functions
newton_raphson_se_solver.hpp Updates observability check call to use new namespace
iterative_linear_se_solver.hpp Updates observability check call to use new namespace

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@Jerry-Jinfeng-Guo
Copy link
Member Author

Validation test case with meshed topology in ill-conditioned-system is wrongly configured. The network is observable.


ObservabilitySensorsResult result{.flow_sensors = std::vector<int8_t>(y_bus_structure.row_indptr.back(), 0),
.voltage_phasor_sensors = std::vector<int8_t>(n_bus, 0),
.bus_injections = std::vector<int8_t>(n_bus + 1, 0),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: The n+1 trick with the number of sensors at the n+1 spot might be useful for voltage_phasor_sensors and flow_sensors as well, since we count them anyway later on.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably a good follow up, as it depends on what will happen with the radial check. Resolving for now.

Copy link
Member

@nitbharambe nitbharambe Oct 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unresolving: I dont really like the n+1 trick. The extra .back() makes the intent really confusing. Why not have a counter within the struct itself?

Comment on lines 426 to 432
for (auto& neighbour : local_neighbour_list[to_node].direct_neighbours) {
if (neighbour.bus == from_node) {
// Change to downstream connection (from from_node to to_node perspective)
neighbour.status = ConnectivityStatus::node_downstream_measured;
break;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pattern happens a lot, maybe a good idea to make it a helper function.

Jerry-Jinfeng-Guo and others added 4 commits September 28, 2025 16:20
Signed-off-by: Jerry Guo <[email protected]>
…-voltage-phasor' into feature/reconfigure-test-case-for-full-observability-check
// upper triangle for branch flow measurement
for (Idx ybus_index = y_bus_structure.bus_entry[row] + 1; ybus_index != y_bus_structure.row_indptr[row + 1];
++ybus_index) {
for (Idx ybus_index = current_bus_entry + 1; ybus_index != y_bus_structure.row_indptr[bus + 1]; ++ybus_index) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can fill the "expand_neighbour_list" info in this loop too using the col_indices

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #1136 (comment)

This also contradicts the 'single responsibility' paradigm you are promoting.

};
Idx bus; // this bus index
ConnectivityStatus status{ConnectivityStatus::has_no_measurement}; // this bus connectivity status
std::vector<neighbour> direct_neighbours; // list of direct connected neighbours
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed yesterday, we can store the neighbour list in YBusStructure order. Adding a note here, but lets think about it later.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of scope here. And into future improvement ideas discussion.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correction: the list is the product/output of a wrapper function/object in between the YBus and the Observability check module. Not in the YBus.

Signed-off-by: Jerry Guo <[email protected]>
@Jerry-Jinfeng-Guo Jerry-Jinfeng-Guo marked this pull request as ready for review October 8, 2025 10:10
…-voltage-phasor' into feature/reconfigure-test-case-for-full-observability-check
@Jerry-Jinfeng-Guo Jerry-Jinfeng-Guo removed the do-not-merge This should not be merged label Oct 8, 2025
Jerry-Jinfeng-Guo and others added 7 commits October 8, 2025 14:40
Signed-off-by: Jerry Guo <[email protected]>
…-voltage-phasor' into feature/reconfigure-test-case-for-full-observability-check
Signed-off-by: Jerry Guo <[email protected]>
…-voltage-phasor' into feature/reconfigure-test-case-for-full-observability-check
…-case-for-full-observability-check

Observability: re-configure relevant test cases for full observability check
Signed-off-by: Jerry Guo <[email protected]>
Signed-off-by: Jerry Guo <[email protected]>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file was already reviewed. See #1139.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file was already reviewed. See #1139.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file was already reviewed. See #1139.

Copy link

sonarqubecloud bot commented Oct 9, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants