From ac644cd85677af4e9d58a2766d859c8fd1efa512 Mon Sep 17 00:00:00 2001 From: "Dr. Alex A. Anderson" Date: Mon, 18 Nov 2024 13:49:22 -0800 Subject: [PATCH 1/2] update with cimgraph service --- README.md | 171 +++++++++++++++++- .../topo_service_tester.py | 0 .../topologyprocessor.py | 0 .../topologyservice.py | 0 .../toposervicedemo.ipynb | 0 pyproject.toml | 7 +- topo_background_service.py | 105 +++++++++++ 7 files changed, 279 insertions(+), 4 deletions(-) rename topo_service_tester.py => archive/topo_service_tester.py (100%) rename topologyprocessor.py => archive/topologyprocessor.py (100%) rename topologyservice.py => archive/topologyservice.py (100%) rename toposervicedemo.ipynb => archive/toposervicedemo.ipynb (100%) create mode 100644 topo_background_service.py diff --git a/README.md b/README.md index f1d6571..79c2341 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,173 @@ -# GridAPPS-D Toolbox Topology Processor +# GridAPPS-D Topology Processor -The Topology Processor is a lightweight service based on the LinkNet(TM) open-source data structure for mapping CIM ConnectivityNodes and Terminals developed by IncSys Corp. LinkNet(TM) is a trademark of Incremental Systems Corporation and is used with permission. +![GitHub Tag](https://img.shields.io/github/v/tag/GRIDAPPSD/topology-processor) +![GitHub Release Date](https://img.shields.io/github/release-date-pre/GRIDAPPSD/topology-processor) +![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/GRIDAPPSD/topology-processor/deploy-dev-release.yml) +![Libraries.io dependency status for GitHub repo](https://img.shields.io/librariesio/github/GRIDAPPSD/topology-processor) + + + +![GitHub Issues or Pull Requests](https://img.shields.io/github/issues/GRIDAPPSD/topology-processor) +![GitHub Issues or Pull Requests](https://img.shields.io/github/issues-pr/GRIDAPPSD/topology-processor) +![GitHub commit activity](https://img.shields.io/github/commit-activity/t/GRIDAPPSD/topology-processor) + +![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/GRIDAPPSD/topology-processor/total?label=git%20downloads) +![GitHub License](https://img.shields.io/github/license/GRIDAPPSD/topology-processor) +![https://doi.org/10.1109/access.2022.3221132](https://img.shields.io/badge/doi-10.1109/access.2022.3221132-blue) + +This repo contains the GridAPPS-D services for transmission and distribution topology. The core algorithms are currently being migrated to https://github.com/PNNL-CIM-Tools/CIM-Graph-Topology-Processor and rebuilt using CIMantic Graphs labeled property graphs instead of the linked list data structures used in this repo. + +The original topology processor services have been moved into the `archive` directory and based on the LinkNet(TM) open-source data structure for mapping CIM ConnectivityNodes and Terminals developed by IncSys Corp. LinkNet(TM) is a trademark of Incremental Systems Corporation and is used with permission. + +## Switch-Delimited Topology Areas for Distributed Apps and Context Manager + +### Service Call + +The topology service uses a new topic and keyword. `mRID` can be that of a `cim:Feeder`, `cim:FeederArea`, or `cim:DistributionArea`. + +```python +topic = "goss.gridappsd.request.data.cimtopology" + +message = { + "requestType": "GET_DISTRIBUTED_AREAS", + "mRID": "FEEDER-1234-ABCD-MRID", + "resultFormat": "JSON" +} + +message = gapps.get_response(topic, message, timeout=30) +``` + +### Service Response + +The new topology processor response will be formatted as JSON-LD, with `mRID` replaced with `@id` and `@type`: + +```json +{ + "DistributionArea": { + "@id": "uuid-string", + "@type": "DistributionArea", + "Substations": [ + { + "@id": "uuid-string", + "@type": "Substation", + "NormalEnergizedFeeder": [ + { + "@id": "uuid-string", + "@type": "Feeder", + "FeederArea": { + "@id": "uuid-string", + "@type": "FeederArea", + "BoundaryTerminals": [ + { + "@id": "uuid-string", + "@type": "Terminal" + } + ], + "AddressableEquipment": [ + { + "@id": "uuid-string", + "@type": "Breaker" + }, + ], + "UnaddressableEquipment": [ + { + "@id": "uuid-string", + "@type": "PowerTransformer" + }, + { + "@id": "uuid-string", + "@type": "EnergySource" + } + ], + "Measurements": [ + { + "@id": "uuid-string", + "@type": "Analog" + }, + { + "@id": "uuid-string", + "@type": "Discrete" + } + ], + "SwitchAreas": [ + { + "@id": "uuid-string", + "@type": "SwitchArea", + "FeederArea": { + "@id": "uuid-string", + "@type": "FeederArea" + }, + "BoundaryTerminals": [ + { + "@id": "uuid-string", + "@type": "Terminal" + } + ], + "AddressableEquipment": [ + { + "@id": "uuid-string", + "@type": "LinearShuntCompensator" + } + ], + "UnaddressableEquipment": [ + { + "@id": "uuid-string", + "@type": "ACLineSegment" + } + "Measurements": [ + { + "@id": "uuid-string", + "@type": "Analog" + }, + { + "@id": "uuid-string", + "@type": "Discrete" + } + ], + "SecondaryAreas": [ + { + "@id": "uuid-string", + "@type": "SecondaryArea", + "SwitchArea": { + "@id": "uuid-string", + "@type": "SwitchArea" + }, + "BoundaryTerminals": [ + { + "@id": "9d06670e-f8ad-46a1-9854-bba7adaf1cf0", + "@type": "Terminal" + } + ], + "AddressableEquipment": [ + { + "@id": "uuid-string", + "@type": "PowerElectronicsConnection" + } + ], + "UnaddressableEquipment": [ + { + "@id": "uuid-string", + "@type": "EnergyConsumer" + } + ], + "Measurements": [ + { + "@id": "uuid-string", + "@type": "Analog" + } + ] + } + ] + } + ] + } + } + ] + } + ] + } +} +``` ## Real-time Topology Processor Service diff --git a/topo_service_tester.py b/archive/topo_service_tester.py similarity index 100% rename from topo_service_tester.py rename to archive/topo_service_tester.py diff --git a/topologyprocessor.py b/archive/topologyprocessor.py similarity index 100% rename from topologyprocessor.py rename to archive/topologyprocessor.py diff --git a/topologyservice.py b/archive/topologyservice.py similarity index 100% rename from topologyservice.py rename to archive/topologyservice.py diff --git a/toposervicedemo.ipynb b/archive/toposervicedemo.ipynb similarity index 100% rename from toposervicedemo.ipynb rename to archive/toposervicedemo.ipynb diff --git a/pyproject.toml b/pyproject.toml index 94b8d1e..50cb429 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,8 +22,11 @@ repository = "https://github.com/GRIDAPPSD/topology-processor" documentation = "https://github.com/GRIDAPPSD/topology-processor" [tool.poetry.dependencies] -python = "^3.8" -gridappsd-python = {version = "^2023.5.1a9", allow-prereleases = true} +python = "^3.10" +gridappsd-python = {version = "^2024.6.0", allow-prereleases = true} +cim-topology = { git = "https://github.com/PNNL-CIM-Tools/CIM-Graph-Topology-Processor", branch = "cimgraph-refactor"} +cim-graph = { git = "https://github.com/PNNL-CIM-Tools/CIM-Graph.git", branch = "feature/68"} + [tool.poetry.group.dev.dependencies] mock = "^5.0.2" diff --git a/topo_background_service.py b/topo_background_service.py new file mode 100644 index 0000000..4ad3d3e --- /dev/null +++ b/topo_background_service.py @@ -0,0 +1,105 @@ +import os +import json +import time +import logging +from gridappsd import GridAPPSD +from gridappsd.topics import service_input_topic, service_output_topic +from cimgraph.databases import ConnectionParameters, BlazegraphConnection + +from cimtopology.utils import DistributedTopologyMessage +import cimgraph.data_profile.cimhub_2023 as cim + +class TopologyProcessor(GridAPPSD): + + def __init__(self): + os.environ['GRIDAPPSD_APPLICATION_ID'] = 'topology-background-service' + os.environ['GRIDAPPSD_APPLICATION_STATUS'] = 'STARTED' + os.environ['GRIDAPPSD_USER'] = 'app_user' + os.environ['GRIDAPPSD_PASSWORD'] = '1234App' + gapps = GridAPPSD() + assert gapps.connected + self.gapps = gapps + self.log = self.gapps.get_logger() + params = ConnectionParameters(url = "http://localhost:8889/bigdata/namespace/kb/sparql", cim_profile='cimhub_2023', iec61970_301=8) + self.blazegraph = BlazegraphConnection(params) + + + self.log.info('Topology Background Service Started') + + + # GridAPPS-D service + def on_message(self, headers, message): + model_mrid = message['mRID'] + reply_to = headers['reply-to'] + + + if message['requestType'] == 'GET_DISTRIBUTED_AREAS': + + self.log.info(f'Building Distributed Areas for {model_mrid}') + + topo_message = DistributedTopologyMessage() + container = self.blazegraph.get_object(mrid=model_mrid) + + if isinstance(container, cim.Feeder): + topo_message.get_context_from_feeder(container, self.blazegraph) + + elif isinstance(container, cim.FeederArea): + topo_message.get_context_from_feeder_area(container, self.blazegraph) + + elif isinstance(container, cim.DistributionArea): + topo_message.get_context_from_distribution_area(container, self.blazegraph) + + return_message = json.dumps(topo_message.message, indent=4) + del topo_message + self.gapps.send(reply_to, return_message) + + elif message['requestType'] == 'GET_BASE_TOPOLOGY': + Topology = self.get_base_topology(model_mrid) + return_message = { + "response": "not yet supported" + # 'modelID': model_mrid, + # 'feeders': Topology.Feeders, + # 'islands': Topology.Islands, + # 'connectivity': Topology.ConnNodeDict, + # 'equipment': Topology.EquipDict + } + self.gapps.send(reply_to, message) + + elif message['requestType'] == 'GET_SNAPSHOT_TOPOLOGY': + # [Topology, timestamp] = self.get_snapshot_topology(model_mrid, message['simulationID'], message['timestamp']) + message = { + "response": "not yet supported" + # 'modelID': model_mrid, + # 'feeders': Topology.Feeders, + # 'islands': Topology.Islands, + # 'timestamp': timestamp + } + self.gapps.send(reply_to, message) + else: + message = "No valid requestType specified" + self.gapps.send(reply_to, message) + + def get_switch_areas(self, model_mrid): + self.log.info('Building switch areas for ' + str(model_mrid)) + # DistTopo = DistributedTopology(self.gapps, model_mrid) + # message = DistTopo.create_switch_areas(model_mrid) + # return message + + + + + + +def _main(): + topic = "goss.gridappsd.request.data.cimtopology" + os.environ['GRIDAPPSD_USER'] = 'app_user' + os.environ['GRIDAPPSD_PASSWORD'] = '1234App' + gapps = GridAPPSD() + assert gapps.connected + topology = TopologyProcessor() + gapps.subscribe(topic, topology) + while True: + time.sleep(0.1) + +if __name__ == "__main__": + _main() \ No newline at end of file From bd5aebaa8308ce2c0fd66f30601d6d364db1cd31 Mon Sep 17 00:00:00 2001 From: "Dr. Alex A. Anderson" Date: Mon, 18 Nov 2024 13:59:50 -0800 Subject: [PATCH 2/2] add service config --- topo_background_config.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 topo_background_config.py diff --git a/topo_background_config.py b/topo_background_config.py new file mode 100644 index 0000000..844e7d8 --- /dev/null +++ b/topo_background_config.py @@ -0,0 +1,14 @@ +{ + "id":"gridappsd-topology-background-service", + "description": "Topology Processor Background Service", + "creator":"PNNL", + "inputs":[], + "outputs":[], + "static_args":[], + "execution_path":"/gridappsd/services/gridappsd-topology-processor/topo_background_service.py", + "type":"PYTHON", + "launch_on_startup": true, + "prereqs":[], + "multiple_instances":false, + "environmentVariables":[] +} \ No newline at end of file