{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Distribution Feeder Modeling" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This section contains description of distribution feeder modeling concepts and usage of the CIMantic Graphs `FeederModel` class for accessing CIM feeder models in a centralized and distributed manner.\n", "\n", "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" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from cimgraph import utils\n", "from mermaid import Mermaid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Distribution Feeders in CIM\n", "\n", "Full modeling of North American distribution circuits was introduced in CIM 17 to include include unbalanced medium-voltage networks, low-voltage customer-side equipment, DERs, and advanced metering infrastructure (AMI) usage points. An example of a very simple distribution feeder is shown and explained in detail below:\n", "\n", "![basic-feeder](./images/4_2_feeder.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* `ConnectivityNode` used for 3-phase buses. Separate modeling of single-phase nodes not used\n", "\n", "* `Terminal` used to connect conducting equipment to a bus\n", "\n", "* `ACLineSegment` used for overhead lines, underground cables, and secondary triplex lines. Phasing represented using `ACLineSegmentPhase`\n", "\n", "* Representation of downstream switching devices using `Recloser`, `Sectionaliser`, etc.\n", "Poletop `LinearShuntCompensator` and `RatioTapChanger` devices\n", "\n", "* `EnergySource` slack bus at substation\n", "\n", "* Loads can be represented at medium voltage level or broken down into individual `EnergyConsumer` customers with split-phase `TransformerTank`\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "----" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## FeederModel Class\n", "\n", "The `FeederModel` class in CIMantic Graphs provides the interface for users to access a single feeder at a time (in a manner similar to study tools such as EPRI OpenDSS or Eaton CYME). The class provides access to the typed property graph and API methods to read and write to a data source.\n", "\n", "It can be imported using" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "from cimgraph.models import FeederModel" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The structure of the distribution network graphs and API methods are explained in the sections below" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "----" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Loading a FeederModel from an XML File\n", "\n", "When working with small test cases (e.g. IEEE 13 and 123 bus models), it is possible to use CIMantic Graphs without any database and instead directly build the graph from an XML file. *Note: large models (e.g. IEEE 8500) will see poor performance when reading directly from the XML (approx 2 minutes to load all triples and build the full network graph).*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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](../02_cim_profiles/2_1_profiles_overview.ipynb)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "import os\n", "os.environ['CIMG_CIM_PROFILE'] = 'cimhub_2023'\n", "import cimgraph.data_profile.cimhub_2023 as cim" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, use the `XMLFile` interface to open the XML file:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "from cimgraph.databases import XMLFile\n", "file = XMLFile(filename='../../sample_models/ieee13.xml')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, create a new `FeederModel` network class to load the feeder into the graph:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "network = FeederModel(container=cim.Feeder(), connection=file)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The complete network model, including both forward and reverse associations between all objects in the model has now been loaded into the FeederModel graph. \n", "\n", "To demonstrate the structure of resulting FeederModel network, we can display a sample breaker object:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n", " \n", " " ], "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Get first breaker in graph\n", "breaker = network.first(cim.Breaker)\n", "# Display the line\n", "Mermaid(utils.get_mermaid(breaker))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "----" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Loading a FeederModel from a Database\n", "\n", "When working with large models (e.g. IEEE 8500/9500 node or utility networks), it is generally advisable to load the the models into a database and then use CIM-Graph to access the feeder via its internal API. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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](../02_cim_profiles/2_1_profiles_overview.ipynb)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import os\n", "os.environ['CIMG_CIM_PROFILE'] = 'cimhub_2023'\n", "import cimgraph.data_profile.cimhub_2023 as cim" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, use the interface class to your preferred database to authenticate and connect to the database." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from cimgraph.databases import BlazegraphConnection\n", "os.environ['CIMG_URL'] = 'http://localhost:8889/bigdata/namespace/kb/sparql'\n", "database = BlazegraphConnection()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, create a CIM `Feeder` object with the correct model mRID. This can be done by a) directly creating the object or b) retrieving it from the database using the `.get_object()` method." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "feeder = cim.Feeder(mRID=\"49AD8E07-3BF9-A4E2-CB8F-C3722F837B62\")\n", "print(feeder)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "feeder = database.get_object(mRID=\"49AD8E07-3BF9-A4E2-CB8F-C3722F837B62\")\n", "print(feeder)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, create a new `FeederModel` class and pass in the feeder and database objects as the input arguments. This will authenticate with the database and load the base feeder topology into the graph" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "network = FeederModel(container=feeder, connection=database)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To ensure performance on large models, only the minimum set of `Equipment`, `ConnectivityNode`, and `Terminal` objects are loaded into graph with only their UUID identifiers. All attributes are left as `None` or `[]` until the object classes are populated using the `.get_all_edges` method." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Get first breaker in graph\n", "breaker = network.first(cim.Breaker)\n", "# Display the breaker\n", "Mermaid(utils.get_mermaid(breaker))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "----" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## FeederModel.graph\n", "\n", "The `.graph` attribute of the GraphModel dataclass provides the interface to the typed property graph with all data contained in the network model.\n", "\n", "It is a dictionary typed first by class type (e.g. `cim.ACLineSegment`) and then by UUID of each element within the network model.\n", "\n", "All objects within the graph (if added using the API) are forced to have a unique UUID identifier." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Graph Initialization\n", "\n", "The CIM `Feeder` class is used to describe containment and naming of equipment and nodes within distribution feeders. For most applications, each feeder is described as having a single normal energizing substation that serves as the source for all downstream customers. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "diagram_text = utils.get_mermaid_path(cim.Feeder, \"Equipments\", show_attributes=False)\n", "diagram_text = utils.add_mermaid_path(cim.Feeder, \"ConnectivityNodes\", diagram_text, show_attributes=False)\n", "diagram_text = utils.add_mermaid_path(cim.Feeder, \"NormalEnergizingSubstation\", diagram_text, show_attributes=False)\n", "diagram_text = utils.add_mermaid_path(cim.Equipment, \"Measurements\", diagram_text, show_attributes=False)\n", "diagram_text = utils.add_mermaid_path(cim.ConnectivityNode, \"Terminals\", diagram_text, show_attributes=False)\n", "\n", "Mermaid(diagram_text)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "----" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Graph Expansion\n", "\n", "One of the key features of CIMantic graphs is the elimination of all custom database queries to access information regarding equipment, impedances, measurements etc. Instead, a single API method is used to extract all information about the \n", "\n", "The `.get_all_edges()` method is the core library method that enables the flexibility of CIM-Graph to query for CIM objects of any class and build the knowledge graph without custom queries.\n", "\n", "The arguments of the method are\n", "\n", "* cim_class (type): The CIM class for which to retrieve edges (e.g. `cim.Breaker`)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "network.get_all_edges(cim.Breaker)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Display the same breaker\n", "Mermaid(utils.get_mermaid(breaker))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [] } ], "metadata": { "kernelspec": { "display_name": ".venv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.12" } }, "nbformat": 4, "nbformat_minor": 2 }