From 9f5c0be72b54346559209590e4c366b17aac507c Mon Sep 17 00:00:00 2001 From: jeandemanged Date: Wed, 11 Dec 2024 10:21:30 +0100 Subject: [PATCH] Fix non-linear shunt compensator section number (#900) Signed-off-by: Damien Jeandemange --- .../dataframe/network/NetworkDataframes.java | 12 +++++- tests/test_network.py | 40 +++++++++++++------ tests/test_network_elements_creation.py | 8 ++-- tests/test_network_modification.py | 16 ++++---- 4 files changed, 49 insertions(+), 27 deletions(-) diff --git a/java/src/main/java/com/powsybl/dataframe/network/NetworkDataframes.java b/java/src/main/java/com/powsybl/dataframe/network/NetworkDataframes.java index a49ba4d650..8519b6555f 100644 --- a/java/src/main/java/com/powsybl/dataframe/network/NetworkDataframes.java +++ b/java/src/main/java/com/powsybl/dataframe/network/NetworkDataframes.java @@ -24,6 +24,7 @@ import java.util.*; import java.util.function.*; +import java.util.stream.IntStream; import java.util.stream.Stream; import static com.powsybl.dataframe.MappingUtils.*; @@ -437,7 +438,9 @@ static NetworkDataframeMapper shuntsNonLinear() { .filter(sc -> sc.getModelType() == ShuntCompensatorModelType.NON_LINEAR) .flatMap(shuntCompensator -> { ShuntCompensatorNonLinearModel model = (ShuntCompensatorNonLinearModel) shuntCompensator.getModel(); - return model.getAllSections().stream().map(section -> Triple.of(shuntCompensator, section, model.getAllSections().indexOf(section))); + // careful: shunt section number starts at 1, but position in array starts at 0 + var allSections = model.getAllSections(); + return IntStream.range(0, allSections.size()).mapToObj(i -> Triple.of(shuntCompensator, allSections.get(i), i + 1)); }); return NetworkDataframeMapperBuilder.ofStream(nonLinearShunts, NetworkDataframes::getShuntSectionNonlinear) .stringsIndex("id", triple -> triple.getLeft().getId()) @@ -457,7 +460,12 @@ static Triple } else { int section = dataframe.getIntValue("section", index) .orElseThrow(() -> new PowsyblException("section is missing")); - return Triple.of(shuntCompensator, shuntNonLinear.getAllSections().get(section), section); + // careful: shunt section number starts at 1, but position in array starts at 0 + List allSections = shuntNonLinear.getAllSections(); + if (section < 1 || section > allSections.size()) { + throw new PowsyblException(String.format("Section number must be between 1 and %d, inclusive", allSections.size())); + } + return Triple.of(shuntCompensator, allSections.get(section - 1), section); } } diff --git a/tests/test_network.py b/tests/test_network.py index ffa99136f4..2744e26a1f 100644 --- a/tests/test_network.py +++ b/tests/test_network.py @@ -1423,24 +1423,24 @@ def test_busbar_sections(): def test_non_linear_shunt(): n = util.create_non_linear_shunt_network() non_linear_shunt_sections = n.get_non_linear_shunt_compensator_sections() - pd.testing.assert_series_equal(non_linear_shunt_sections.loc[('SHUNT', 0)], - pd.Series(data={'g': 0.0, 'b': 0.00001}, - name=('SHUNT', 0)), check_dtype=False) pd.testing.assert_series_equal(non_linear_shunt_sections.loc[('SHUNT', 1)], - pd.Series(data={'g': 0.3, 'b': 0.0200}, + pd.Series(data={'g': 0.0, 'b': 0.00001}, name=('SHUNT', 1)), check_dtype=False) - update = pd.DataFrame(index=pd.MultiIndex.from_tuples([('SHUNT', 0), ('SHUNT', 1)], names=['id', 'section']), + pd.testing.assert_series_equal(non_linear_shunt_sections.loc[('SHUNT', 2)], + pd.Series(data={'g': 0.3, 'b': 0.0200}, + name=('SHUNT', 2)), check_dtype=False) + update = pd.DataFrame(index=pd.MultiIndex.from_tuples([('SHUNT', 1), ('SHUNT', 2)], names=['id', 'section']), columns=['g', 'b'], data=[[0.1, 0.00002], [0.4, 0.03]]) n.update_non_linear_shunt_compensator_sections(update) non_linear_shunt_sections = n.get_non_linear_shunt_compensator_sections() - pd.testing.assert_series_equal(non_linear_shunt_sections.loc[('SHUNT', 0)], - pd.Series(data={'g': 0.1, 'b': 0.00002}, - name=('SHUNT', 0)), check_dtype=False) pd.testing.assert_series_equal(non_linear_shunt_sections.loc[('SHUNT', 1)], - pd.Series(data={'g': 0.4, 'b': 0.03}, + pd.Series(data={'g': 0.1, 'b': 0.00002}, name=('SHUNT', 1)), check_dtype=False) + pd.testing.assert_series_equal(non_linear_shunt_sections.loc[('SHUNT', 2)], + pd.Series(data={'g': 0.4, 'b': 0.03}, + name=('SHUNT', 2)), check_dtype=False) def test_voltage_levels(): @@ -1469,11 +1469,25 @@ def test_voltage_levels(): pd.testing.assert_frame_equal(expected, n.get_voltage_levels(), check_dtype=False) -def test_update_with_keywords(): +def test_update_non_linear_shunt_with_keywords(): + n = util.create_non_linear_shunt_network() + n.update_non_linear_shunt_compensator_sections(id='SHUNT', section=1, g=0.2, b=0.000001) + n.update_non_linear_shunt_compensator_sections(id='SHUNT', section=2, g=0.3, b=0.000002) + sections = n.get_non_linear_shunt_compensator_sections() + assert 0.2 == sections.loc['SHUNT', 1]['g'] + assert 0.000001 == sections.loc['SHUNT', 1]['b'] + assert 0.3 == sections.loc['SHUNT', 2]['g'] + assert 0.000002 == sections.loc['SHUNT', 2]['b'] + + +def test_update_non_linear_shunt_wrong_section(): n = util.create_non_linear_shunt_network() - n.update_non_linear_shunt_compensator_sections(id='SHUNT', section=0, g=0.2, b=0.000001) - assert 0.2 == n.get_non_linear_shunt_compensator_sections().loc['SHUNT', 0]['g'] - assert 0.000001 == n.get_non_linear_shunt_compensator_sections().loc['SHUNT', 0]['b'] + with pytest.raises(PyPowsyblError) as exc: + n.update_non_linear_shunt_compensator_sections(id='SHUNT', section=0, g=0.2, b=0.000001) + assert exc.match('Section number must be between 1 and 2, inclusive') + with pytest.raises(PyPowsyblError) as exc: + n.update_non_linear_shunt_compensator_sections(id='SHUNT', section=3, g=0.2, b=0.000001) + assert exc.match('Section number must be between 1 and 2, inclusive') def test_update_generators_with_keywords(): diff --git a/tests/test_network_elements_creation.py b/tests/test_network_elements_creation.py index 8a84984895..8396c3a1a5 100644 --- a/tests/test_network_elements_creation.py +++ b/tests/test_network_elements_creation.py @@ -446,16 +446,16 @@ def test_non_linear_shunt(): assert shunt.b == 2 model1 = n.get_non_linear_shunt_compensator_sections().loc['SHUNT1'] - section1 = model1.loc[0] - section2 = model1.loc[1] + section1 = model1.loc[1] + section2 = model1.loc[2] assert section1.g == 1 assert section1.b == 2 assert section2.g == 3 assert section2.b == 4 model2 = n.get_non_linear_shunt_compensator_sections().loc['SHUNT2'] - section1 = model2.loc[0] - section2 = model2.loc[1] + section1 = model2.loc[1] + section2 = model2.loc[2] assert section1.g == 5 assert section1.b == 6 assert section2.g == 7 diff --git a/tests/test_network_modification.py b/tests/test_network_modification.py index b466c157b3..80d306537e 100644 --- a/tests/test_network_modification.py +++ b/tests/test_network_modification.py @@ -527,16 +527,16 @@ def test_add_non_linear_shunt_bay(): assert shunt.b == 2 model1 = n.get_non_linear_shunt_compensator_sections().loc['shunt1'] - section1 = model1.loc[0] - section2 = model1.loc[1] + section1 = model1.loc[1] + section2 = model1.loc[2] assert section1.g == 1 assert section1.b == 2 assert section2.g == 3 assert section2.b == 4 model2 = n.get_non_linear_shunt_compensator_sections().loc['shunt2'] - section1 = model2.loc[0] - section2 = model2.loc[1] + section1 = model2.loc[1] + section2 = model2.loc[2] assert section1.g == 5 assert section1.b == 6 assert section2.g == 7 @@ -581,16 +581,16 @@ def test_add_non_linear_shunt_bay_bus_breaker(): assert shunt.b == 2 model1 = n.get_non_linear_shunt_compensator_sections().loc['shunt1'] - section1 = model1.loc[0] - section2 = model1.loc[1] + section1 = model1.loc[1] + section2 = model1.loc[2] assert section1.g == 1 assert section1.b == 2 assert section2.g == 3 assert section2.b == 4 model2 = n.get_non_linear_shunt_compensator_sections().loc['shunt2'] - section1 = model2.loc[0] - section2 = model2.loc[1] + section1 = model2.loc[1] + section2 = model2.loc[2] assert section1.g == 5 assert section1.b == 6 assert section2.g == 7