Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tap controllers from pandapower #887

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 50 additions & 2 deletions pypowsybl/network/impl/pandapower_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
DEFAULT_MIN_P = -4999.0
DEFAULT_MAX_P = 4999.0

# Setup logging configuration
logging.basicConfig(level=logging.ERROR, format='%(levelname)s: %(message)s')

def convert_from_pandapower(n_pdp: pandapowerNet) -> Network:
if util.find_spec("pandapower") is None:
Expand Down Expand Up @@ -120,8 +122,10 @@ def create_transformers(n: Network, n_pdp: pandapowerNet) -> None:
connectable_bus2_id = build_bus_id(trafo_and_bus['lv_bus'].astype(str))
bus1_id = np.where(trafo_and_bus['in_service'], connectable_bus1_id, "")
bus2_id = np.where(trafo_and_bus['in_service'], connectable_bus2_id, "")
n_tap = np.where(~np.isnan(trafo_and_bus['tap_pos']) & ~np.isnan(trafo_and_bus['tap_neutral']) & ~np.isnan(trafo_and_bus['tap_step_percent']),
1.0 + (trafo_and_bus['tap_pos'] - trafo_and_bus['tap_neutral']) * trafo_and_bus['tap_step_percent'] / 100.0, 1.0)
# Run this for trafos which are not phase shifters
# Here we enable also the cross regulator
# For case of PST if tap_step_degree and tap_step_percent is defined , it will lead to error in power flow
n_tap = extract_tap_info(trafo_and_bus)
rated_u1 = np.where(trafo_and_bus['tap_side'] == "hv", trafo_and_bus['vn_hv_kv'] * n_tap, trafo_and_bus['vn_hv_kv'])
rated_u2 = np.where(trafo_and_bus['tap_side'] == "lv", trafo_and_bus['vn_lv_kv'] * n_tap, trafo_and_bus['vn_lv_kv'])
c = n_pdp.sn_mva / n_pdp.trafo['sn_mva']
Expand Down Expand Up @@ -204,6 +208,50 @@ def create_shunts(n: Network, n_pdp: pandapowerNet) -> None:
}, index=shunt_id)
n.create_shunt_compensators(shunt_df=shunt_df, linear_model_df=linear_model_df)

def extract_tap_info(trafo_and_bus):
"""
This function ensures that the pandapower model was correct wrt phase_shifter boolean
Furthermore, the tap_step_percent is calculated from tap_step_degree which is
then augmented to the tap_step_percent already present, this means powsybl can just use
tap_step_percent for the calculations and then calculates the n_tap value
"""

# Create a copy of 'tap_step_percent' to modify
tap_step_percent_new = np.zeros_like(trafo_and_bus['tap_step_percent'])

# Check if 'tap_step_degree' is not NaN (available) for transformers
degree_mask = ~np.isnan(trafo_and_bus['tap_step_degree'])

# Identify phase shift transformers (tap_phase_shifter == True)
phase_shift_mask = trafo_and_bus['tap_phase_shifter']

# Log error if both tap_step_degree and tap_step_percent are parameterized for phase shift transformers
both_parameterized_mask = phase_shift_mask & degree_mask & ~np.isnan(trafo_and_bus['tap_step_percent'])

if np.any(both_parameterized_mask):
for idx in trafo_and_bus.index[both_parameterized_mask]:
logging.error(
f"Transformer at index {idx} has both 'tap_step_degree' and 'tap_step_percent' parameterized, This is"
"not allowed in pandapower.")

# For transformers where 'tap_step_degree' is present, calculate tap_step_percent_new
tap_step_percent_new[degree_mask] = (
0.01 * (2 * np.sin(0.5 * trafo_and_bus['tap_step_degree'][degree_mask])) # Correct formula
)

# Add the newly calculated tap_step_percent_new to the existing tap_step_percent
trafo_and_bus['tap_step_percent'] += tap_step_percent_new # Update original tap_step_percent

# Now calculate n_tap based on the updated tap_step_percent
n_tap = np.where(
(~np.isnan(trafo_and_bus['tap_pos']) &
~np.isnan(trafo_and_bus['tap_neutral']) &
~np.isnan(trafo_and_bus['tap_step_percent'])), # Use the updated 'tap_step_percent'
1.0 + (trafo_and_bus['tap_pos'] - trafo_and_bus['tap_neutral']) * trafo_and_bus['tap_step_percent'] / 100.0,
1.0
)
return n_tap

class PandaPowerGeneratorType(Enum):
GENERATOR = 1
EXT_GRID = 2
Expand Down
Loading