88import math
99import os
1010import tempfile
11+ from copy import deepcopy
1112
1213from os import remove
1314from os .path import isfile
2526from pandapower .pypower .idx_cost import MODEL , NCOST , COST
2627from pandapower .pypower .idx_gen import PG , QG , GEN_BUS , VG , GEN_STATUS , QMAX , QMIN , PMIN , PMAX
2728from pandapower .results import init_results , verify_results
29+ from pandapower .auxiliary import pandapowerNet
30+ from collections .abc import Callable
31+ from typing import Literal
2832
2933
3034# const value in branch for tnep
@@ -51,13 +55,31 @@ def default(self, obj):
5155 return json .JSONEncoder .default (self , obj )
5256
5357
54- def convert_pp_to_pm (net , pm_file_path = None , correct_pm_network_data = True ,
55- calculate_voltage_angles = True ,
56- ac = True , silence = True , trafo_model = "t" , delta = 1e-8 , trafo3w_losses = "hv" ,
57- check_connectivity = True , pp_to_pm_callback = None , pm_model = "ACPPowerModel" ,
58- pm_solver = "ipopt" ,
59- pm_mip_solver = "cbc" , pm_nl_solver = "ipopt" , opf_flow_lim = "S" , pm_tol = 1e-8 ,
60- voltage_depend_loads = False , from_time_step = None , to_time_step = None , init_vm_pu = "flat" , init_va_degree = "flat" , ** kwargs ):
58+ def convert_pp_to_pm (
59+ net : pandapowerNet ,
60+ pm_file_path : str | None = None ,
61+ correct_pm_network_data : bool | None = True ,
62+ calculate_voltage_angles : bool | None = True ,
63+ ac : bool | None = True ,
64+ silence : bool | None = True ,
65+ trafo_model : str | None = "t" ,
66+ delta : float | None = 1e-8 ,
67+ trafo3w_losses : str | None = "hv" ,
68+ check_connectivity : bool | None = True ,
69+ pp_to_pm_callback : Callable | None = None ,
70+ pm_model : str | None = "ACPPowerModel" ,
71+ pm_solver : str | None = "ipopt" ,
72+ pm_mip_solver : str | None = "cbc" ,
73+ pm_nl_solver : str | None = "ipopt" ,
74+ opf_flow_lim : str | None = "S" ,
75+ pm_tol : float | None = 1e-8 ,
76+ voltage_depend_loads : bool | None = False ,
77+ from_time_step : int | None = None ,
78+ to_time_step : int | None = None ,
79+ init_vm_pu : Literal ["flat" , "results" ] | float = "flat" ,
80+ init_va_degree : Literal ["dc" , "flat" , "results" ] | float = "flat" ,
81+ ** kwargs
82+ ):
6183 """
6284 Converts a pandapower net to a PowerModels.jl datastructure and saves it to a json file
6385 INPUT:
@@ -106,6 +128,19 @@ def convert_pp_to_pm(net, pm_file_path=None, correct_pm_network_data=True,
106128 net.load.const_z_q_percent and net.load.const_i_q_percent are not considered,
107129 i.e. net.load.p_mw and net.load.q_mvar are considered as constant-power loads.
108130
131+ **from_time_step** (int, None) - for timeseries calculation / optimization,
132+ starting timestep (to_time_step must be also set!).
133+
134+ **to_time_step** (int, None) - for timeseries calculation / optimization,
135+ starting timestep (from_time_step must be also set!).
136+
137+ **init_vm_pu** (["flat", "results"], float) - Allows to define initialization
138+ specifically for voltage magnitudes.
139+
140+ **init_va_degree** (["dc", "flat", "results"], float) - Allows to define
141+ initialization specifically for voltage angles.
142+
143+
109144 Returns
110145 -------
111146 """
@@ -135,8 +170,13 @@ def convert_pp_to_pm(net, pm_file_path=None, correct_pm_network_data=True,
135170logger = logging .getLogger (__name__ )
136171
137172
138- def convert_to_pm_structure (net , opf_flow_lim = "S" , from_time_step = None , to_time_step = None ,
139- ** kwargs ):
173+ def convert_to_pm_structure (
174+ net : pandapowerNet ,
175+ # opf_flow_lim: str = "S", # unused, is saved in net["_opf_options"].
176+ from_time_step : int | None = None ,
177+ to_time_step : int | None = None ,
178+ ** kwargs
179+ ):
140180 if net ["_options" ]["voltage_depend_loads" ] and not (
141181 np .allclose (net .load .const_z_p_percent .values , 0 ) and
142182 np .allclose (net .load .const_i_p_percent .values , 0 ) and
@@ -164,7 +204,10 @@ def convert_to_pm_structure(net, opf_flow_lim="S", from_time_step=None, to_time_
164204 return net , pm , ppc , ppci
165205
166206
167- def dump_pm_json (pm , buffer_file = None ):
207+ def dump_pm_json (
208+ pm : dict ,
209+ buffer_file : str | None = None
210+ ):
168211 # dump pm dict to buffer_file (*.json)
169212 if buffer_file is None :
170213 # if no buffer file is provided a random file name is generated
@@ -256,11 +299,22 @@ def ppc_to_pm(net, ppci):
256299 # create power models dict. Similar to matpower case file. ne_branch is for a tnep case
257300 # "per_unit == True" means that the grid data in PowerModels are per-unit values. In this
258301 # ppc-to-pm process, the grid data schould be transformed according to baseMVA = 1.
259- pm = {"gen" : {}, "branch" : {}, "bus" : {}, "dcline" : {}, "load" : {},
260- "storage" : {},
261- "ne_branch" : {}, "switch" : {},
262- "baseMVA" : ppci ["baseMVA" ], "source_version" : "2.0.0" , "shunt" : {},
263- "sourcetype" : "matpower" , "per_unit" : True , "name" : net .name }
302+ pm = {
303+ "gen" : {},
304+ "branch" : {},
305+ "bus" : {},
306+ "dcline" : {},
307+ "load" : {},
308+ "storage" : {},
309+ "ne_branch" : {},
310+ "switch" : {},
311+ "baseMVA" : ppci ["baseMVA" ],
312+ "source_version" : "2.0.0" ,
313+ "shunt" : {},
314+ "sourcetype" : "matpower" ,
315+ "per_unit" : True ,
316+ "name" : net .name
317+ }
264318 baseMVA = ppci ["baseMVA" ]
265319 load_idx = 1
266320 shunt_idx = 1
@@ -315,8 +369,27 @@ def ppc_to_pm(net, ppci):
315369 shunt_idx += 1
316370 pm ["bus" ][str (idx )] = bus
317371
372+ # number of bus-bus switches in the network
373+ n_bb_switches = net ._impedance_bb_switches .sum ()
374+
318375 n_lines = net .line .in_service .sum ()
319376 for idx , row in enumerate (ppci ["branch" ], start = 1 ):
377+
378+ # the bus-bus switches are added to the end of the ppci, +1 since we use 1-indexing.
379+ if idx > (n_lines - n_bb_switches + 1 ):
380+ switch = {
381+ "index" : idx ,
382+ "f_bus" : int (row [F_BUS ].real ) + 1 ,
383+ "t_bus" : int (row [T_BUS ].real ) + 1 ,
384+ "status" : 1 ,
385+ "state" : 1 ,
386+ "thermal_rating" : np .inf ,
387+ "psw" : 0. ,
388+ "qsw" : 0. ,
389+ }
390+ pm ["switch" ][str (idx - n_lines )] = switch
391+ continue
392+
320393 branch = {}
321394 branch ["index" ] = idx
322395 branch ["transformer" ] = bool (idx > n_lines )
@@ -346,6 +419,8 @@ def ppc_to_pm(net, ppci):
346419 branch ["shift" ] = math .radians (row [SHIFT ].real )
347420 pm ["branch" ][str (idx )] = branch
348421
422+
423+
349424 #### create pm["gen"]
350425 gen_idxs_pm = [str (i + 1 ) for i in range (len (ppci ["gen" ]))]
351426 gen_df = pd .DataFrame (index = gen_idxs_pm )
@@ -562,7 +637,12 @@ def add_params_to_pm(net, pm):
562637 return pm
563638
564639
565- def add_time_series_to_pm (net , pm , from_time_step , to_time_step ):
640+ def add_time_series_to_pm (
641+ net : pandapowerNet ,
642+ pm : dict ,
643+ from_time_step : int ,
644+ to_time_step : int
645+ ):
566646 from pandapower .control import ConstControl
567647 if from_time_step is None or to_time_step is None :
568648 raise ValueError ("please define 'from_time_step' " +
0 commit comments