Skip to content

Commit 938307d

Browse files
docs: add demo (#38)
Signed-off-by: jaapschoutenalliander <[email protected]>
1 parent e21ddfd commit 938307d

File tree

7 files changed

+307
-3
lines changed

7 files changed

+307
-3
lines changed

docs/Makefile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@
33
# SPDX-License-Identifier: MPL-2.0
44

55
# Minimal makefile for Sphinx documentation
6-
#
76

87
# You can set these variables from the command line, and also
98
# from the environment for the first two.
109
SPHINXOPTS ?=
1110
SPHINXBUILD ?= sphinx-build
12-
SOURCEDIR = source
11+
SOURCEDIR = .
1312
BUILDDIR = _build
1413

1514
# Put it first so that "make" without argument is like "make help".
Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"# Connecting a new consumer\n",
8+
"\n",
9+
"This demo shows how to use power-grid-model-ds to simulate a new consumer to be connected to the grid\n",
10+
"\n",
11+
"1. First we create an extension of the Grid objects with properties we want to use in this context\n",
12+
"2. We create a random grid structure for the purpose of the demo\n",
13+
"3. We define functions that add a new consumer to the grid and simulate its impact"
14+
]
15+
},
16+
{
17+
"cell_type": "code",
18+
"execution_count": null,
19+
"metadata": {},
20+
"outputs": [],
21+
"source": [
22+
"from dataclasses import dataclass\n",
23+
"\n",
24+
"import numpy as np\n",
25+
"from numpy.typing import NDArray\n",
26+
"\n",
27+
"from power_grid_model_ds import Grid\n",
28+
"from power_grid_model_ds.arrays import LineArray, NodeArray\n",
29+
"\n",
30+
"\n",
31+
"class ExtendedNodeArray(NodeArray):\n",
32+
" \"\"\"Extends the node array with the simulated voltage and coordinates\"\"\"\n",
33+
"\n",
34+
" _defaults = {\"u\": 0}\n",
35+
"\n",
36+
" u: NDArray[np.float64]\n",
37+
" x_coor: NDArray[np.float64]\n",
38+
" y_coor: NDArray[np.float64]\n",
39+
"\n",
40+
" @property\n",
41+
" def is_overloaded(self):\n",
42+
" return np.logical_or(self.u > 1.1 * self.u_rated, self.u < 0.9 * self.u_rated)\n",
43+
"\n",
44+
"\n",
45+
"class ExtendedLineArray(LineArray):\n",
46+
" \"\"\"Extends the line array with current output\"\"\"\n",
47+
"\n",
48+
" _defaults = {\"i_from\": 0}\n",
49+
"\n",
50+
" i_from: NDArray[np.float64]\n",
51+
"\n",
52+
" @property\n",
53+
" def is_overloaded(self):\n",
54+
" return self.i_from > self.i_n\n",
55+
"\n",
56+
"\n",
57+
"@dataclass\n",
58+
"class ExtendedGrid(Grid):\n",
59+
" node: ExtendedNodeArray\n",
60+
" line: ExtendedLineArray"
61+
]
62+
},
63+
{
64+
"cell_type": "code",
65+
"execution_count": null,
66+
"metadata": {},
67+
"outputs": [],
68+
"source": [
69+
"from power_grid_model_ds.generators import RadialGridGenerator\n",
70+
"\n",
71+
"grid_generator = RadialGridGenerator(grid_class=ExtendedGrid, nr_nodes=20, nr_sources=1, nr_nops=10)\n",
72+
"grid = grid_generator.run(seed=0)\n",
73+
"\n",
74+
"grid.set_feeder_ids()\n",
75+
"\n",
76+
"grid.node.x_coor = np.random.uniform(100, 500, len(grid.node))\n",
77+
"grid.node.y_coor = np.random.uniform(100, 500, len(grid.node))"
78+
]
79+
},
80+
{
81+
"cell_type": "markdown",
82+
"metadata": {},
83+
"source": [
84+
"First we create a new consumer, with a location and a load demand"
85+
]
86+
},
87+
{
88+
"cell_type": "code",
89+
"execution_count": null,
90+
"metadata": {},
91+
"outputs": [],
92+
"source": [
93+
"from power_grid_model import LoadGenType\n",
94+
"\n",
95+
"from power_grid_model_ds.arrays import SymLoadArray\n",
96+
"from power_grid_model_ds.enums import NodeType\n",
97+
"\n",
98+
"\n",
99+
"def create_new_consumer_arrays(\n",
100+
" u_rated: float, x_coor: float, y_coor: float, p_specified: float, q_specified: float\n",
101+
") -> tuple[ExtendedNodeArray, SymLoadArray]:\n",
102+
" new_consumer = ExtendedNodeArray(\n",
103+
" u_rated=[u_rated],\n",
104+
" node_type=[NodeType.UNSPECIFIED],\n",
105+
" x_coor=[x_coor],\n",
106+
" y_coor=[y_coor],\n",
107+
" )\n",
108+
" new_consumer_load = SymLoadArray(\n",
109+
" node=[new_consumer.get_empty_value(\"id\")],\n",
110+
" status=[1],\n",
111+
" type=[LoadGenType.const_power],\n",
112+
" p_specified=[p_specified],\n",
113+
" q_specified=[q_specified],\n",
114+
" )\n",
115+
" return new_consumer, new_consumer_load\n",
116+
"\n",
117+
"\n",
118+
"new_consumer, new_consumer_load = create_new_consumer_arrays(10_500, 300, 300, 1_000_000, 200_000)"
119+
]
120+
},
121+
{
122+
"cell_type": "markdown",
123+
"metadata": {},
124+
"source": [
125+
"Now lets define some functions that add the new consumer by connecting it to the closest node"
126+
]
127+
},
128+
{
129+
"cell_type": "code",
130+
"execution_count": null,
131+
"metadata": {},
132+
"outputs": [],
133+
"source": [
134+
"from power_grid_model_ds._core.load_flow import PowerGridModelInterface\n",
135+
"\n",
136+
"R_PER_KM = 0.1\n",
137+
"X_PER_KM = 0.1\n",
138+
"\n",
139+
"\n",
140+
"def find_closest_node(grid: ExtendedGrid, x: float, y: float) -> int:\n",
141+
" dist = np.sqrt((grid.node.x_coor - x) ** 2 + (grid.node.y_coor - y) ** 2)\n",
142+
" return np.argmin(dist)\n",
143+
"\n",
144+
"\n",
145+
"def connect_new_consumer(\n",
146+
" grid: ExtendedGrid,\n",
147+
" new_consumer: ExtendedNodeArray,\n",
148+
" new_consumer_load: SymLoadArray,\n",
149+
"):\n",
150+
" closest_node_idx = find_closest_node(\n",
151+
" grid=grid,\n",
152+
" x=new_consumer.x_coor[0],\n",
153+
" y=new_consumer.y_coor[0],\n",
154+
" )\n",
155+
" closest_node = grid.node[closest_node_idx]\n",
156+
"\n",
157+
" grid.append(new_consumer)\n",
158+
" new_consumer_load.node = new_consumer.id\n",
159+
" grid.append(new_consumer_load)\n",
160+
"\n",
161+
" dist = np.sqrt((closest_node.x_coor - new_consumer.x_coor) ** 2 + (closest_node.y_coor - new_consumer.y_coor) ** 2)\n",
162+
"\n",
163+
" new_line = ExtendedLineArray(\n",
164+
" from_node=[closest_node.id],\n",
165+
" to_node=[new_consumer.id],\n",
166+
" from_status=[1],\n",
167+
" to_status=[1],\n",
168+
" r1=[R_PER_KM * dist / 1_000],\n",
169+
" x1=[X_PER_KM * dist / 1_000],\n",
170+
" c1=[0],\n",
171+
" tan1=[0],\n",
172+
" i_n=[200],\n",
173+
" )\n",
174+
" grid.append(new_line)\n",
175+
"\n",
176+
"\n",
177+
"def update_grid(grid: ExtendedGrid):\n",
178+
" # Set the new feeder ids\n",
179+
" grid.set_feeder_ids()\n",
180+
"\n",
181+
" # Update the loadflow\n",
182+
" core_interface = PowerGridModelInterface(grid=grid)\n",
183+
"\n",
184+
" core_interface.create_input_from_grid()\n",
185+
" core_interface.calculate_power_flow()\n",
186+
" core_interface.update_grid()"
187+
]
188+
},
189+
{
190+
"cell_type": "code",
191+
"execution_count": null,
192+
"metadata": {},
193+
"outputs": [],
194+
"source": [
195+
"connect_new_consumer(grid, new_consumer, new_consumer_load)\n",
196+
"update_grid(grid)"
197+
]
198+
},
199+
{
200+
"cell_type": "markdown",
201+
"metadata": {},
202+
"source": [
203+
"We can inspect the results\n",
204+
"\n",
205+
"- The grid has been extended (graph and arrays)\n",
206+
"- Load values have been updated on node and line arrays\n",
207+
"- The feeder ids have been updated for the new consumer"
208+
]
209+
},
210+
{
211+
"cell_type": "code",
212+
"execution_count": null,
213+
"metadata": {},
214+
"outputs": [],
215+
"source": [
216+
"print(grid.node)"
217+
]
218+
},
219+
{
220+
"cell_type": "code",
221+
"execution_count": null,
222+
"metadata": {},
223+
"outputs": [],
224+
"source": [
225+
"print(grid.line)"
226+
]
227+
},
228+
{
229+
"cell_type": "code",
230+
"execution_count": null,
231+
"metadata": {},
232+
"outputs": [],
233+
"source": [
234+
"print(f\"Overloaded nodes: {grid.node[grid.node.is_overloaded].id}\")\n",
235+
"print(f\"Overloaded lines: {grid.line[grid.line.is_overloaded].id}\")"
236+
]
237+
},
238+
{
239+
"cell_type": "markdown",
240+
"metadata": {},
241+
"source": [
242+
"Now simulate more consumers being added, as to see how this will lead to overloads"
243+
]
244+
},
245+
{
246+
"cell_type": "code",
247+
"execution_count": null,
248+
"metadata": {},
249+
"outputs": [],
250+
"source": [
251+
"for _ in range(10):\n",
252+
" new_consumer, new_consumer_load = create_new_consumer_arrays(\n",
253+
" 10_500, np.random.uniform(0, 500), np.random.uniform(0, 500), 1_000_000, 200_000\n",
254+
" )\n",
255+
" connect_new_consumer(grid, new_consumer, new_consumer_load)\n",
256+
"update_grid(grid)\n",
257+
"\n",
258+
"print(f\"Overloaded nodes: {grid.node[grid.node.is_overloaded].id}\")\n",
259+
"print(f\"Overloaded lines: {grid.line[grid.line.is_overloaded].id}\")"
260+
]
261+
}
262+
],
263+
"metadata": {
264+
"kernelspec": {
265+
"display_name": ".venv",
266+
"language": "python",
267+
"name": "python3"
268+
},
269+
"language_info": {
270+
"codemirror_mode": {
271+
"name": "ipython",
272+
"version": 3
273+
},
274+
"file_extension": ".py",
275+
"mimetype": "text/x-python",
276+
"name": "python",
277+
"nbconvert_exporter": "python",
278+
"pygments_lexer": "ipython3",
279+
"version": "3.12.6"
280+
}
281+
},
282+
"nbformat": 4,
283+
"nbformat_minor": 2
284+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SPDX-FileCopyrightText: Contributors to the Power Grid Model project <[email protected]>
2+
3+
SPDX-License-Identifier: MPL-2.0

docs/demos/index.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.. SPDX-FileCopyrightText: Contributors to the Power Grid Model project <[email protected]>
2+
..
3+
.. SPDX-License-Identifier: MPL-2.0
4+
5+
Demos
6+
======================
7+
These showcase integrated examples of how to use the PGM-DS library.
8+
They are designed to help users understand the practical applications of the library,
9+
demonstrating key features and common use cases.
10+
11+
.. toctree::
12+
:maxdepth: 1
13+
:caption: Contents:
14+
15+
connecting_new_consumer

docs/examples/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
Examples
66
======================
77

8+
These example explain the PGM-DS interface and how to use it.
9+
810
.. toctree::
911
:maxdepth: 1
1012
:caption: Contents:

docs/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pip install power-grid-model-ds
3131
:maxdepth: 2
3232
3333
quick_start
34+
demos/index
3435
model_structure
3536
model_interface
3637
examples/index

docs/make.bat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ REM Command file for Sphinx documentation
1111
if "%SPHINXBUILD%" == "" (
1212
set SPHINXBUILD=sphinx-build
1313
)
14-
set SOURCEDIR=source
14+
set SOURCEDIR=.
1515
set BUILDDIR=_build
1616

1717
%SPHINXBUILD% >NUL 2>NUL

0 commit comments

Comments
 (0)