Skip to content
Open
Show file tree
Hide file tree
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
7 changes: 3 additions & 4 deletions pandapower/opf/make_objective.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,16 @@ def _fill_gencost_poly(ppci, net, is_quadratic, q_costs):
gens, cost, signs = _map_costs_to_gen(net, net.poly_cost)
c0 = cost["cp0_eur"].values
c1 = cost["cp1_eur_per_mw"].values
signs = array([-1 if element in ["load", "storage", "dcline"] else 1 for element in cost.et])
if is_quadratic:
c2 = cost["cp2_eur_per_mw2"]
ppci["gencost"][gens, NCOST] = 3
ppci["gencost"][gens, COST] = c2 * signs
ppci["gencost"][gens, COST] = c2
ppci["gencost"][gens, COST + 1] = c1 * signs
ppci["gencost"][gens, COST + 2] = c0 * signs
ppci["gencost"][gens, COST + 2] = c0
else:
ppci["gencost"][gens, NCOST] = 2
ppci["gencost"][gens, COST] = c1 * signs
ppci["gencost"][gens, COST + 1] = c0 * signs
ppci["gencost"][gens, COST + 1] = c0
if q_costs:
gens_q = gens + len(ppci["gen"])
c0 = cost["cq0_eur"].values
Expand Down
61 changes: 61 additions & 0 deletions pandapower/test/opf/test_costs_pol.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,33 @@
# Copyright (c) 2016-2026 by University of Kassel and Fraunhofer Institute for Energy Economics
# and Energy System Technology (IEE), Kassel. All rights reserved.

from copy import deepcopy

import numpy as np
import pytest

from pandapower.create import create_empty_network, create_bus, create_gen, create_ext_grid, create_load, \
create_line_from_parameters, create_poly_cost, create_sgen
from pandapower.converter.pypower import to_ppc
from pandapower.pypower.idx_cost import COST, NCOST
from pandapower.run import runopp
from pandapower.test.opf.test_basic import simple_opf_test_net

import logging


def _add_controllable_load_and_sgen_costs(net):
load = create_load(net, 1, p_mw=0.5, q_mvar=0.1, controllable=True,
min_p_mw=0.1, max_p_mw=1.0, min_q_mvar=-0.5, max_q_mvar=0.5)
sgen = create_sgen(net, 1, p_mw=0.5, q_mvar=0.1, controllable=True,
min_p_mw=0.1, max_p_mw=1.0, min_q_mvar=-0.5, max_q_mvar=0.5)

create_poly_cost(net, load, "load", cp0_eur=3, cp1_eur_per_mw=1, cp2_eur_per_mw2=2)
create_poly_cost(net, sgen, "sgen", cp0_eur=30, cp1_eur_per_mw=10, cp2_eur_per_mw2=20)

return load, sgen


def test_cost_pol_gen():
""" Testing a very simple network for the resulting cost value
constraints with OPF """
Expand Down Expand Up @@ -86,6 +103,50 @@ def test_cost_pol_all_elements():
assert np.isclose(net.res_cost, net.res_gen.p_mw.values ** 2 + net.res_sgen.p_mw.values)


def test_controllable_load_polynomial_cost_signs(simple_opf_test_net):
"""Controllable loads use the opposite active-power sign in PYPOWER."""
net = deepcopy(simple_opf_test_net)
load, sgen = _add_controllable_load_and_sgen_costs(net)
ppci = to_ppc(net, mode="opf", init="flat", calculate_voltage_angles=False)
load_gen = net._pd2ppc_lookups["load_controllable"][load]
sgen_gen = net._pd2ppc_lookups["sgen_controllable"][sgen]

assert ppci["gencost"][load_gen, NCOST] == 3
assert ppci["gencost"][sgen_gen, NCOST] == 3
assert np.allclose(ppci["gencost"][load_gen, COST:COST + 3], [2, -1, 3])
assert np.allclose(ppci["gencost"][sgen_gen, COST:COST + 3], [20, 10, 30])

net.poly_cost.loc[:, "cp2_eur_per_mw2"] = 0
ppci = to_ppc(net, mode="opf", init="flat", calculate_voltage_angles=False)

assert ppci["gencost"][load_gen, NCOST] == 2
assert ppci["gencost"][sgen_gen, NCOST] == 2
assert np.allclose(ppci["gencost"][load_gen, COST:COST + 2], [-1, 3])
assert np.allclose(ppci["gencost"][sgen_gen, COST:COST + 2], [10, 30])


def test_controllable_load_reactive_polynomial_cost_signs(simple_opf_test_net):
"""Reactive cost rows keep the existing PYPOWER q-cost sign convention."""
net = deepcopy(simple_opf_test_net)
load, sgen = _add_controllable_load_and_sgen_costs(net)

load_cost = (net.poly_cost.et == "load") & (net.poly_cost.element == load)
sgen_cost = (net.poly_cost.et == "sgen") & (net.poly_cost.element == sgen)
net.poly_cost.loc[load_cost, ["cq0_eur", "cq1_eur_per_mvar", "cq2_eur_per_mvar2"]] = [5, 4, 6]
net.poly_cost.loc[sgen_cost, ["cq0_eur", "cq1_eur_per_mvar", "cq2_eur_per_mvar2"]] = [50, 40, 60]

ppci = to_ppc(net, mode="opf", init="flat", calculate_voltage_angles=False)
load_gen = net._pd2ppc_lookups["load_controllable"][load]
sgen_gen = net._pd2ppc_lookups["sgen_controllable"][sgen]
load_q_gen = load_gen + len(ppci["gen"])
sgen_q_gen = sgen_gen + len(ppci["gen"])

assert ppci["gencost"][load_q_gen, NCOST] == 3
assert ppci["gencost"][sgen_q_gen, NCOST] == 3
assert np.allclose(ppci["gencost"][load_q_gen, COST:COST + 3], [-6, -4, -5])
assert np.allclose(ppci["gencost"][sgen_q_gen, COST:COST + 3], [60, 40, 50])


def test_cost_pol_q():
""" Testing a very simple network for the resulting cost value
constraints with OPF """
Expand Down
12 changes: 12 additions & 0 deletions pandapower/test/opf/test_pandamodels_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from pandapower.pd2ppc import _pd2ppc
from pandapower.run import runopp
from pandapower.test.opf.test_basic import simple_opf_test_net, net_3w_trafo_opf
from pandapower.test.opf.test_costs_pol import _add_controllable_load_and_sgen_costs

try:
from juliacall import JuliaError as UnsupportedPythonError # type: ignore
Expand Down Expand Up @@ -72,5 +73,16 @@ def test_obj_factors(net_3w_trafo_opf):
assert pm["user_defined_params"]["gen_and_controllable_sgen"]["3"] == 3


def test_controllable_load_polynomial_cost_signs_for_powermodels(simple_opf_test_net):
net = deepcopy(simple_opf_test_net)
load, sgen = _add_controllable_load_and_sgen_costs(net)
pm = convert_pp_to_pm(net)
load_gen = net._pd2ppc_lookups["load_controllable"][load] + 1
sgen_gen = net._pd2ppc_lookups["sgen_controllable"][sgen] + 1

assert pm["gen"][str(load_gen)]["cost"] == [2, -1, 3]
assert pm["gen"][str(sgen_gen)]["cost"] == [20, 10, 30]


if __name__ == '__main__':
pytest.main([__file__, "-xs"])
Loading