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.
Files changed (64) hide show
  1. power_grid_model_ds/__init__.py +9 -0
  2. power_grid_model_ds/_core/__init__.py +0 -0
  3. power_grid_model_ds/_core/data_source/__init__.py +0 -0
  4. power_grid_model_ds/_core/data_source/generator/__init__.py +0 -0
  5. power_grid_model_ds/_core/data_source/generator/arrays/__init__.py +0 -0
  6. power_grid_model_ds/_core/data_source/generator/arrays/base.py +25 -0
  7. power_grid_model_ds/_core/data_source/generator/arrays/line.py +133 -0
  8. power_grid_model_ds/_core/data_source/generator/arrays/node.py +37 -0
  9. power_grid_model_ds/_core/data_source/generator/arrays/source.py +30 -0
  10. power_grid_model_ds/_core/data_source/generator/arrays/transformer.py +37 -0
  11. power_grid_model_ds/_core/data_source/generator/grid_generators.py +78 -0
  12. power_grid_model_ds/_core/fancypy.py +66 -0
  13. power_grid_model_ds/_core/load_flow.py +140 -0
  14. power_grid_model_ds/_core/model/__init__.py +0 -0
  15. power_grid_model_ds/_core/model/arrays/__init__.py +43 -0
  16. power_grid_model_ds/_core/model/arrays/base/__init__.py +0 -0
  17. power_grid_model_ds/_core/model/arrays/base/_build.py +166 -0
  18. power_grid_model_ds/_core/model/arrays/base/_filters.py +115 -0
  19. power_grid_model_ds/_core/model/arrays/base/_modify.py +64 -0
  20. power_grid_model_ds/_core/model/arrays/base/_optional.py +11 -0
  21. power_grid_model_ds/_core/model/arrays/base/_string.py +94 -0
  22. power_grid_model_ds/_core/model/arrays/base/array.py +325 -0
  23. power_grid_model_ds/_core/model/arrays/base/errors.py +17 -0
  24. power_grid_model_ds/_core/model/arrays/pgm_arrays.py +122 -0
  25. power_grid_model_ds/_core/model/constants.py +27 -0
  26. power_grid_model_ds/_core/model/containers/__init__.py +0 -0
  27. power_grid_model_ds/_core/model/containers/base.py +244 -0
  28. power_grid_model_ds/_core/model/containers/grid_protocol.py +22 -0
  29. power_grid_model_ds/_core/model/dtypes/__init__.py +0 -0
  30. power_grid_model_ds/_core/model/dtypes/appliances.py +39 -0
  31. power_grid_model_ds/_core/model/dtypes/branches.py +117 -0
  32. power_grid_model_ds/_core/model/dtypes/id.py +19 -0
  33. power_grid_model_ds/_core/model/dtypes/nodes.py +27 -0
  34. power_grid_model_ds/_core/model/dtypes/regulators.py +30 -0
  35. power_grid_model_ds/_core/model/dtypes/sensors.py +63 -0
  36. power_grid_model_ds/_core/model/enums/__init__.py +0 -0
  37. power_grid_model_ds/_core/model/enums/nodes.py +16 -0
  38. power_grid_model_ds/_core/model/graphs/__init__.py +0 -0
  39. power_grid_model_ds/_core/model/graphs/container.py +158 -0
  40. power_grid_model_ds/_core/model/graphs/errors.py +19 -0
  41. power_grid_model_ds/_core/model/graphs/models/__init__.py +7 -0
  42. power_grid_model_ds/_core/model/graphs/models/_rustworkx_search.py +63 -0
  43. power_grid_model_ds/_core/model/graphs/models/base.py +326 -0
  44. power_grid_model_ds/_core/model/graphs/models/rustworkx.py +119 -0
  45. power_grid_model_ds/_core/model/grids/__init__.py +0 -0
  46. power_grid_model_ds/_core/model/grids/_text_sources.py +119 -0
  47. power_grid_model_ds/_core/model/grids/base.py +434 -0
  48. power_grid_model_ds/_core/model/grids/helpers.py +122 -0
  49. power_grid_model_ds/_core/utils/__init__.py +0 -0
  50. power_grid_model_ds/_core/utils/misc.py +41 -0
  51. power_grid_model_ds/_core/utils/pickle.py +47 -0
  52. power_grid_model_ds/_core/utils/zip.py +72 -0
  53. power_grid_model_ds/arrays.py +39 -0
  54. power_grid_model_ds/constants.py +7 -0
  55. power_grid_model_ds/enums.py +7 -0
  56. power_grid_model_ds/errors.py +27 -0
  57. power_grid_model_ds/fancypy.py +9 -0
  58. power_grid_model_ds/generators.py +11 -0
  59. power_grid_model_ds/graph_models.py +8 -0
  60. power_grid_model_ds-0.0.1a11709467271.dist-info/LICENSE +292 -0
  61. power_grid_model_ds-0.0.1a11709467271.dist-info/METADATA +80 -0
  62. power_grid_model_ds-0.0.1a11709467271.dist-info/RECORD +64 -0
  63. power_grid_model_ds-0.0.1a11709467271.dist-info/WHEEL +5 -0
  64. 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,7 @@
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.constants import EMPTY_ID, empty
6
+
7
+ __all__ = ["EMPTY_ID", "empty"]
@@ -0,0 +1,7 @@
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.enums.nodes import NodeType
6
+
7
+ __all__ = ["NodeType"]
@@ -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"]