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
3 changes: 2 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Change Log

[upcoming release] - 2026-..-..
-------------------------------
- [ADDED] set_opf_controllable parameter in from_mpc to mark converted external grids and generators as controllable
- [ADDED] OpenDSS converter: series (bus-to-bus) ``Reactor`` elements are now imported as a fixed-impedance ``line``, the pattern some feeder libraries (e.g. EPRI's Ckt5/Ckt7) use to model the substation's Thevenin-equivalent source impedance instead of a ``Transformer``.

[3.5.4] - 2026-07-08
Expand Down Expand Up @@ -194,7 +195,7 @@ Change Log
- [FIXED] DC OPF bug if verbose = True
- [CHANGED] cim2pp conversion of SVC parameter active power: p is set to 0, instead of using the p-value from the SV-profile
- [ADDED] Parellel contingency analysis using multiple cores through a multiprocessing worker pool
- [Changed] DC-line mode to handle negative values in 2 different ways, inversing the line direction or considering powerflow always to correlate with the given from_bus
- [Changed] DC-line mode to handle negative values in 2 different ways, inversing the line direction or considering powerflow always to correlate with the given from_bus
- [FIXED] type annotations in create methods
- [CHANGED] drop_inactive_elements performance improvements: using pandas methods instead of looping
- [ADDED] add a few more tests for the grid modification functions
Expand Down
8 changes: 7 additions & 1 deletion pandapower/converter/matpower/from_mpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def from_mpc(
casename_mpc_file='mpc',
validate_conversion=False,
load_case_engine=None,
set_opf_controllable=False,
**kwargs,
):
"""
Expand All @@ -50,6 +51,7 @@ def from_mpc(
load_case_engine (object, None): External engine used to call MATPOWER `loadcase` (e.g. Oct2Py() object from
matpower.start_instance()). Defaults to None. If None, parse data using
matpowercaseframes.reader.parse_file.
set_opf_controllable (bool, False): If True, marks converted ``ext_grid`` and ``gen`` elements as controllable in the pandapower network. This is needed for correct conversion for OPF purposes, as MATPOWER cannot imply controllability directly for gen types.

Keyword Arguments:
any: are passed to :func:`from_ppc`
Expand All @@ -68,12 +70,16 @@ def from_mpc(
elif ending == ".m":
ppc = _m2ppc(mpc_file, load_case_engine=load_case_engine)
net = from_ppc(ppc, f_hz=f_hz, validate_conversion=validate_conversion, **kwargs)
if set_opf_controllable:
if len(net.ext_grid) > 0:
net.ext_grid["controllable"] = True
if len(net.gen) > 0:
net.gen["controllable"] = True
if "mpc_additional_data" in ppc:
if "_options" not in net:
net["_options"] = {}
net._options.update(ppc["mpc_additional_data"])
logger.info('added fields %s in net._options' % list(ppc["mpc_additional_data"].keys()))

return net


Expand Down
1 change: 0 additions & 1 deletion pandapower/converter/pypower/from_ppc.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ def from_ppc(ppc, f_hz=50, validate_conversion=False, **kwargs) -> pandapowerNet
logger.setLevel(logging.DEBUG)
if not validate_from_ppc(ppc, net, **kwargs):
logger.error("Validation failed.")

return net


Expand Down
21 changes: 21 additions & 0 deletions pandapower/test/converter/test_from_mpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,27 @@ def test_from_mpc_m():
assert case24_m.converged
assert nets_equal(case24_mat, case24_m)

@pytest.mark.skipif(not matpowercaseframes_imported,
reason="matpowercaseframes is needed to convert .m files.")
def test_from_mpc_opf_controllable():
this_folder = os.path.join(pp_dir, "test", "converter")
mat_case = os.path.join(this_folder, 'case24_ieee_rts.mat')
mat_net = from_mpc(
str(mat_case),
validate_conversion=False,
set_opf_controllable=True,
)
assert mat_net.ext_grid["controllable"].all()
assert mat_net.gen["controllable"].all()

m_case = os.path.join(this_folder, 'case24_ieee_rts.m')
m_net = from_mpc(
str(m_case),
validate_conversion=False,
set_opf_controllable=True,
)
assert m_net.ext_grid["controllable"].all()
assert m_net.gen["controllable"].all()

if __name__ == '__main__':
pytest.main([__file__, "-xs"])
36 changes: 36 additions & 0 deletions pandapower/test/converter/test_from_ppc_opf_controllable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import numpy as np

from pandapower.converter.pypower import from_ppc

def test_from_ppc_opf_controllable():
ppc = {
"version": "2",
"baseMVA": 100.0,
"bus": np.array(
[
[0, 3, 0, 0, 0, 0, 1, 1.0, 0.0, 110.0, 1, 1.1, 0.9],
[1, 2, 0, 0, 0, 0, 1, 1.0, 0.0, 110.0, 1, 1.1, 0.9],
],
dtype=float,
),
"branch": np.array(
[
[0, 1, 0.01, 0.05, 0, 100, 100, 100, 0, 0, 1, -30, 30],
],
dtype=float,
),
"gen": np.array(
[
[0, 50, 0, 100, -100, 1.0, 100, 1, 100, 0],
[1, 20, 0, 100, -100, 1.0, 100, 1, 100, 0],
],
dtype=float,
),
}

net = from_ppc(ppc, validate_conversion=False, set_opf_controllable=True)

assert len(net.ext_grid) == 1
assert len(net.gen) == 1
assert net.ext_grid["controllable"].all()
assert net.gen["controllable"].all()
Loading