From 312fc4f68e7e77664e26e84dad217372eac02a5a Mon Sep 17 00:00:00 2001 From: Damien Jeandemange Date: Wed, 20 Nov 2024 18:53:01 +0100 Subject: [PATCH 1/4] Fix non-linear shunt compensator section number Signed-off-by: Damien Jeandemange --- .../dataframe/network/NetworkDataframes.java | 6 +++-- tests/test_network.py | 24 +++++++++---------- tests/test_network_elements_creation.py | 8 +++---- tests/test_network_modification.py | 16 ++++++------- 4 files changed, 28 insertions(+), 26 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 eb5c245144..36c640d7cd 100644 --- a/java/src/main/java/com/powsybl/dataframe/network/NetworkDataframes.java +++ b/java/src/main/java/com/powsybl/dataframe/network/NetworkDataframes.java @@ -423,7 +423,8 @@ 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 + return model.getAllSections().stream().map(section -> Triple.of(shuntCompensator, section, model.getAllSections().indexOf(section) + 1)); }); return NetworkDataframeMapperBuilder.ofStream(nonLinearShunts, NetworkDataframes::getShuntSectionNonlinear) .stringsIndex("id", triple -> triple.getLeft().getId()) @@ -443,7 +444,8 @@ 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 + return Triple.of(shuntCompensator, shuntNonLinear.getAllSections().get(section - 1), section); } } diff --git a/tests/test_network.py b/tests/test_network.py index 31151db378..114c1cb01e 100644 --- a/tests/test_network.py +++ b/tests/test_network.py @@ -1413,24 +1413,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(): @@ -1461,9 +1461,9 @@ def test_voltage_levels(): def test_update_with_keywords(): 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'] + n.update_non_linear_shunt_compensator_sections(id='SHUNT', section=1, g=0.2, b=0.000001) + assert 0.2 == n.get_non_linear_shunt_compensator_sections().loc['SHUNT', 1]['g'] + assert 0.000001 == n.get_non_linear_shunt_compensator_sections().loc['SHUNT', 1]['b'] 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 From 903298b91127f8b3f61a6b637266ba2b07d9d7af Mon Sep 17 00:00:00 2001 From: Damien Jeandemange Date: Thu, 21 Nov 2024 10:24:29 +0100 Subject: [PATCH 2/4] better error handling Signed-off-by: Damien Jeandemange --- .../dataframe/network/NetworkDataframes.java | 6 +++++- tests/test_network.py | 20 ++++++++++++++++--- 2 files changed, 22 insertions(+), 4 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 36c640d7cd..b614c61263 100644 --- a/java/src/main/java/com/powsybl/dataframe/network/NetworkDataframes.java +++ b/java/src/main/java/com/powsybl/dataframe/network/NetworkDataframes.java @@ -445,7 +445,11 @@ static Triple int section = dataframe.getIntValue("section", index) .orElseThrow(() -> new PowsyblException("section is missing")); // careful: shunt section number starts at 1, but position in array starts at 0 - return Triple.of(shuntCompensator, shuntNonLinear.getAllSections().get(section - 1), section); + 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 114c1cb01e..a4cc64a303 100644 --- a/tests/test_network.py +++ b/tests/test_network.py @@ -1459,11 +1459,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) - assert 0.2 == n.get_non_linear_shunt_compensator_sections().loc['SHUNT', 1]['g'] - assert 0.000001 == n.get_non_linear_shunt_compensator_sections().loc['SHUNT', 1]['b'] + 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() + 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(): From a47d755355e9be75ff6cf33859b34c3b8902bfe3 Mon Sep 17 00:00:00 2001 From: jeandemanged Date: Fri, 22 Nov 2024 14:38:54 +0100 Subject: [PATCH 3/4] avoid the linear search for getting an index for each of the section Co-authored-by: Geoffroy Jamgotchian Signed-off-by: jeandemanged --- .../java/com/powsybl/dataframe/network/NetworkDataframes.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 2266e14051..d837320dc8 100644 --- a/java/src/main/java/com/powsybl/dataframe/network/NetworkDataframes.java +++ b/java/src/main/java/com/powsybl/dataframe/network/NetworkDataframes.java @@ -438,7 +438,8 @@ static NetworkDataframeMapper shuntsNonLinear() { .flatMap(shuntCompensator -> { ShuntCompensatorNonLinearModel model = (ShuntCompensatorNonLinearModel) shuntCompensator.getModel(); // careful: shunt section number starts at 1, but position in array starts at 0 - return model.getAllSections().stream().map(section -> Triple.of(shuntCompensator, section, model.getAllSections().indexOf(section) + 1)); + 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()) From 1d2297e83dd361b0a29a7a0e7bc4d54cb38c3f39 Mon Sep 17 00:00:00 2001 From: Damien Jeandemange Date: Fri, 22 Nov 2024 14:42:38 +0100 Subject: [PATCH 4/4] fix Signed-off-by: Damien Jeandemange --- .../java/com/powsybl/dataframe/network/NetworkDataframes.java | 1 + 1 file changed, 1 insertion(+) 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 d837320dc8..b9370e3d82 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.*;