power-grid-model-ds 0.0.1a11709467271__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- power_grid_model_ds/__init__.py +9 -0
- power_grid_model_ds/_core/__init__.py +0 -0
- power_grid_model_ds/_core/data_source/__init__.py +0 -0
- power_grid_model_ds/_core/data_source/generator/__init__.py +0 -0
- power_grid_model_ds/_core/data_source/generator/arrays/__init__.py +0 -0
- power_grid_model_ds/_core/data_source/generator/arrays/base.py +25 -0
- power_grid_model_ds/_core/data_source/generator/arrays/line.py +133 -0
- power_grid_model_ds/_core/data_source/generator/arrays/node.py +37 -0
- power_grid_model_ds/_core/data_source/generator/arrays/source.py +30 -0
- power_grid_model_ds/_core/data_source/generator/arrays/transformer.py +37 -0
- power_grid_model_ds/_core/data_source/generator/grid_generators.py +78 -0
- power_grid_model_ds/_core/fancypy.py +66 -0
- power_grid_model_ds/_core/load_flow.py +140 -0
- power_grid_model_ds/_core/model/__init__.py +0 -0
- power_grid_model_ds/_core/model/arrays/__init__.py +43 -0
- power_grid_model_ds/_core/model/arrays/base/__init__.py +0 -0
- power_grid_model_ds/_core/model/arrays/base/_build.py +166 -0
- power_grid_model_ds/_core/model/arrays/base/_filters.py +115 -0
- power_grid_model_ds/_core/model/arrays/base/_modify.py +64 -0
- power_grid_model_ds/_core/model/arrays/base/_optional.py +11 -0
- power_grid_model_ds/_core/model/arrays/base/_string.py +94 -0
- power_grid_model_ds/_core/model/arrays/base/array.py +325 -0
- power_grid_model_ds/_core/model/arrays/base/errors.py +17 -0
- power_grid_model_ds/_core/model/arrays/pgm_arrays.py +122 -0
- power_grid_model_ds/_core/model/constants.py +27 -0
- power_grid_model_ds/_core/model/containers/__init__.py +0 -0
- power_grid_model_ds/_core/model/containers/base.py +244 -0
- power_grid_model_ds/_core/model/containers/grid_protocol.py +22 -0
- power_grid_model_ds/_core/model/dtypes/__init__.py +0 -0
- power_grid_model_ds/_core/model/dtypes/appliances.py +39 -0
- power_grid_model_ds/_core/model/dtypes/branches.py +117 -0
- power_grid_model_ds/_core/model/dtypes/id.py +19 -0
- power_grid_model_ds/_core/model/dtypes/nodes.py +27 -0
- power_grid_model_ds/_core/model/dtypes/regulators.py +30 -0
- power_grid_model_ds/_core/model/dtypes/sensors.py +63 -0
- power_grid_model_ds/_core/model/enums/__init__.py +0 -0
- power_grid_model_ds/_core/model/enums/nodes.py +16 -0
- power_grid_model_ds/_core/model/graphs/__init__.py +0 -0
- power_grid_model_ds/_core/model/graphs/container.py +158 -0
- power_grid_model_ds/_core/model/graphs/errors.py +19 -0
- power_grid_model_ds/_core/model/graphs/models/__init__.py +7 -0
- power_grid_model_ds/_core/model/graphs/models/_rustworkx_search.py +63 -0
- power_grid_model_ds/_core/model/graphs/models/base.py +326 -0
- power_grid_model_ds/_core/model/graphs/models/rustworkx.py +119 -0
- power_grid_model_ds/_core/model/grids/__init__.py +0 -0
- power_grid_model_ds/_core/model/grids/_text_sources.py +119 -0
- power_grid_model_ds/_core/model/grids/base.py +434 -0
- power_grid_model_ds/_core/model/grids/helpers.py +122 -0
- power_grid_model_ds/_core/utils/__init__.py +0 -0
- power_grid_model_ds/_core/utils/misc.py +41 -0
- power_grid_model_ds/_core/utils/pickle.py +47 -0
- power_grid_model_ds/_core/utils/zip.py +72 -0
- power_grid_model_ds/arrays.py +39 -0
- power_grid_model_ds/constants.py +7 -0
- power_grid_model_ds/enums.py +7 -0
- power_grid_model_ds/errors.py +27 -0
- power_grid_model_ds/fancypy.py +9 -0
- power_grid_model_ds/generators.py +11 -0
- power_grid_model_ds/graph_models.py +8 -0
- power_grid_model_ds-0.0.1a11709467271.dist-info/LICENSE +292 -0
- power_grid_model_ds-0.0.1a11709467271.dist-info/METADATA +80 -0
- power_grid_model_ds-0.0.1a11709467271.dist-info/RECORD +64 -0
- power_grid_model_ds-0.0.1a11709467271.dist-info/WHEEL +5 -0
- power_grid_model_ds-0.0.1a11709467271.dist-info/top_level.txt +1 -0
@@ -0,0 +1,122 @@
|
|
1
|
+
# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MPL-2.0
|
4
|
+
|
5
|
+
from typing import TYPE_CHECKING
|
6
|
+
|
7
|
+
import numpy as np
|
8
|
+
|
9
|
+
from power_grid_model_ds._core.model.arrays.pgm_arrays import BranchArray
|
10
|
+
from power_grid_model_ds._core.model.enums.nodes import NodeType
|
11
|
+
|
12
|
+
if TYPE_CHECKING:
|
13
|
+
from .base import Grid
|
14
|
+
|
15
|
+
|
16
|
+
def set_feeder_ids(grid: "Grid"):
|
17
|
+
"""Determines all feeder groups in the network and gives them a feeder identifier
|
18
|
+
|
19
|
+
feeder_branch_id := All assets being connected through the same feeding branch(es) on the substation
|
20
|
+
feeder_node_id := All assets connected to the same feeder node (substation)
|
21
|
+
|
22
|
+
Example:
|
23
|
+
Nodes Topology
|
24
|
+
(SUBSTATION) 101 --- 102 --- 103 -|- 104 --- 105 --- 101 (SUBSTATION)
|
25
|
+
{-}
|
26
|
+
106
|
27
|
+
|
28
|
+
Branches Topology:
|
29
|
+
(SUBSTATION) *** 201 *** 202 *** 203 *** 601 *** 204 *** (SUBSTATION)
|
30
|
+
301
|
31
|
+
***
|
32
|
+
|
33
|
+
Substation ID | Feeder ID
|
34
|
+
101 | -1 | -1
|
35
|
+
102 | 101 | 201
|
36
|
+
103 | 101 | 201
|
37
|
+
104 | 101 | 204
|
38
|
+
105 | 101 | 204
|
39
|
+
106 | 101 | 201
|
40
|
+
201 | 101 | 201
|
41
|
+
202 | 101 | 201
|
42
|
+
203 | 101 | -1
|
43
|
+
204 | 101 | 204
|
44
|
+
301 | 101 | 201
|
45
|
+
601 | 101 | 204
|
46
|
+
"""
|
47
|
+
_reset_feeder_ids(grid)
|
48
|
+
feeder_node_ids = grid.node.filter(node_type=NodeType.SUBSTATION_NODE).id
|
49
|
+
components = grid.graphs.active_graph.get_components(feeder_node_ids)
|
50
|
+
for component_node_ids in components:
|
51
|
+
component_branches = _get_active_component_branches(grid, component_node_ids)
|
52
|
+
|
53
|
+
feeder_branch = _get_feeder_branch(component_branches)
|
54
|
+
|
55
|
+
if feeder_branch.size == 0:
|
56
|
+
continue # early exit
|
57
|
+
|
58
|
+
feeder_node_id = _get_feeder_node_id(feeder_branch, feeder_node_ids)
|
59
|
+
|
60
|
+
for array in grid.branch_arrays:
|
61
|
+
array.update_by_id(
|
62
|
+
component_branches.id,
|
63
|
+
feeder_branch_id=feeder_branch.id.item(),
|
64
|
+
feeder_node_id=feeder_node_id,
|
65
|
+
allow_missing=True,
|
66
|
+
)
|
67
|
+
|
68
|
+
grid.node.update_by_id(
|
69
|
+
component_node_ids,
|
70
|
+
feeder_branch_id=feeder_branch.id.item(),
|
71
|
+
feeder_node_id=feeder_node_id,
|
72
|
+
allow_missing=True,
|
73
|
+
)
|
74
|
+
|
75
|
+
|
76
|
+
def set_is_feeder(grid: "Grid") -> None:
|
77
|
+
"Set the is_feeder property for all branches in the network."
|
78
|
+
feeder_node_ids = grid.node.filter(node_type=NodeType.SUBSTATION_NODE).id
|
79
|
+
array: BranchArray
|
80
|
+
for array in [grid.link, grid.line, grid.transformer]:
|
81
|
+
array.is_feeder = np.logical_xor(
|
82
|
+
np.isin(array.from_node, feeder_node_ids), np.isin(array.to_node, feeder_node_ids)
|
83
|
+
)
|
84
|
+
|
85
|
+
|
86
|
+
def _reset_feeder_ids(grid: "Grid"):
|
87
|
+
# Resets all feeder ids to EMPTY_ID
|
88
|
+
for array in grid.branch_arrays:
|
89
|
+
array.set_empty("feeder_branch_id")
|
90
|
+
array.set_empty("feeder_node_id")
|
91
|
+
|
92
|
+
grid.node.set_empty("feeder_branch_id")
|
93
|
+
grid.node.set_empty("feeder_node_id")
|
94
|
+
|
95
|
+
|
96
|
+
def _get_active_component_branches(grid: "Grid", component_node_ids: list[int]) -> BranchArray:
|
97
|
+
# a component is a set of actively connected nodes (ids)
|
98
|
+
# returns all active branches in the component
|
99
|
+
|
100
|
+
branches = grid.branches
|
101
|
+
branches_in_component = branches.filter(from_node=component_node_ids, to_node=component_node_ids, mode_="OR")
|
102
|
+
active_branches = branches_in_component.filter(from_status=1, to_status=1)
|
103
|
+
return active_branches
|
104
|
+
|
105
|
+
|
106
|
+
def _get_feeder_branch(component_branches: BranchArray) -> BranchArray:
|
107
|
+
feeder_branches = component_branches.filter(is_feeder=True)
|
108
|
+
|
109
|
+
if feeder_branches.size == 1:
|
110
|
+
return feeder_branches
|
111
|
+
|
112
|
+
if feeder_branches.size > 1:
|
113
|
+
# Cannot point to multiple branches, so just pick the first one
|
114
|
+
return feeder_branches[0]
|
115
|
+
|
116
|
+
return BranchArray()
|
117
|
+
|
118
|
+
|
119
|
+
def _get_feeder_node_id(feeder_branch: BranchArray, feeder_node_ids: np.ndarray) -> int:
|
120
|
+
# intersect to retrieve the feeder node id
|
121
|
+
feeder_node_id = np.intersect1d(feeder_branch.node_ids, feeder_node_ids)
|
122
|
+
return feeder_node_id.item()
|
File without changes
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MPL-2.0
|
4
|
+
|
5
|
+
"""Misc utils"""
|
6
|
+
|
7
|
+
from collections.abc import Sequence
|
8
|
+
from typing import Type, get_type_hints
|
9
|
+
|
10
|
+
import numpy as np
|
11
|
+
|
12
|
+
|
13
|
+
def is_sequence(seq):
|
14
|
+
"""
|
15
|
+
Returns True for lists, tuples, sets, arrays
|
16
|
+
Return False for strings, dicts
|
17
|
+
"""
|
18
|
+
if isinstance(seq, str):
|
19
|
+
return False
|
20
|
+
|
21
|
+
if isinstance(seq, (np.ndarray, set)):
|
22
|
+
return True
|
23
|
+
return isinstance(seq, Sequence)
|
24
|
+
|
25
|
+
|
26
|
+
def get_inherited_attrs(cls: Type, *private_attributes):
|
27
|
+
"""
|
28
|
+
Get the attribute from the object and all its parents
|
29
|
+
"""
|
30
|
+
|
31
|
+
# The extras are needed for annotated types like NDArray3
|
32
|
+
retrieved_attributes = get_type_hints(cls, include_extras=True)
|
33
|
+
retrieved_attributes = {attr: type for attr, type in retrieved_attributes.items() if not attr.startswith("_")}
|
34
|
+
|
35
|
+
for private_attr in private_attributes:
|
36
|
+
for parent in reversed(list(cls.__mro__)):
|
37
|
+
attr_dict = retrieved_attributes.get(private_attr, {})
|
38
|
+
attr_dict.update(getattr(parent, private_attr, {}))
|
39
|
+
retrieved_attributes[private_attr] = attr_dict
|
40
|
+
|
41
|
+
return retrieved_attributes
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MPL-2.0
|
4
|
+
|
5
|
+
"""helper functions for pickling python objects and loading pickle objects"""
|
6
|
+
|
7
|
+
import pickle
|
8
|
+
from pathlib import Path
|
9
|
+
|
10
|
+
from power_grid_model_ds._core.utils.zip import gzip2file
|
11
|
+
|
12
|
+
|
13
|
+
def save_to_pickle(path: Path, python_object: object):
|
14
|
+
"""Save a python object to pickle"""
|
15
|
+
path.parent.mkdir(exist_ok=True, parents=True)
|
16
|
+
with open(str(path), "wb") as file:
|
17
|
+
pickle.dump(python_object, file)
|
18
|
+
|
19
|
+
|
20
|
+
def load_from_pickle(path: Path) -> object:
|
21
|
+
"""Load a python object from a pickle file"""
|
22
|
+
with open(str(path), "rb") as file:
|
23
|
+
return pickle.load(file)
|
24
|
+
|
25
|
+
|
26
|
+
def get_pickle_path(path: Path) -> Path:
|
27
|
+
"""
|
28
|
+
Returns the path to the pickle file.
|
29
|
+
If ony a .gz-file is available, the .gz-file is unpacked.
|
30
|
+
"""
|
31
|
+
pickle_suffix = ".pickle"
|
32
|
+
gz_suffix = ".gz"
|
33
|
+
|
34
|
+
if path.suffix == pickle_suffix and path.is_file():
|
35
|
+
return path
|
36
|
+
|
37
|
+
if path.with_suffix(pickle_suffix).is_file():
|
38
|
+
return path.with_suffix(pickle_suffix)
|
39
|
+
|
40
|
+
if path.suffix == gz_suffix and path.is_file():
|
41
|
+
return gzip2file(path)
|
42
|
+
|
43
|
+
pickle_gz_suffix = pickle_suffix + gz_suffix
|
44
|
+
if path.with_suffix(pickle_gz_suffix).is_file():
|
45
|
+
return gzip2file(path.with_suffix(pickle_gz_suffix))
|
46
|
+
|
47
|
+
raise FileNotFoundError(f"Expected either {path.name}.pickle or {path.name}.pickle.gz")
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MPL-2.0
|
4
|
+
|
5
|
+
"""Helper functions for (un)zipping files"""
|
6
|
+
|
7
|
+
import gzip
|
8
|
+
import logging
|
9
|
+
import os
|
10
|
+
import shutil
|
11
|
+
from pathlib import Path
|
12
|
+
from typing import List
|
13
|
+
from zipfile import ZipFile
|
14
|
+
|
15
|
+
_logger = logging.getLogger(__name__)
|
16
|
+
|
17
|
+
|
18
|
+
def zip_folder(folder_to_zip: Path) -> Path:
|
19
|
+
"""Zip folder contents"""
|
20
|
+
zip_file_path = folder_to_zip.with_suffix(".zip").resolve()
|
21
|
+
folder_to_zip = folder_to_zip.resolve()
|
22
|
+
|
23
|
+
# move into folder to zip to avoid nested folders in .zip file
|
24
|
+
current_working_directory = os.getcwd()
|
25
|
+
os.chdir(folder_to_zip)
|
26
|
+
files_to_zip = [path.relative_to(folder_to_zip) for path in folder_to_zip.rglob("*")]
|
27
|
+
zip_files(zip_file_path, files_to_zip)
|
28
|
+
|
29
|
+
# move out of folder again
|
30
|
+
os.chdir(current_working_directory)
|
31
|
+
|
32
|
+
return zip_file_path
|
33
|
+
|
34
|
+
|
35
|
+
def zip_files(zip_file_path: Path, files_to_zip: List[Path]) -> Path:
|
36
|
+
"""Zip files"""
|
37
|
+
with ZipFile(str(zip_file_path.with_suffix(".zip")), "w") as zip_object:
|
38
|
+
for file in files_to_zip:
|
39
|
+
zip_object.write(str(file))
|
40
|
+
zip_object.close()
|
41
|
+
return zip_file_path.resolve()
|
42
|
+
|
43
|
+
|
44
|
+
def unzip_files(zip_file_path: Path) -> Path:
|
45
|
+
"""Unzip .zip file to folder"""
|
46
|
+
extraction_dir = zip_file_path.with_suffix("")
|
47
|
+
extraction_dir.mkdir(parents=True, exist_ok=True)
|
48
|
+
with ZipFile(str(zip_file_path.resolve()), "r") as zip_ref:
|
49
|
+
zip_ref.extractall(extraction_dir)
|
50
|
+
return extraction_dir
|
51
|
+
|
52
|
+
|
53
|
+
def gzip2file(gzip_path: Path) -> Path:
|
54
|
+
"""unzip a gzip (.gz) file"""
|
55
|
+
_logger.info(f"Unzipping {gzip_path.name}")
|
56
|
+
|
57
|
+
file_path = gzip_path.with_suffix("")
|
58
|
+
with gzip.open(gzip_path, "rb") as f_in:
|
59
|
+
with open(file_path, "wb") as f_out:
|
60
|
+
shutil.copyfileobj(f_in, f_out)
|
61
|
+
return file_path
|
62
|
+
|
63
|
+
|
64
|
+
def file2gzip(file_path: Path) -> Path:
|
65
|
+
"""zip a gzip (.gz) file"""
|
66
|
+
_logger.info(f"Zipping {file_path.name}")
|
67
|
+
|
68
|
+
gzip_path = file_path.with_suffix(f"{file_path.suffix}.gz")
|
69
|
+
with open(file_path, "rb") as f_in:
|
70
|
+
with gzip.open(gzip_path, "wb") as f_out:
|
71
|
+
shutil.copyfileobj(f_in, f_out)
|
72
|
+
return gzip_path
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MPL-2.0
|
4
|
+
|
5
|
+
from power_grid_model_ds._core.model.arrays import (
|
6
|
+
AsymVoltageSensorArray,
|
7
|
+
Branch3Array,
|
8
|
+
BranchArray,
|
9
|
+
IdArray,
|
10
|
+
LineArray,
|
11
|
+
LinkArray,
|
12
|
+
NodeArray,
|
13
|
+
SourceArray,
|
14
|
+
SymGenArray,
|
15
|
+
SymLoadArray,
|
16
|
+
SymPowerSensorArray,
|
17
|
+
SymVoltageSensorArray,
|
18
|
+
ThreeWindingTransformerArray,
|
19
|
+
TransformerArray,
|
20
|
+
TransformerTapRegulatorArray,
|
21
|
+
)
|
22
|
+
|
23
|
+
__all__ = [
|
24
|
+
"IdArray",
|
25
|
+
"NodeArray",
|
26
|
+
"BranchArray",
|
27
|
+
"LinkArray",
|
28
|
+
"LineArray",
|
29
|
+
"TransformerArray",
|
30
|
+
"Branch3Array",
|
31
|
+
"ThreeWindingTransformerArray",
|
32
|
+
"SourceArray",
|
33
|
+
"SymGenArray",
|
34
|
+
"SymLoadArray",
|
35
|
+
"TransformerTapRegulatorArray",
|
36
|
+
"AsymVoltageSensorArray",
|
37
|
+
"SymPowerSensorArray",
|
38
|
+
"SymVoltageSensorArray",
|
39
|
+
]
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MPL-2.0
|
4
|
+
|
5
|
+
from power_grid_model_ds._core.load_flow import PGMCoreException
|
6
|
+
from power_grid_model_ds._core.model.arrays.base.errors import (
|
7
|
+
ArrayDefinitionError,
|
8
|
+
MultipleRecordsReturned,
|
9
|
+
RecordDoesNotExist,
|
10
|
+
)
|
11
|
+
from power_grid_model_ds._core.model.graphs.errors import (
|
12
|
+
GraphError,
|
13
|
+
MissingBranchError,
|
14
|
+
MissingNodeError,
|
15
|
+
NoPathBetweenNodes,
|
16
|
+
)
|
17
|
+
|
18
|
+
__all__ = [
|
19
|
+
"PGMCoreException",
|
20
|
+
"GraphError",
|
21
|
+
"ArrayDefinitionError",
|
22
|
+
"RecordDoesNotExist",
|
23
|
+
"MultipleRecordsReturned",
|
24
|
+
"MissingNodeError",
|
25
|
+
"MissingBranchError",
|
26
|
+
"NoPathBetweenNodes",
|
27
|
+
]
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MPL-2.0
|
4
|
+
|
5
|
+
from power_grid_model_ds._core.fancypy import array_equal, concatenate, sort, unique
|
6
|
+
from power_grid_model_ds._core.model.arrays.base.array import FancyArray
|
7
|
+
from power_grid_model_ds._core.model.containers.base import FancyArrayContainer
|
8
|
+
|
9
|
+
__all__ = ["FancyArray", "FancyArrayContainer", "concatenate", "unique", "sort", "array_equal"]
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MPL-2.0
|
4
|
+
|
5
|
+
from power_grid_model_ds._core.data_source.generator.arrays.line import LineGenerator
|
6
|
+
from power_grid_model_ds._core.data_source.generator.arrays.node import NodeGenerator
|
7
|
+
from power_grid_model_ds._core.data_source.generator.arrays.source import SourceGenerator
|
8
|
+
from power_grid_model_ds._core.data_source.generator.arrays.transformer import TransformerGenerator
|
9
|
+
from power_grid_model_ds._core.data_source.generator.grid_generators import RadialGridGenerator
|
10
|
+
|
11
|
+
__all__ = ["RadialGridGenerator", "NodeGenerator", "LineGenerator", "TransformerGenerator", "SourceGenerator"]
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MPL-2.0
|
4
|
+
|
5
|
+
from power_grid_model_ds._core.model.graphs.models import RustworkxGraphModel
|
6
|
+
from power_grid_model_ds._core.model.graphs.models.base import BaseGraphModel
|
7
|
+
|
8
|
+
__all__ = ["BaseGraphModel", "RustworkxGraphModel"]
|