Skip to content

[bug] OPF (line) loading limits not considered correctly #2959

@kornerc

Description

@kornerc

Bug report checklis

  • Searched the issues page for similar reports

  • Read the relevant sections of the documentation

  • Browse the tutorials and tests for usefull code snippets and examples of use

  • Reproduced the issue after updating with pip install --upgrade pandapower (or git pull)

  • Tried basic troubleshooting (if a bug/error) like restarting the interpreter and checking the pythonpath

Reproducible Example

import pandapower as pp

def grid_simulation(opt_load: bool, slack_voltage: float) -> pp.pandapowerNet:
    net = pp.create_empty_network()

    b1 = pp.create_bus(net, vn_kv=20., min_vm_pu=0.9, max_vm_pu=1.1)
    b2 = pp.create_bus(net, vn_kv=20., min_vm_pu=0.9, max_vm_pu=1.1)
    pp.create_line(net, from_bus=b1, to_bus=b2, length_km=10.0, std_type="NAYY 4x50 SE", max_loading_percent=80.0)
    pp.create_ext_grid(net, bus=b1, vm_pu=slack_voltage)
    load = pp.create_load(net, bus=b2, p_mw=0.0, min_p_mw=-5.0, max_p_mw=4.0, min_q_mvar=0.0, max_q_mvar=0.0, controllable=True)

    pp.create_poly_cost(net, element=load, et="load", cp1_eur_per_mw=-1.0 if opt_load else 1.0)

    pp.runpm_ac_opf(net)

    return net

def main():
    for opt_load in [True, False]:
        for slack_voltage in [1.0, 1.02]:
            net = grid_simulation(opt_load, slack_voltage)

            print(f"Scenario: Increase {'load' if opt_load else 'generation'} | Slack Voltage: {slack_voltage:.2f} p.u.")
            print(f"\tLoading {net.res_line['loading_percent'].values[0]:.1f} % (Max. 80 %)")
            print(f"\tLoad {net.res_load['p_mw'].values[0]:.1f} MW")
            print(f"\tVoltage {net.res_bus["vm_pu"].min():.3f} - {net.res_bus["vm_pu"].max():.3f} p.u.")
            print()

if __name__ == "__main__":
    main()

Always a line loading of 80 % would be expected:

Scenario: Increase load | Slack Voltage: 1.00 p.u.
	Loading 80.0 % (Max. 80 %)
	Load 3.7 MW
	Voltage 0.937 - 1.000 p.u.

Scenario: Increase load | Slack Voltage: 1.02 p.u.
	Loading 78.4 % (Max. 80 %)
	Load 3.7 MW
	Voltage 0.958 - 1.020 p.u.

Scenario: Increase generation | Slack Voltage: 1.00 p.u.
	Loading 75.7 % (Max. 80 %)
	Load -3.9 MW
	Voltage 1.000 - 1.060 p.u.

Scenario: Increase generation | Slack Voltage: 1.02 p.u.
	Loading 74.4 % (Max. 80 %)
	Load -3.9 MW
	Voltage 1.020 - 1.079 p.u.

Issue Description and Traceback

When running the OPF the line (and maybe also the transformer) loading limits are not considered correctly.

The cause might be the following:

  • When setting up the optimization model, pandapower transforms a line loading limit from a current limit to an apparent power limit using the nominal voltage of the connected from bus
    vr = net.bus.loc[line["from_bus"].values, "vn_kv"].values * np.sqrt(3.)

    branch[f:t, RATE_A] = max_load / 100. * max_i_ka * df * parallel * vr
  • When calculating the loading after the optimization, not the apparent power but the current is used
    np.divide(i_ka, i_max, where=i_max != 0, out=loading, dtype=np.float64)

So it seems to me like the optimizer uses apparent power limits for the loading but pandapower uses the current as loding limit.
Depending on the voltage this will result in different loadings.

Expected Behavior

Consider the current loading limit and not the apparent power loading limit for the OPF.

It seems like PYPOWER (parameter rateA) does not support that but PowerModels.jl (parameter c_rating_a) does.

Installed Versions

python version: 3.13.5
pandapower: 3.4.0
pandas version: 2.3.3

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions