pandahub 0.3.17__zip → 0.4.1__zip
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.
- {pandahub-0.3.17 → pandahub-0.4.1}/CHANGELOG.md +3 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/PKG-INFO +1 -1
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/PandaHub.py +184 -206
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/datatypes.py +2 -10
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/mongo_client.py +17 -4
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub.egg-info/PKG-INFO +1 -1
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub.egg-info/requires.txt +1 -1
- {pandahub-0.3.17 → pandahub-0.4.1}/pyproject.toml +1 -1
- {pandahub-0.3.17 → pandahub-0.4.1}/requirements.txt +1 -1
- {pandahub-0.3.17 → pandahub-0.4.1}/test/performance_test.py +1 -1
- {pandahub-0.3.17 → pandahub-0.4.1}/test/test_networks.py +3 -3
- {pandahub-0.3.17 → pandahub-0.4.1}/CONTRIBUTING.rst +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/LICENSE +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/MANIFEST.in +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/README.md +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/__init__.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/__init__.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/dependencies.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/internal/__init__.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/internal/db.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/internal/schemas.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/internal/settings.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/internal/toolbox.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/internal/users.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/main.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/routers/__init__.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/routers/auth.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/routers/net.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/routers/projects.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/routers/timeseries.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/routers/users.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/routers/variants.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/__init__.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/database_toolbox.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/mongodb_indexes.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/timeseries/__init__.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/timeseries/data_sources/__init__.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/timeseries/data_sources/mongo_data.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/timeseries/output_writer_mongodb.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub.egg-info/SOURCES.txt +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub.egg-info/dependency_links.txt +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/pandahub.egg-info/top_level.txt +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/setup.cfg +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/setup.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/test/__init__.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/test/conftest.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/test/test_client.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/test/test_projects.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/test/test_timeseries.py +0 -0
- {pandahub-0.3.17 → pandahub-0.4.1}/tutorials/config.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pandahub
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: Data hub for pandapower and pandapipes networks based on MongoDB
|
|
5
5
|
Author-email: Jan Ulffers <jan.ulffers@iee.fraunhofer.de>, Leon Thurner <leon.thurner@retoflow.de>, Jannis Kupka <jannis.kupka@retoflow.de>, Mike Vogt <mike.vogt@iee.fraunhofer.de>, Joschka Thurner <joschka.thurner@retoflow.de>, Alexander Scheidler <alexander.scheidler@iee.fraunhofer.de>
|
|
6
6
|
License: Copyright (c) 2022 by University of Kassel, Fraunhofer Institute for Energy Economics
|
|
@@ -4,28 +4,29 @@ import json
|
|
|
4
4
|
import logging
|
|
5
5
|
import time
|
|
6
6
|
import warnings
|
|
7
|
-
from inspect import signature, _empty
|
|
8
7
|
from collections.abc import Callable
|
|
8
|
+
from functools import reduce
|
|
9
|
+
from inspect import signature, _empty
|
|
10
|
+
from itertools import chain
|
|
11
|
+
from operator import getitem
|
|
9
12
|
from types import NoneType
|
|
10
13
|
from typing import Optional, Union, TypeVar
|
|
14
|
+
from uuid import UUID
|
|
11
15
|
|
|
12
16
|
import numpy as np
|
|
17
|
+
import pandapipes as pps
|
|
18
|
+
import pandapower as pp
|
|
19
|
+
import pandapower.io_utils as io_pp
|
|
13
20
|
import pandas as pd
|
|
14
21
|
from bson.errors import InvalidId
|
|
15
22
|
from bson.objectid import ObjectId
|
|
16
|
-
from
|
|
17
|
-
from
|
|
18
|
-
from uuid import UUID
|
|
23
|
+
from pandapipes import from_json_string as from_json_pps, FromSerializableRegistryPpipe, BranchComponent
|
|
24
|
+
from pandapipes.component_models import NodeElementComponent
|
|
19
25
|
from pymongo import MongoClient, ReplaceOne
|
|
20
|
-
from pymongo.database import Database
|
|
21
26
|
from pymongo.collection import Collection
|
|
27
|
+
from pymongo.database import Database
|
|
22
28
|
from pymongo.errors import ServerSelectionTimeoutError, DuplicateKeyError
|
|
23
29
|
|
|
24
|
-
import pandapipes as pps
|
|
25
|
-
from pandapipes import from_json_string as from_json_pps, FromSerializableRegistryPpipe
|
|
26
|
-
import pandapower as pp
|
|
27
|
-
import pandapower.io_utils as io_pp
|
|
28
|
-
|
|
29
30
|
from pandahub.api.internal.settings import MONGODB_URL, MONGODB_USER, MONGODB_PASSWORD, MONGODB_GLOBAL_DATABASE_URL, \
|
|
30
31
|
MONGODB_GLOBAL_DATABASE_USER, MONGODB_GLOBAL_DATABASE_PASSWORD, CREATE_INDEXES_WITH_PROJECT, PANDAHUB_GLOBAL_DB_CLIENT
|
|
31
32
|
from pandahub.lib.database_toolbox import (
|
|
@@ -77,6 +78,20 @@ def validate_variant_type(variant: int | None):
|
|
|
77
78
|
msg = f"variant must be int or None, but got {variant} of type {type(variant)}"
|
|
78
79
|
raise ValueError(msg)
|
|
79
80
|
|
|
81
|
+
|
|
82
|
+
def re_arg(kwarg_map: dict[str, str]) -> Callable:
|
|
83
|
+
def decorator(func: Callable) -> Callable:
|
|
84
|
+
def wrapped(*args, **kwargs):
|
|
85
|
+
new_kwargs = {}
|
|
86
|
+
for k, v in kwargs.items():
|
|
87
|
+
if k in kwarg_map:
|
|
88
|
+
print(f"DEPRECATION WARNING: keyword argument '{k}' is no longer valid. Use '{kwarg_map[k]}' instead.")
|
|
89
|
+
new_kwargs[kwarg_map.get(k, k)] = v
|
|
90
|
+
return func(*args, **new_kwargs)
|
|
91
|
+
return wrapped
|
|
92
|
+
return decorator
|
|
93
|
+
|
|
94
|
+
|
|
80
95
|
class PandaHub:
|
|
81
96
|
permissions = {
|
|
82
97
|
"read": ["owner", "developer", "guest"],
|
|
@@ -856,15 +871,15 @@ class PandaHub:
|
|
|
856
871
|
def get_subnet_by_name(
|
|
857
872
|
self,
|
|
858
873
|
name,
|
|
859
|
-
|
|
874
|
+
node_filter=None,
|
|
860
875
|
include_results=True,
|
|
861
876
|
add_edge_branches=True,
|
|
862
877
|
geo_mode="string",
|
|
863
878
|
variant=None,
|
|
864
879
|
additional_filters: dict[
|
|
865
|
-
str, Callable[[pp.auxiliary.pandapowerNet], dict]
|
|
880
|
+
str, Callable[[pp.auxiliary.pandapowerNet | pps.pandapipesNet], dict]
|
|
866
881
|
] = {},
|
|
867
|
-
):
|
|
882
|
+
) -> pp.auxiliary.pandapowerNet | pps.pandapipesNet:
|
|
868
883
|
self.check_permission("read")
|
|
869
884
|
db = self._get_project_database()
|
|
870
885
|
net_id = self._get_net_id_from_name(name, db)
|
|
@@ -872,7 +887,7 @@ class PandaHub:
|
|
|
872
887
|
return None
|
|
873
888
|
return self.get_subnet(
|
|
874
889
|
net_id,
|
|
875
|
-
|
|
890
|
+
node_filter=node_filter,
|
|
876
891
|
include_results=include_results,
|
|
877
892
|
add_edge_branches=add_edge_branches,
|
|
878
893
|
geo_mode=geo_mode,
|
|
@@ -880,221 +895,192 @@ class PandaHub:
|
|
|
880
895
|
additional_filters=additional_filters,
|
|
881
896
|
)
|
|
882
897
|
|
|
898
|
+
@re_arg({"bus_filter": "node_filter"})
|
|
883
899
|
def get_subnet(
|
|
884
900
|
self,
|
|
885
901
|
net_id,
|
|
886
|
-
|
|
902
|
+
node_filter=None,
|
|
887
903
|
include_results=True,
|
|
888
904
|
add_edge_branches=True,
|
|
889
905
|
geo_mode="string",
|
|
890
906
|
variant=None,
|
|
891
|
-
ignore_elements=[],
|
|
907
|
+
ignore_elements=tuple([]),
|
|
892
908
|
additional_filters: dict[
|
|
893
|
-
str, Callable[[pp.auxiliary.pandapowerNet], dict]
|
|
894
|
-
] =
|
|
895
|
-
|
|
909
|
+
str, Callable[[pp.auxiliary.pandapowerNet | pps.pandapipesNet], dict]
|
|
910
|
+
] | None = None,
|
|
911
|
+
additional_branch_node_cols: dict[str, list[str]] | None = None,
|
|
912
|
+
*,
|
|
913
|
+
return_edge_branch_nodes: bool = False
|
|
914
|
+
) -> (pp.pandapowerNet | pps.pandapipesNet) | (tuple[pp.pandapowerNet | pps.pandapipesNet, list]):
|
|
896
915
|
db = self._get_project_database()
|
|
897
916
|
meta = self._get_network_metadata(db, net_id)
|
|
898
|
-
dtypes =
|
|
917
|
+
dtypes = meta["dtypes"]
|
|
918
|
+
sector = meta["sector"]
|
|
919
|
+
is_power = sector == "power"
|
|
899
920
|
|
|
900
|
-
|
|
921
|
+
if additional_filters is None:
|
|
922
|
+
additional_filters = {}
|
|
923
|
+
if additional_branch_node_cols is None:
|
|
924
|
+
additional_branch_node_cols = {}
|
|
901
925
|
|
|
902
|
-
|
|
926
|
+
def switch_filter(bus_filter):
|
|
927
|
+
return {
|
|
928
|
+
"$and": [
|
|
929
|
+
{"et": "b"},
|
|
930
|
+
bus_filter,
|
|
931
|
+
]
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
def get_nodes_from_element(ntw, element, nd_cols):
|
|
935
|
+
return [ntw[element][ndc].to_numpy() for ndc in nd_cols]
|
|
936
|
+
|
|
937
|
+
def get_nodes_from_switch(ntw, _, _nd_cols):
|
|
938
|
+
return [ntw.switch.bus.to_numpy(), ntw.switch.loc[ntw.switch.et == "b", "element"].to_numpy()]
|
|
939
|
+
|
|
940
|
+
if is_power:
|
|
941
|
+
net = pp.create_empty_network()
|
|
942
|
+
node_name = "bus"
|
|
943
|
+
default_branches = ["line", "trafo", "trafo3w", "switch"]
|
|
944
|
+
default_node_cols = [
|
|
945
|
+
("from_bus", "to_bus"),
|
|
946
|
+
("hv_bus", "lv_bus"),
|
|
947
|
+
("hv_bus", "lv_bus", "mv_bus"),
|
|
948
|
+
("bus", "element")
|
|
949
|
+
]
|
|
950
|
+
special_filters = {"switch": switch_filter}
|
|
951
|
+
get_nodes_func = {br: get_nodes_from_element for br in default_branches}
|
|
952
|
+
get_nodes_func["switch"] = get_nodes_from_switch
|
|
953
|
+
# add node elements
|
|
954
|
+
node_elements = [
|
|
955
|
+
"load",
|
|
956
|
+
"asymmetric_load",
|
|
957
|
+
"sgen",
|
|
958
|
+
"asymmetric_sgen",
|
|
959
|
+
"gen",
|
|
960
|
+
"ext_grid",
|
|
961
|
+
"shunt",
|
|
962
|
+
"xward",
|
|
963
|
+
"ward",
|
|
964
|
+
"motor",
|
|
965
|
+
"storage",
|
|
966
|
+
]
|
|
967
|
+
branch_elements = ["trafo", "line", "trafo3w", "switch", "impedance"]
|
|
968
|
+
all_elements = (
|
|
969
|
+
node_elements + branch_elements + ["bus"] + list(additional_filters.keys())
|
|
970
|
+
)
|
|
971
|
+
all_elements = list(set(all_elements) - set(ignore_elements))
|
|
972
|
+
else:
|
|
973
|
+
net = pps.create_empty_network()
|
|
974
|
+
node_name = "junction"
|
|
975
|
+
component_list = []
|
|
976
|
+
if "data" in meta and "component_list" in meta["data"]:
|
|
977
|
+
component_list = json.loads(
|
|
978
|
+
meta["data"]["component_list"][11:], cls=io_pp.PPJSONDecoder,
|
|
979
|
+
registry_class=FromSerializableRegistryPpipe
|
|
980
|
+
)
|
|
981
|
+
default_branches = []
|
|
982
|
+
default_node_cols = []
|
|
983
|
+
node_elements = []
|
|
984
|
+
all_elements = []
|
|
985
|
+
for c in component_list:
|
|
986
|
+
pps.add_new_component(net, c)
|
|
987
|
+
all_elements.append(c.table_name())
|
|
988
|
+
if issubclass(c, BranchComponent):
|
|
989
|
+
default_branches.append(c.table_name())
|
|
990
|
+
default_node_cols.append(c.from_to_node_cols())
|
|
991
|
+
if issubclass(c, NodeElementComponent):
|
|
992
|
+
node_elements.append(c.table_name())
|
|
993
|
+
special_filters = dict()
|
|
994
|
+
get_nodes_func = {br: get_nodes_from_element for br in default_branches}
|
|
995
|
+
|
|
996
|
+
if db[self._collection_name_of_element(node_name)].find_one() is None:
|
|
903
997
|
net["empty"] = True
|
|
904
998
|
|
|
999
|
+
add_args = {
|
|
1000
|
+
"net": net,
|
|
1001
|
+
"db": db,
|
|
1002
|
+
"net_id": net_id,
|
|
1003
|
+
"include_results": include_results,
|
|
1004
|
+
"geo_mode": geo_mode,
|
|
1005
|
+
"variant": variant,
|
|
1006
|
+
"dtypes": dtypes,
|
|
1007
|
+
"filter": node_filter,
|
|
1008
|
+
}
|
|
1009
|
+
|
|
905
1010
|
# Add buses with filter
|
|
906
|
-
if
|
|
907
|
-
self._add_element_from_collection(
|
|
908
|
-
|
|
909
|
-
db,
|
|
910
|
-
"bus",
|
|
911
|
-
net_id,
|
|
912
|
-
bus_filter,
|
|
913
|
-
geo_mode=geo_mode,
|
|
914
|
-
variant=variant,
|
|
915
|
-
dtypes=dtypes,
|
|
916
|
-
)
|
|
917
|
-
buses = net.bus.index.tolist()
|
|
1011
|
+
if node_filter is not None:
|
|
1012
|
+
self._add_element_from_collection(element_type=node_name, **add_args)
|
|
1013
|
+
nodes = net[node_name].index.tolist()
|
|
918
1014
|
|
|
919
1015
|
if isinstance(add_edge_branches, bool):
|
|
920
1016
|
if add_edge_branches:
|
|
921
|
-
add_edge_branches =
|
|
1017
|
+
add_edge_branches = default_branches
|
|
922
1018
|
else:
|
|
923
1019
|
add_edge_branches = []
|
|
924
1020
|
elif not isinstance(add_edge_branches, list):
|
|
925
1021
|
raise ValueError("add_edge_branches must be a list or a boolean")
|
|
926
|
-
|
|
927
|
-
# Add
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
"
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
"
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
geo_mode=geo_mode,
|
|
967
|
-
variant=variant,
|
|
968
|
-
dtypes=dtypes,
|
|
969
|
-
)
|
|
970
|
-
switch_operator = "$or" if "switch" in add_edge_branches else "$and"
|
|
971
|
-
self._add_element_from_collection(
|
|
972
|
-
net,
|
|
973
|
-
db,
|
|
974
|
-
"switch",
|
|
975
|
-
net_id,
|
|
976
|
-
{
|
|
977
|
-
"$and": [
|
|
978
|
-
{"et": "b"},
|
|
1022
|
+
|
|
1023
|
+
# Add elements for which the user has provided a filter function
|
|
1024
|
+
for element, filter_func in additional_filters.items():
|
|
1025
|
+
if element in ignore_elements:
|
|
1026
|
+
continue
|
|
1027
|
+
add_args["filter"] = filter_func(net)
|
|
1028
|
+
self._add_element_from_collection(element_type=element, **add_args)
|
|
1029
|
+
|
|
1030
|
+
branch_nodes = set()
|
|
1031
|
+
for branch_name, node_cols in zip(default_branches, default_node_cols):
|
|
1032
|
+
operator = "$or" if branch_name in add_edge_branches else "$and"
|
|
1033
|
+
# Add branch elements connected to at least one node
|
|
1034
|
+
filter_ = {operator: [{b: {"$in": nodes}} for b in node_cols]}
|
|
1035
|
+
if branch_name in special_filters:
|
|
1036
|
+
filter_ = special_filters[branch_name](filter_)
|
|
1037
|
+
add_args["filter"] = filter_
|
|
1038
|
+
self._add_element_from_collection(element_type=branch_name, **add_args)
|
|
1039
|
+
get_nd_func = get_nodes_func[branch_name]
|
|
1040
|
+
branch_nodes.update(set(chain.from_iterable(get_nd_func(net, branch_name, node_cols))))
|
|
1041
|
+
|
|
1042
|
+
for branch_name, node_cols in additional_branch_node_cols.items():
|
|
1043
|
+
if branch_name not in net:
|
|
1044
|
+
continue
|
|
1045
|
+
branch_nodes.update(
|
|
1046
|
+
set(chain.from_iterable(get_nodes_from_element(net, branch_name, node_cols)))
|
|
1047
|
+
)
|
|
1048
|
+
|
|
1049
|
+
branch_nodes_outside = []
|
|
1050
|
+
if branch_nodes:
|
|
1051
|
+
# Add buses on the other side of the branches
|
|
1052
|
+
branch_nodes_outside = list(map(int, branch_nodes - set(nodes)))
|
|
1053
|
+
add_args["filter"] = {"index": {"$in": branch_nodes_outside}}
|
|
1054
|
+
self._add_element_from_collection(element_type=node_name, **add_args)
|
|
1055
|
+
nodes = net[node_name].index.tolist()
|
|
1056
|
+
|
|
1057
|
+
if is_power:
|
|
1058
|
+
add_args["filter"] = {
|
|
1059
|
+
"$or": [
|
|
1060
|
+
{"$and": [{"et": "t"}, {"element": {"$in": net.trafo.index.tolist()}}]},
|
|
1061
|
+
{"$and": [{"et": "l"}, {"element": {"$in": net.line.index.tolist()}}]},
|
|
979
1062
|
{
|
|
980
|
-
|
|
981
|
-
{"
|
|
982
|
-
{"element": {"$in":
|
|
1063
|
+
"$and": [
|
|
1064
|
+
{"et": "t3"},
|
|
1065
|
+
{"element": {"$in": net.trafo3w.index.tolist()}},
|
|
983
1066
|
]
|
|
984
1067
|
},
|
|
985
1068
|
]
|
|
986
|
-
}
|
|
987
|
-
|
|
988
|
-
variant=variant,
|
|
989
|
-
dtypes=dtypes,
|
|
990
|
-
)
|
|
991
|
-
if add_edge_branches:
|
|
992
|
-
# Add buses on the other side of the branches
|
|
993
|
-
branch_buses = (
|
|
994
|
-
set(net.trafo.hv_bus.values)
|
|
995
|
-
| set(net.trafo.lv_bus.values)
|
|
996
|
-
| set(net.line.from_bus)
|
|
997
|
-
| set(net.line.to_bus)
|
|
998
|
-
| set(net.trafo3w.hv_bus.values)
|
|
999
|
-
| set(net.trafo3w.mv_bus.values)
|
|
1000
|
-
| set(net.trafo3w.lv_bus.values)
|
|
1001
|
-
| set(net.switch.bus)
|
|
1002
|
-
| set(net.switch.element)
|
|
1003
|
-
)
|
|
1004
|
-
branch_buses_outside = [int(b) for b in branch_buses - set(buses)]
|
|
1005
|
-
self._add_element_from_collection(
|
|
1006
|
-
net,
|
|
1007
|
-
db,
|
|
1008
|
-
"bus",
|
|
1009
|
-
net_id,
|
|
1010
|
-
geo_mode=geo_mode,
|
|
1011
|
-
variant=variant,
|
|
1012
|
-
filter={"index": {"$in": branch_buses_outside}},
|
|
1013
|
-
dtypes=dtypes,
|
|
1014
|
-
)
|
|
1015
|
-
buses = net.bus.index.tolist()
|
|
1016
|
-
|
|
1017
|
-
switch_filter = {
|
|
1018
|
-
"$or": [
|
|
1019
|
-
{"$and": [{"et": "t"}, {"element": {"$in": net.trafo.index.tolist()}}]},
|
|
1020
|
-
{"$and": [{"et": "l"}, {"element": {"$in": net.line.index.tolist()}}]},
|
|
1021
|
-
{
|
|
1022
|
-
"$and": [
|
|
1023
|
-
{"et": "t3"},
|
|
1024
|
-
{"element": {"$in": net.trafo3w.index.tolist()}},
|
|
1025
|
-
]
|
|
1026
|
-
},
|
|
1027
|
-
]
|
|
1028
|
-
}
|
|
1029
|
-
self._add_element_from_collection(
|
|
1030
|
-
net,
|
|
1031
|
-
db,
|
|
1032
|
-
"switch",
|
|
1033
|
-
net_id,
|
|
1034
|
-
switch_filter,
|
|
1035
|
-
geo_mode=geo_mode,
|
|
1036
|
-
variant=variant,
|
|
1037
|
-
dtypes=dtypes,
|
|
1038
|
-
)
|
|
1039
|
-
|
|
1040
|
-
# add node elements
|
|
1041
|
-
node_elements = [
|
|
1042
|
-
"load",
|
|
1043
|
-
"asymmetric_load",
|
|
1044
|
-
"sgen",
|
|
1045
|
-
"asymmetric_sgen",
|
|
1046
|
-
"gen",
|
|
1047
|
-
"ext_grid",
|
|
1048
|
-
"shunt",
|
|
1049
|
-
"xward",
|
|
1050
|
-
"ward",
|
|
1051
|
-
"motor",
|
|
1052
|
-
"storage",
|
|
1053
|
-
]
|
|
1054
|
-
branch_elements = ["trafo", "line", "trafo3w", "switch", "impedance"]
|
|
1055
|
-
all_elements = (
|
|
1056
|
-
node_elements + branch_elements + ["bus"] + list(additional_filters.keys())
|
|
1057
|
-
)
|
|
1058
|
-
all_elements = list(set(all_elements) - set(ignore_elements))
|
|
1069
|
+
}
|
|
1070
|
+
self._add_element_from_collection(element_type="switch", **add_args)
|
|
1059
1071
|
|
|
1060
1072
|
# add all node elements that are connected to buses within the network
|
|
1061
1073
|
for element in node_elements:
|
|
1062
|
-
|
|
1063
|
-
self._add_element_from_collection(
|
|
1064
|
-
net,
|
|
1065
|
-
db,
|
|
1066
|
-
element,
|
|
1067
|
-
net_id,
|
|
1068
|
-
filter=element_filter,
|
|
1069
|
-
geo_mode=geo_mode,
|
|
1070
|
-
include_results=include_results,
|
|
1071
|
-
variant=variant,
|
|
1072
|
-
dtypes=dtypes,
|
|
1073
|
-
)
|
|
1074
|
-
|
|
1075
|
-
# Add elements for which the user has provided a filter function
|
|
1076
|
-
for element, filter_func in additional_filters.items():
|
|
1077
|
-
if element in ignore_elements:
|
|
1078
|
-
continue
|
|
1079
|
-
element_filter = filter_func(net)
|
|
1080
|
-
self._add_element_from_collection(
|
|
1081
|
-
net,
|
|
1082
|
-
db,
|
|
1083
|
-
element,
|
|
1084
|
-
net_id,
|
|
1085
|
-
filter=element_filter,
|
|
1086
|
-
geo_mode=geo_mode,
|
|
1087
|
-
include_results=include_results,
|
|
1088
|
-
variant=variant,
|
|
1089
|
-
dtypes=dtypes,
|
|
1090
|
-
)
|
|
1074
|
+
add_args["filter"] = {node_name: {"$in": nodes}}
|
|
1075
|
+
self._add_element_from_collection(element_type=element, **add_args)
|
|
1091
1076
|
|
|
1092
1077
|
# add all other collections
|
|
1093
1078
|
collection_names = self.get_net_collections(db)
|
|
1094
1079
|
for collection in collection_names:
|
|
1095
1080
|
table_name = self._element_name_of_collection(collection)
|
|
1096
1081
|
# skip all element tables that we have already added
|
|
1097
|
-
if table_name in all_elements or table_name in ignore_elements
|
|
1082
|
+
if (table_name in all_elements or table_name in ignore_elements
|
|
1083
|
+
or table_name in additional_filters.keys()):
|
|
1098
1084
|
continue
|
|
1099
1085
|
# for tables that share an index with an element (e.g. load->res_load) load only relevant entries
|
|
1100
1086
|
for element in all_elements:
|
|
@@ -1106,18 +1092,11 @@ class PandaHub:
|
|
|
1106
1092
|
else:
|
|
1107
1093
|
# all other tables (e.g. std_types) are loaded without filter
|
|
1108
1094
|
element_filter = None
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
db,
|
|
1112
|
-
table_name,
|
|
1113
|
-
net_id,
|
|
1114
|
-
filter=element_filter,
|
|
1115
|
-
geo_mode=geo_mode,
|
|
1116
|
-
include_results=include_results,
|
|
1117
|
-
variant=variant,
|
|
1118
|
-
dtypes=dtypes,
|
|
1119
|
-
)
|
|
1095
|
+
add_args["filter"] = element_filter
|
|
1096
|
+
self._add_element_from_collection(element_type=table_name, **add_args)
|
|
1120
1097
|
self.deserialize_and_update_data(net, meta)
|
|
1098
|
+
if return_edge_branch_nodes:
|
|
1099
|
+
return net, branch_nodes_outside
|
|
1121
1100
|
return net
|
|
1122
1101
|
|
|
1123
1102
|
def _collection_name_of_element(self, element):
|
|
@@ -3217,7 +3196,6 @@ class PandaHub:
|
|
|
3217
3196
|
return self.get_net_collections(db, with_areas)
|
|
3218
3197
|
|
|
3219
3198
|
|
|
3220
|
-
|
|
3221
3199
|
if __name__ == "__main__":
|
|
3222
3200
|
self = PandaHub()
|
|
3223
3201
|
project_name = "test_project"
|
|
@@ -7,7 +7,7 @@ DATATYPES = {
|
|
|
7
7
|
"zone": str,
|
|
8
8
|
"in_service": bool,
|
|
9
9
|
"max_vm_pu": float,
|
|
10
|
-
"min_vm_pu": float
|
|
10
|
+
"min_vm_pu": float,
|
|
11
11
|
},
|
|
12
12
|
"load": {
|
|
13
13
|
"name": str,
|
|
@@ -95,7 +95,7 @@ DATATYPES = {
|
|
|
95
95
|
"type": str,
|
|
96
96
|
"in_service": bool,
|
|
97
97
|
"max_loading_percent": float,
|
|
98
|
-
"std_type": str
|
|
98
|
+
"std_type": str,
|
|
99
99
|
},
|
|
100
100
|
"trafo": {
|
|
101
101
|
"name": str,
|
|
@@ -306,12 +306,4 @@ DATATYPES = {
|
|
|
306
306
|
'initial_run': bool,
|
|
307
307
|
"recycle": str
|
|
308
308
|
},
|
|
309
|
-
"line_geodata": {
|
|
310
|
-
"coords": object
|
|
311
|
-
},
|
|
312
|
-
"bus_geodata": {
|
|
313
|
-
"x": float,
|
|
314
|
-
"y": float,
|
|
315
|
-
"coords": object
|
|
316
|
-
},
|
|
317
309
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from contextlib import contextmanager
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Generator, overload
|
|
3
3
|
|
|
4
4
|
from pymongo import MongoClient
|
|
5
5
|
from pymongo.synchronous.collection import Collection
|
|
@@ -7,6 +7,7 @@ from pymongo.synchronous.database import Database
|
|
|
7
7
|
|
|
8
8
|
from pandahub.api.internal.settings import PANDAHUB_GLOBAL_DB_CLIENT, MONGODB_URL, MONGODB_USER, MONGODB_PASSWORD
|
|
9
9
|
|
|
10
|
+
|
|
10
11
|
def _get_mongo_client(connection_url: str = MONGODB_URL, connection_user: str = MONGODB_USER,
|
|
11
12
|
connection_password: str = MONGODB_PASSWORD) -> MongoClient:
|
|
12
13
|
mongo_client_args = {
|
|
@@ -27,8 +28,20 @@ else:
|
|
|
27
28
|
_global_mongo_client = None
|
|
28
29
|
|
|
29
30
|
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@overload
|
|
34
|
+
def get_mongo_client(database: None = None, collection: None = None,
|
|
35
|
+
connection_url: str = ..., connection_user: str = ..., connection_password: str = ...) -> MongoClient: ...
|
|
36
|
+
@overload
|
|
37
|
+
def get_mongo_client(database: str, collection: None=None,
|
|
38
|
+
connection_url: str = ..., connection_user: str = ..., connection_password: str = ...) -> Database: ...
|
|
39
|
+
@overload
|
|
40
|
+
def get_mongo_client(database: str, collection: str,
|
|
41
|
+
connection_url: str = ..., connection_user: str = ..., connection_password: str = ...) -> Collection: ...
|
|
42
|
+
|
|
30
43
|
def get_mongo_client(database: str | None = None, collection: str | None = None, connection_url: str = MONGODB_URL, connection_user: str = MONGODB_USER,
|
|
31
|
-
connection_password: str = MONGODB_PASSWORD) ->
|
|
44
|
+
connection_password: str = MONGODB_PASSWORD) -> MongoClient | Database | Collection:
|
|
32
45
|
if collection is not None and database is None:
|
|
33
46
|
raise ValueError("Must specify database to access a collection!")
|
|
34
47
|
if _global_mongo_client is None:
|
|
@@ -40,7 +53,7 @@ def get_mongo_client(database: str | None = None, collection: str | None = None,
|
|
|
40
53
|
|
|
41
54
|
@contextmanager
|
|
42
55
|
def mongo_client(database: str | None = None, collection: str | None = None, connection_url: str = MONGODB_URL,
|
|
43
|
-
connection_user: str = MONGODB_USER, connection_password: str = MONGODB_PASSWORD) ->
|
|
56
|
+
connection_user: str = MONGODB_USER, connection_password: str = MONGODB_PASSWORD) -> Generator[MongoClient | Database | Collection, None, None]:
|
|
44
57
|
"""Contextmanager for pymongo MongoClient / Database / Collection with close after use.
|
|
45
58
|
|
|
46
59
|
Parameters
|
|
@@ -69,7 +82,7 @@ def mongo_client(database: str | None = None, collection: str | None = None, con
|
|
|
69
82
|
client.close()
|
|
70
83
|
|
|
71
84
|
|
|
72
|
-
def _get_db_or_coll(client: MongoClient, database: str | None = None, collection: str | None = None) ->
|
|
85
|
+
def _get_db_or_coll(client: MongoClient, database: str | None = None, collection: str | None = None) -> MongoClient | Database | Collection:
|
|
73
86
|
if database is not None and collection is not None:
|
|
74
87
|
return client[database][collection]
|
|
75
88
|
elif database is not None:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pandahub
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: Data hub for pandapower and pandapipes networks based on MongoDB
|
|
5
5
|
Author-email: Jan Ulffers <jan.ulffers@iee.fraunhofer.de>, Leon Thurner <leon.thurner@retoflow.de>, Jannis Kupka <jannis.kupka@retoflow.de>, Mike Vogt <mike.vogt@iee.fraunhofer.de>, Joschka Thurner <joschka.thurner@retoflow.de>, Alexander Scheidler <alexander.scheidler@iee.fraunhofer.de>
|
|
6
6
|
License: Copyright (c) 2022 by University of Kassel, Fraunhofer Institute for Energy Economics
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pandahub"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.1" # File format version '__format_version__' is tracked in __init__.py
|
|
8
8
|
authors=[
|
|
9
9
|
{ name = "Jan Ulffers", email = "jan.ulffers@iee.fraunhofer.de" },
|
|
10
10
|
{ name = "Leon Thurner", email = "leon.thurner@retoflow.de" },
|
|
@@ -46,7 +46,7 @@ def load_test_subnet_from_mongodb(project_name):
|
|
|
46
46
|
buses = list(range(1000))
|
|
47
47
|
t0 = time.time()
|
|
48
48
|
subnet = ph.get_subnet_by_name("test_net",
|
|
49
|
-
|
|
49
|
+
node_filter={"index": {"$in": buses}})
|
|
50
50
|
t1 = time.time()
|
|
51
51
|
print("LOADED NET IN %.2fs"%(t1-t0))
|
|
52
52
|
return subnet
|
|
@@ -90,20 +90,20 @@ def test_load_subnetwork(ph):
|
|
|
90
90
|
net = nw_pp.mv_oberrhein()
|
|
91
91
|
ph.write_network_to_db(net, name)
|
|
92
92
|
|
|
93
|
-
subnet = ph.get_subnet_by_name(name,
|
|
93
|
+
subnet = ph.get_subnet_by_name(name, node_filter={"vn_kv": 110})
|
|
94
94
|
expected_sizes = [("bus", 4), ("line", 0), ("trafo", 2), ("ext_grid", 2)]
|
|
95
95
|
|
|
96
96
|
for element, size in expected_sizes:
|
|
97
97
|
assert len(subnet[element]) == size
|
|
98
98
|
assert len(subnet["res_" + element]) == size
|
|
99
99
|
|
|
100
|
-
subnet = ph.get_subnet_by_name(name,
|
|
100
|
+
subnet = ph.get_subnet_by_name(name, node_filter={"vn_kv": 110},
|
|
101
101
|
include_results=False)
|
|
102
102
|
for element, size in expected_sizes:
|
|
103
103
|
assert len(subnet[element]) == size
|
|
104
104
|
assert len(subnet["res_" + element]) == 0
|
|
105
105
|
|
|
106
|
-
subnet = ph.get_subnet_by_name(name,
|
|
106
|
+
subnet = ph.get_subnet_by_name(name, node_filter={"vn_kv": 110},
|
|
107
107
|
add_edge_branches=False)
|
|
108
108
|
expected_sizes = [("bus", 2), ("line", 0), ("trafo", 0), ("ext_grid", 2)]
|
|
109
109
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|