Partitioning#
Partitioning divides a network into clusters of nodes based on distance metrics. NPAP provides four partitioning strategy families, each suited for different use cases.
Overview#
Strategy Family |
Distance Metric |
Use Case |
|---|---|---|
Geographical |
Euclidean / Haversine |
Spatial proximity clustering |
Electrical |
PTDF-based |
Electrical behavior clustering |
VA Geographical |
Geographical + Voltage aware |
Multi-voltage-level networks |
VA Electrical |
PTDF + Voltage aware |
Multi-voltage-level electrical clustering |
Basic Usage#
All partitioning is done through the PartitionAggregatorManager:
import npap
manager = npap.PartitionAggregatorManager()
manager.load_data("networkx_direct", graph=G)
# Partition the network
partition_result = manager.partition(
strategy="geographical_kmeans",
n_clusters=10
)
The result is a PartitionResult object:
print(partition_result.mapping)
# {0: ['bus_1', 'bus_2'], 1: ['bus_3', 'bus_4'], ...}
print(partition_result.n_clusters)
# 10
print(partition_result.strategy_name)
# 'geographical_kmeans'
AC-Island Awareness#
What Are AC Islands?#
In networks with HVDC links, AC-connected regions form AC islands. These islands:
Are electrically separate in AC sense
Connected only through DC links
Have independent power flow characteristics
How NPAP Handles AC Islands#
When nodes have a ac_island attribute (automatically set by va_loader):
Distance matrices include infinite distances between islands
Clustering algorithms using precomputed distances respect these boundaries
Partitions never span across AC island boundaries
Algorithm Support#
Algorithm |
AC-Island Support |
|---|---|
K-Means |
No (works on raw coordinates) |
K-Medoids |
Yes |
DBSCAN |
Yes |
HDBSCAN |
Yes |
Hierarchical (non-ward) |
Yes |
Hierarchical (ward) |
No |
Note
K-Means and Ward linkage will issue a warning if AC islands are detected but will proceed without respecting island boundaries.
Choosing a Strategy#
Decision Guide#
flowchart TD
A[Start] --> B{Multi-voltage?}
B -->|Yes| C{Need electrical distance?}
B -->|No| D{Need electrical distance?}
C -->|Yes| E[va_electrical_*]
C -->|No| F[va_geographical_*]
D -->|Yes| G[electrical_*]
D -->|No| H{AC islands?}
H -->|Yes| I[geographical_kmedoids_*]
H -->|No| K[geographical_kmeans]
style A fill:#2993B5,stroke:#1d6f8a,color:#fff
style B fill:#FFBF00,stroke:#cc9900,color:#1e293b
style C fill:#FFBF00,stroke:#cc9900,color:#1e293b
style D fill:#FFBF00,stroke:#cc9900,color:#1e293b
style E fill:#0fad6b,stroke:#076b3f,color:#fff
style F fill:#0fad6b,stroke:#076b3f,color:#fff
style G fill:#0fad6b,stroke:#076b3f,color:#fff
style H fill:#FFBF00,stroke:#cc9900,color:#1e293b
style I fill:#0fad6b,stroke:#076b3f,color:#fff
style K fill:#0fad6b,stroke:#076b3f,color:#fff
Recommendations by Use Case#
Use Case |
Recommended Strategy |
|---|---|
Geographical clustering |
|
Geographical with AC islands |
|
Electrical behavior grouping |
|
Multi-voltage network |
|
Unknown cluster count |
|
Performance Comparison#
Strategy |
Speed |
Memory |
Robustness |
|---|---|---|---|
K-Means |
Fast |
Low |
Medium |
K-Medoids |
Medium |
High (distance matrix) |
High |
DBSCAN |
Medium |
Medium |
High |
HDBSCAN |
Slow |
High |
Very High |
Hierarchical |
Medium |
High |
High |
Configuration Options#
All geographical partitioning strategies share a common configuration:
from npap.partitioning import GeographicalConfig
config = GeographicalConfig(
random_state=42, # Reproducibility
max_iter=300, # K-Means iterations
n_init=10, # K-Means initializations
hierarchical_linkage="ward", # Hierarchical linkage
infinite_distance=1e4 # AC island separation
)
Electrical strategies have their own configuration:
from npap.partitioning import ElectricalDistanceConfig
config = ElectricalDistanceConfig(
zero_reactance_replacement=1e-5,
regularization_factor=1e-10,
infinite_distance=1e4
)
Working with Partition Results#
Inspecting Results#
partition = manager.partition("geographical_kmeans", n_clusters=5)
# Cluster mapping
print(partition.mapping)
# {0: ['bus_1', 'bus_2'], 1: ['bus_3'], ...}
# Number of clusters
print(partition.n_clusters)
# Strategy used
print(partition.strategy_name)
# Graph hash for validation
print(partition.original_graph_hash)
Reusing Partitions#
Partition results can be reused for multiple aggregations:
# Partition once
partition = manager.partition("geographical_kmeans", n_clusters=10)
# Aggregate with different profiles
simple_agg = manager.aggregate(partition, mode=AggregationMode.SIMPLE)
geo_agg = manager.aggregate(partition, mode=AggregationMode.GEOGRAPHICAL)
Validation#
NPAP validates that partitions match their source graph:
# This will raise GraphCompatibilityError if graph changed
aggregated = manager.aggregate(partition)