Node Breaker Models¶
This section contains description of transmission node-breaker modeling concepts and usage of the CIMantic Graphs NodeBreakerModel class for accessing CIM feeder models in a centralized and distributed manner.
All diagrams within this page have been auto-generated using mermaid.js and the cimgraph.utils module of CIMantic Graphs, which can be imported using
from cimgraph import utils
from mermaid import Mermaid
Transmission Network Models in CIM¶
CIM was originally designed to support full node-breaker modeling of transmission network models and substations
# TODO: Provide sample Node Breaker Model diagram
Loading a FeederModel from an XML File¶
It is possible to use CIMantic Graphs without any database and instead directly build the graph from an XML file.
The first step is to import the correct CIM profile to use and set the associated environment variable used by CIM-Graph. For an explanation of CIM profiles, see Profiles Overview
import os
os.environ['CIMG_CIM_PROFILE'] = 'cim17v40' # import and env var must match
import cimgraph.data_profile.cim17v40 as cim # import and env var must match
Next, use the XMLFile interface to open the XML file:
from cimgraph.databases import XMLFile
file = XMLFile(filename='../../sample_models/maple10nodebreaker.xml')
If custom extensions are used, provide a namespaces dictionary mapping the prefix to the custom namespaces:
namespaces={'cim': 'http://iec.ch/TC57/CIM100#',
'gmdm': 'http://epri.com/gmdm/2025#',
'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
'gad': 'http://gridappsd.org/CIM/extension#'}
file = XMLFile(filename='../../sample_models/maple10nodebreaker.xml',
namespaces=namespaces)
Finally, create a new NodeBreakerModel network class to load the transmission model into the graph:
from cimgraph.models import NodeBreakerModel
network = NodeBreakerModel(container=None, connection=file)
# Get first breaker in graph
breaker = network.first(cim.Breaker)
# Display the line
Mermaid(utils.get_mermaid(breaker))
Modifying Files¶
Objects can be created, modified, or deleted using the .add_to_graph(object), .delete(object), and .create('incremental_file.xml') methods
new_breaker = cim.Breaker(name='new_breaker', open=False)
network.add_to_graph(new_breaker)
network.delete(new_breaker)
network.modify(breaker, 'open', True, incremental_file='breaker_incremental.xml')
Saving to a File¶
Use the utils.write_xml() and utils.write_json_ld methods to save modified network to file
from cimgraph import utils
utils.write_xml(network, '../../sample_models/maple10nodebreaker_modified.xml')
utils.write_json_ld(network, '../../sample_models/maple10nodebreaker_modified.jsonld')
Advanced Concepts - Distributed Modeling¶
These features are still in development and intended to provide a preview of planned capabilities. Under certain use cases, users may wish to instantiate a new typed property graph for each substation and voltage level as its own standalone network.
network = NodeBreakerModel(container=None, connection=file, distributed = True)
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) Cell In[12], line 1 ----> 1 network = NodeBreakerModel(container=None, connection=file, distributed = True) File <string>:10, in __init__(self, container, connection, distributed, graph, incrementals, __class_iter__, aggregate_lower_areas) File ~/CIM-Graph/cimgraph/models/node_breaker_model.py:51, in NodeBreakerModel.__post_init__(self) 47 if self.connection is not None: # Check if connection has been specified 48 # self.cim = self.connection.cim # Set CIM data profile 49 if self.distributed: # Check if distributed flag is true 50 # Build distributed network model ---> 51 self.initialize_distributed_model(self.container) 52 else: 53 # Otherwise build centralized network model 54 self.initialize_centralized_model(self.container) File ~/CIM-Graph/cimgraph/models/node_breaker_model.py:65, in NodeBreakerModel.initialize_distributed_model(self, container) 63 def initialize_distributed_model(self, container: object) -> None: 64 self.graph = {} ---> 65 self.add_to_graph(self.container) 66 self.distributed_areas = {} File ~/CIM-Graph/cimgraph/models/graph_model.py:56, in GraphModel.add_to_graph(self, obj, graph) 54 if type(obj) not in graph: 55 graph[type(obj)] = {} ---> 56 if obj.identifier not in graph[type(obj)]: 57 graph[type(obj)][obj.identifier] = obj AttributeError: 'NoneType' object has no attribute 'identifier'
for sr_area in network.distributed_areas[cim.SubGeographicalRegion].values():
print("subregion", sr_area.container.name)
for sub_area in sr_area.distributed_areas[cim.Substation].values():
print("substation", sub_area.container.name)
for vl_area in sub_area.distributed_areas[cim.VoltageLevel].values():
print("voltage level", vl_area.container.name)
for feeder_area in sub_area.distributed_areas[cim.Feeder].values():
print("feeder", feeder_area.container.name, "contains PV aggregates")
feeder_area.get_all_edges(cim.PowerElectronicsConnection)
feeder_area.get_all_edges(cim.PhotoVoltaicUnit)
if cim.PowerElectronicsConnection in feeder_area.graph:
for pv in feeder_area.graph[cim.PowerElectronicsConnection].values():
print(pv.name, float(pv.p)/1000000, "MW")
else:
print("none")