Network Reduction#

The grid-data-models (GDM) package provides helper functions to facilitate the reduction of distribution models, making them more computationally efficient for specific analyses. Model reduction techniques are particularly useful when studying large distribution networks where simulating the entire model is unnecessary or resource-intensive.

GDM currently supports two model reduction formulations:

  • Three-phase balanced representation

  • Primary network representation

We start by loading a sample DistributionSystem.

import sys

from gdm.distribution import DistributionSystem
from gdmloader.constants import GCS_CASE_SOURCE
from gdmloader.source import SystemLoader

from IPython.display import display, HTML
from loguru import logger
import plotly.io as pio

logger.remove()

# Add a new sink with the desired minimum level
logger.add(sys.stderr, level="WARNING")

gdm_loader = SystemLoader()
gdm_loader.add_source(GCS_CASE_SOURCE)

distribution_system: DistributionSystem = gdm_loader.load_dataset(
    source_name=GCS_CASE_SOURCE.name,
    system_type=DistributionSystem,
    dataset_name="p1rhs7_1247",
)
distribution_system.name = "p1rhs7_1247"
distribution_system.info()
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/site-packages/gdmloader/source.py:124, in SystemLoader.load_dataset(self, system_type, source_name, dataset_name, version)
    123 try:
--> 124     source.fs.get(
    125         remote_folder,
    126         str(local_folder),
    127         recursive=True,
    128     )
    129 except FileNotFoundError:

File /opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/site-packages/fsspec/asyn.py:118, in sync_wrapper.<locals>.wrapper(*args, **kwargs)
    117 self = obj or args[0]
--> 118 return sync(self.loop, func, *args, **kwargs)

File /opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/site-packages/fsspec/asyn.py:103, in sync(loop, func, timeout, *args, **kwargs)
    102 elif isinstance(return_result, BaseException):
--> 103     raise return_result
    104 else:

File /opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/site-packages/fsspec/asyn.py:56, in _runner(event, coro, result, timeout)
     55 try:
---> 56     result[0] = await coro
     57 except Exception as ex:

File /opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/site-packages/fsspec/asyn.py:645, in AsyncFileSystem._get(self, rpath, lpath, recursive, callback, maxdepth, **kwargs)
    644 rpath = self._strip_protocol(rpath)
--> 645 rpaths = await self._expand_path(
    646     rpath, recursive=recursive, maxdepth=maxdepth
    647 )
    648 if source_is_str and (not recursive or maxdepth is not None):
    649     # Non-recursive glob does not copy directories

File /opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/site-packages/fsspec/asyn.py:883, in AsyncFileSystem._expand_path(self, path, recursive, maxdepth)
    882 if isinstance(path, str):
--> 883     out = await self._expand_path([path], recursive, maxdepth)
    884 else:

File /opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/site-packages/fsspec/asyn.py:912, in AsyncFileSystem._expand_path(self, path, recursive, maxdepth)
    911 if not out:
--> 912     raise FileNotFoundError(path)
    913 return sorted(out)

FileNotFoundError: ['gdm_data/data/DistributionSystem/2_2_0/p1rhs7_1247']

During handling of the above exception, another exception occurred:

ValueError                                Traceback (most recent call last)
Cell In[1], line 19
     16 gdm_loader = SystemLoader()
     17 gdm_loader.add_source(GCS_CASE_SOURCE)
---> 19 distribution_system: DistributionSystem = gdm_loader.load_dataset(
     20     source_name=GCS_CASE_SOURCE.name,
     21     system_type=DistributionSystem,
     22     dataset_name="p1rhs7_1247",
     23 )
     24 distribution_system.name = "p1rhs7_1247"
     25 distribution_system.info()

File /opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/site-packages/gdmloader/source.py:131, in SystemLoader.load_dataset(self, system_type, source_name, dataset_name, version)
    129     except FileNotFoundError:
    130         msg = f"{remote_folder=} not found! Check the URL: {source.url}/{remote_folder}"
--> 131         raise ValueError(msg)
    133 system_file = list(dataset_folder.rglob("*.json"))[0]
    134 return system_type.from_json(system_file)

ValueError: remote_folder='gdm_data/data/DistributionSystem/2_2_0/p1rhs7_1247' not found! Check the URL: https://storage.googleapis.com/gdm_data/gdm_data/data/DistributionSystem/2_2_0/p1rhs7_1247
from gdm.distribution.enums import MapType, PlotingStyle

fig = distribution_system.plot(
    map_type=MapType.SCATTER_MAP,
    style=PlotingStyle.OPEN_STREET_MAP,
    flip_coordinates=True,
    show=False,
)
display(HTML(pio.to_html(fig, include_plotlyjs="cdn", full_html=False)))

Three-Phase Balanced Representation#

The model is reduced by representing only the three-phase buses in the system. This formulation is particularly useful for system-level studies where maintaining a balanced representation of the network is sufficient.

from gdm.distribution.model_reduction import reduce_to_three_phase_system

three_phase_gdm_model: DistributionSystem = reduce_to_three_phase_system(
    distribution_system, name="reduced_system", agg_timeseries=False
)
three_phase_gdm_model.info()
System                                   
┏━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓
┃ Property                       Value ┃
┡━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩
│ System name          │ reduced_system │
│ Data format version  │          2.0.1 │
│ Components attached  │           1953 │
│ Time Series attached │              0 │
│ Description          │                │
└──────────────────────┴────────────────┘
Component Information                       
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┓
┃ Type                              Count ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━┩
│ DistributionBus                  │   328 │
│ DistributionLoad                 │   190 │
│ DistributionTransformer          │    22 │
│ DistributionTransformerEquipment │     2 │
│ DistributionVoltageSource        │     1 │
│ LoadEquipment                    │   190 │
│ Location                         │   328 │
│ MatrixImpedanceBranch            │   248 │
│ MatrixImpedanceBranchEquipment   │     8 │
│ MatrixImpedanceSwitch            │    57 │
│ MatrixImpedanceSwitchEquipment   │     9 │
│ PhaseLoadEquipment               │   556 │
│ PhaseVoltageSourceEquipment      │     3 │
│ VoltageLimitSet                  │     6 │
│ VoltageSourceEquipment           │     1 │
│ WindingEquipment                 │     4 │
└──────────────────────────────────┴───────┘
fig = three_phase_gdm_model.plot(
    map_type=MapType.SCATTER_MAP,
    style=PlotingStyle.OPEN_STREET_MAP,
    flip_coordinates=True,
    show=False,
)
display(HTML(pio.to_html(fig, include_plotlyjs="cdn", full_html=False)))

Primary Network Representation#

This approach involves lumping loads, generation, and capacitors and representing them on the primary network. All secondary networks are removed, resulting in a streamlined model that captures the essential characteristics of the primary distribution network while discarding unnecessary details.

from gdm.distribution.model_reduction import reduce_to_primary_system

primary_gdm_model: DistributionSystem = reduce_to_primary_system(
    distribution_system, name="reduced_system", agg_timeseries=False
)
primary_gdm_model.info()
System                                   
┏━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓
┃ Property                       Value ┃
┡━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩
│ System name          │ reduced_system │
│ Data format version  │          2.0.1 │
│ Components attached  │           4289 │
│ Time Series attached │              0 │
│ Description          │                │
└──────────────────────┴────────────────┘
Component Information                       
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┓
┃ Type                              Count ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━┩
│ DistributionBus                  │   796 │
│ DistributionLoad                 │   502 │
│ DistributionTransformer          │     1 │
│ DistributionTransformerEquipment │     1 │
│ DistributionVoltageSource        │     1 │
│ LoadEquipment                    │   502 │
│ Location                         │   796 │
│ MatrixImpedanceBranch            │   629 │
│ MatrixImpedanceBranchEquipment   │     8 │
│ MatrixImpedanceFuse              │    81 │
│ MatrixImpedanceFuseEquipment     │     6 │
│ MatrixImpedanceSwitch            │    84 │
│ MatrixImpedanceSwitchEquipment   │    15 │
│ PhaseLoadEquipment               │   856 │
│ PhaseVoltageSourceEquipment      │     3 │
│ TimeCurrentCurve                 │     1 │
│ VoltageLimitSet                  │     4 │
│ VoltageSourceEquipment           │     1 │
│ WindingEquipment                 │     2 │
└──────────────────────────────────┴───────┘
fig = primary_gdm_model.plot(
    map_type=MapType.SCATTER_MAP,
    style=PlotingStyle.OPEN_STREET_MAP,
    flip_coordinates=True,
    show=False,
)
display(HTML(pio.to_html(fig, include_plotlyjs="cdn", full_html=False)))

Support for Time Series Aggregation#

Model reduction algorithms aggregate components. Additionally, agg_timeseries can be set to true to aggregate time series profiles.

from infrasys.time_series_models import SingleTimeSeries

three_phase_gdm_model: DistributionSystem = reduce_to_three_phase_system(
    distribution_system,
    name="reduced_system",
    agg_timeseries=True,
    time_series_type=SingleTimeSeries,
)