Skip to content

Commit 0dec7ec

Browse files
grid.py from psdm2pp
1 parent 1d59000 commit 0dec7ec

File tree

3 files changed

+201
-67
lines changed

3 files changed

+201
-67
lines changed

poetry.lock

Lines changed: 32 additions & 28 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pp2psdm/grid.py

Lines changed: 168 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import math
22
from dataclasses import dataclass, field
3+
from datetime import datetime
34
from typing import Tuple
5+
from uuid import uuid4
46

57
import numpy as np
68
import pandapower as pp
79
import pandas as pd
810
from pypsdm.models.input.container.raw_grid import RawGridContainer
911
from pypsdm.models.input.create.participants import create_data
12+
from pypsdm.models.input.create.grid_elements import create_nodes, create_nodes_data, create_lines, create_lines_data
1013

1114

1215
@dataclass
@@ -25,9 +28,10 @@ def convert_grid(
2528
net = RawGridContainer.empty(
2629
)
2730

28-
for uuid, bus in grid.bus.data.iterrows():
29-
idx = convert_node(net, bus)
30-
uuid_idx.bus[uuid] = idx # type: ignore
31+
nodes = convert_nodes(grid.bus)
32+
33+
convert_lines(grid)
34+
3135

3236
for uuid, line in grid.line.data.iterrows():
3337
idx = convert_line(net, line, uuid_idx.node)
@@ -41,48 +45,174 @@ def convert_grid(
4145

4246
return net, uuid_idx
4347

48+
def convert_nodes(grid):
49+
nodes_data = {}
4450

45-
def convert_node(net: pp.pandapowerNet, node_data: pd.Series):
46-
node_id = node_data["id"]
47-
vn_kv = node_data["v_rated"]
48-
xy_coords = [node_data["longitude"], node_data["latitude"]]
49-
subnet = node_data["subnet"]
50-
node_type = "b"
51-
return create_nodes_data(
51+
df = grid.bus
5252

53-
)
53+
for idx, row in df.iterrows():
54+
# TODO SLACK?
5455

56+
# Get operation times
57+
operates_from, operates_until = get_operation_times(row)
5558

56-
def convert_line(net: pp.pandapowerNet, line_data: pd.Series, uuid_idx: dict):
57-
line_id = line_data["id"]
58-
from_bus = uuid_idx[line_data["node_a"]]
59-
to_bus = uuid_idx[line_data["node_b"]]
60-
length_km = line_data["length"]
61-
r_ohm_per_km = line_data["r"]
62-
x_ohm_per_km = line_data["x"]
63-
g_us_per_km, c_nf_per_km = line_param_conversion(
64-
float(line_data["b"]), float(line_data["g"])
65-
)
66-
max_i_ka = line_data["i_max"] / 1000
67-
return pp.create_line_from_parameters(
68-
net,
69-
name=line_id,
70-
from_bus=from_bus,
71-
to_bus=to_bus,
72-
length_km=length_km,
73-
r_ohm_per_km=r_ohm_per_km,
74-
x_ohm_per_km=x_ohm_per_km,
75-
c_nf_per_km=c_nf_per_km,
76-
max_i_ka=max_i_ka,
77-
g_us_per_km=g_us_per_km,
78-
)
59+
# Determine the voltage level (vlt_lvl or vn_kv)
60+
if "vlt_lvl" in df.columns and not pd.isna(row["vlt_lvl"]):
61+
volt_lvl = row["vlt_lvl"]
62+
else:
63+
volt_lvl = row["vn_kv"]
64+
65+
# Determine the subnet (subnet, zone, or fixed number)
66+
if "subnet" in df.columns and not pd.isna(row["subnet"]):
67+
subnet = row["subnet"]
68+
elif "zone" in df.columns and not pd.isna(row["zone"]):
69+
subnet = row["zone"]
70+
else:
71+
subnet = 101
72+
73+
node_data = create_nodes_data(
74+
uuid=row["uuid"],
75+
geo_position=None,
76+
id=row["name"],
77+
subnet=subnet,
78+
v_rated=row["vn_kv"],
79+
v_target=row["vn_kv"],
80+
volt_lvl=volt_lvl,
81+
operates_from=operates_from,
82+
operates_until=operates_until,
83+
operator=None,
84+
slack=False
85+
)
86+
nodes_data[node_data.name] = node_data
87+
88+
if row["uuid"] == '1f6e5dd7-9bd7-4bb5-9ff9-56000a6cd14b':
89+
print(node_data)
90+
91+
92+
# if row["uuid"] == '798443cf-7d59-4e95-aaf5-955f65531bac':
93+
# print(node_data)
94+
95+
96+
return create_nodes(nodes_data)
97+
98+
99+
def get_operation_times(row):
100+
if row["in_service"]:
101+
operates_from = None
102+
operates_until = None
103+
else:
104+
operates_from = datetime(1980, 1, 1)
105+
operates_until = datetime(1980, 1, 2)
106+
107+
return operates_from, operates_until
108+
109+
110+
def get_node_uuid(nodes, node_id):
111+
for uuid, node_data in nodes.items():
112+
if node_data['id'] == node_id:
113+
return uuid
114+
raise ValueError(f"No matching node found for id {node_id}")
115+
116+
def get_v_target_for_node(nodes, node_uuid):
117+
return nodes[node_uuid]['v_target']
79118

80119

81-
def line_param_conversion(b_us: float, g_us: float):
82-
g_us_per_km = g_us
120+
def line_param_conversion(c_nf_per_km: float, g_us_per_km: float):
121+
g_us = g_us_per_km
83122
f = 50
84-
c_nf_per_km = b_us / (2 * np.pi * f * 1e-3)
85-
return g_us_per_km, c_nf_per_km
123+
b_us = c_nf_per_km * (2 * np.pi * f * 1e-3)
124+
125+
return g_us, b_us
126+
127+
def convert_line_types(df, nodes):
128+
line_type_columns = ['r_ohm_per_km', 'x_ohm_per_km', 'c_nf_per_km', 'g_us_per_km', 'max_i_ka']
129+
unique_line_types = df[line_type_columns].drop_duplicates().reset_index(drop=True)
130+
131+
line_types = {}
132+
133+
for idx, row in unique_line_types.iterrows():
134+
uuid = str(uuid4())
135+
136+
g_us, b_us = line_param_conversion(row['c_nf_per_km'], row['g_us_per_km'])
137+
138+
# Retrieve node_a and node_b UUIDs based on from_bus and to_bus
139+
node_a_uuid = get_node_uuid(nodes, row['from_bus'])
140+
node_b_uuid = get_node_uuid(nodes, row['to_bus'])
141+
142+
# Retrieve v_target for node_a and node_b
143+
v_target_a = get_v_target_for_node(nodes, node_a_uuid)
144+
v_target_b = get_v_target_for_node(nodes, node_b_uuid)
145+
146+
# Ensure v_target_a and v_target_b are the same
147+
if v_target_a != v_target_b:
148+
raise ValueError(f"v_target mismatch between node_a ({v_target_a}) and node_b ({v_target_b}) for line {row['from_bus']} to {row['to_bus']}")
149+
150+
151+
line_types[uuid] = {
152+
'uuid': uuid,
153+
'r': row['r_ohm_per_km'],
154+
'x': row['x_ohm_per_km'],
155+
'b': b_us,
156+
'g': g_us,
157+
'i_max': row['max_i_ka'] * 1000,
158+
'id': f"line_type_{idx + 1}",
159+
'v_rated': v_target_a,
160+
}
161+
162+
return line_types
163+
def convert_lines(df, line_types, nodes):
164+
lines_data = []
165+
166+
for idx, row in df.iterrows():
167+
# Find the corresponding line type based on r, x, c, g, max_i_ka
168+
line_type_uuid = None
169+
170+
for uuid, line_type_data in line_types.items():
171+
if (
172+
line_type_data['r'] == row['r_ohm_per_km'] and
173+
line_type_data['x'] == row['x_ohm_per_km'] and
174+
line_type_data['b'] == row['c_nf_per_km'] and
175+
line_type_data['g'] == row['g_us_per_km'] and
176+
line_type_data['i_max'] == row['max_i_ka']
177+
):
178+
line_type_uuid = uuid
179+
break
180+
181+
# If no matching line type is found, there might be an issue
182+
if not line_type_uuid:
183+
raise ValueError(f"No matching line type found for line {row['name']}")
184+
185+
# Retrieve node_a and node_b UUIDs based on from_bus and to_bus
186+
node_a_uuid = get_node_uuid(nodes, row['from_bus'])
187+
node_b_uuid = get_node_uuid(nodes, row['to_bus'])
188+
189+
# Set operates_from and operates_until based on in_service status
190+
if row['in_service']:
191+
operates_from = None
192+
operates_until = None
193+
else:
194+
operates_from = datetime(1980, 1, 1)
195+
operates_until = datetime(1980, 12, 31)
196+
197+
# Create line data
198+
line_data = {
199+
'uuid': row["uuid"],
200+
'geo_position': None,
201+
'id': row['name'],
202+
'length': row['length_km'],
203+
'node_a': node_a_uuid,
204+
'node_b': node_b_uuid,
205+
'olm_characteristic': "olm:{(0.0,1.0)}",
206+
'operates_from': operates_from,
207+
'operates_until': operates_until,
208+
'operator': None,
209+
'parallel_devices': row['parallel'],
210+
'type': line_type_uuid,
211+
}
212+
213+
lines_data.append(line_data)
214+
215+
return lines_data
86216

87217

88218
def convert_transformer(net: pp.pandapowerNet, trafo_data: pd.Series, uuid_idx: dict):

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ readme = "README.md"
77

88
[tool.poetry.dependencies]
99
python = "<3.12,>3.11"
10-
pypsdm = "^0.0.3"
10+
pypsdm = {git = "https://github.com/ie3-institute/pypsdm.git"}
1111
pandapower = "^2.14.11"
1212
simbench = "^1.5.3"
1313

0 commit comments

Comments
 (0)