From 6d2e8366d5a5d23339777809539875eeea03ef4c Mon Sep 17 00:00:00 2001 From: BOUTIER Charly Date: Tue, 8 Apr 2025 15:29:43 +0200 Subject: [PATCH 1/6] Upgrade to powsybl-dependencies v2025.0.0 Signed-off-by: BOUTIER Charly --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f351f68c..0ab57006 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ 1.0 - 2.20.0 + 2.21.0-SNAPSHOT From d64659ecb2a274595214f95dab7d5826521d4f31 Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Wed, 16 Apr 2025 14:18:34 +0200 Subject: [PATCH 2/6] implement area and battery short circuit and adapt to network store upgrade Signed-off-by: Etienne LESOT --- .../com/powsybl/network/store/tck/AreaIt.java | 60 +++ .../integration/NetworkStoreExtensionsIT.java | 138 ++++--- .../store/integration/NetworkStoreIT.java | 12 +- .../store/server/ExternalAttributesType.java | 3 +- .../network/store/server/Mappings.java | 35 +- .../store/server/NetworkStoreController.java | 62 +++- .../store/server/NetworkStoreRepository.java | 351 ++++++++++++++++-- .../network/store/server/QueryCatalog.java | 65 ++++ .../changesets/changelog_20250415T064500Z.xml | 53 +++ .../db/changelog/db.changelog-master.yaml | 3 + pom.xml | 36 +- 11 files changed, 720 insertions(+), 98 deletions(-) create mode 100644 network-store-iidm-tck/src/test/java/com/powsybl/network/store/tck/AreaIt.java create mode 100644 network-store-server/src/main/resources/db/changelog/changesets/changelog_20250415T064500Z.xml diff --git a/network-store-iidm-tck/src/test/java/com/powsybl/network/store/tck/AreaIt.java b/network-store-iidm-tck/src/test/java/com/powsybl/network/store/tck/AreaIt.java new file mode 100644 index 00000000..7e4edebe --- /dev/null +++ b/network-store-iidm-tck/src/test/java/com/powsybl/network/store/tck/AreaIt.java @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2025, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package com.powsybl.network.store.tck; + +import com.powsybl.iidm.network.tck.AbstractAreaTest; +import com.powsybl.network.store.server.NetworkStoreApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.ContextHierarchy; + +/** + * @author Etienne Lesot + */ +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, properties = {"spring.config.location=classpath:application.yaml"}) +@ContextHierarchy({@ContextConfiguration(classes = {NetworkStoreApplication.class})}) +public class AreaIt extends AbstractAreaTest { + @Override + public void mergeAndFlatten() { + // merge is not implemented + } + + @Override + public void throwAddVoltageLevelOtherNetwork() { + // problem + } + + @Override + public void removeArea() { + // removed equipments is managed differently in powsybl core implementation + } + + @Override + public void throwRemovedVoltageLevel() { + // removed equipments is managed differently in powsybl core implementation + } + + @Override + public void testGetAreaBoundary() { + // problem with removal + } + + @Override + public void testSetterGetterInMultiVariants() { + // problem with removal + } + + @Override + public void throwBoundaryOtherNetwork() { + // creation of subnetwork needed + } + + @Override + public void removeEquipmentRemovesAreaBoundaryMergeAndDetach() { + // merge is not implemented + } +} diff --git a/network-store-integration-test/src/test/java/com/powsybl/network/store/integration/NetworkStoreExtensionsIT.java b/network-store-integration-test/src/test/java/com/powsybl/network/store/integration/NetworkStoreExtensionsIT.java index 6862a100..cf093d0b 100644 --- a/network-store-integration-test/src/test/java/com/powsybl/network/store/integration/NetworkStoreExtensionsIT.java +++ b/network-store-integration-test/src/test/java/com/powsybl/network/store/integration/NetworkStoreExtensionsIT.java @@ -11,6 +11,7 @@ import com.powsybl.cgmes.conversion.CgmesImport; import com.powsybl.cgmes.extensions.*; import com.powsybl.cgmes.model.CgmesMetadataModel; +import com.powsybl.cgmes.model.CgmesNames; import com.powsybl.cgmes.model.CgmesSubset; import com.powsybl.commons.PowsyblException; import com.powsybl.commons.datasource.ReadOnlyDataSource; @@ -121,7 +122,7 @@ void testGeneratorShortCircuit() { assertNull(gen.getExtensionByName(GeneratorShortCircuit.NAME)); assertTrue(gen.getExtensions().isEmpty()); GeneratorShortCircuitAdder circuitAdder = gen.newExtension(GeneratorShortCircuitAdder.class).withDirectTransX(Double.NaN); - assertThrows(PowsyblException.class, () -> circuitAdder.add()); + assertThrows(PowsyblException.class, circuitAdder::add); circuitAdder.withDirectSubtransX(20.) .withDirectTransX(30.) .withStepUpTransformerX(50.) @@ -150,6 +151,44 @@ void testGeneratorShortCircuit() { } } + @Test + void testBatteryShortCircuit() { + try (NetworkStoreService service = createNetworkStoreService(randomServerPort)) { + Network network = BatteryNetworkFactory.create(service.getNetworkFactory()); + Battery bat = network.getBattery("BAT"); + assertNull(bat.getExtension(BatteryShortCircuit.class)); + assertNull(bat.getExtensionByName(BatteryShortCircuit.NAME)); + assertTrue(bat.getExtensions().isEmpty()); + BatteryShortCircuitAdder circuitAdder = bat.newExtension(BatteryShortCircuitAdder.class).withDirectTransX(Double.NaN); + assertThrows(PowsyblException.class, circuitAdder::add); + circuitAdder.withDirectSubtransX(20.) + .withDirectTransX(30.) + .withStepUpTransformerX(50.) + .add(); + service.flush(network); + } + + try (NetworkStoreService service = createNetworkStoreService(randomServerPort)) { + Network network = service.getNetwork(service.getNetworkIds().keySet().iterator().next()); + Battery bat = network.getBattery("BAT"); + BatteryShortCircuit batteryShortCircuit = bat.getExtension(BatteryShortCircuit.class); + assertNotNull(batteryShortCircuit); + assertEquals(20., batteryShortCircuit.getDirectSubtransX(), 0); + assertEquals(30., batteryShortCircuit.getDirectTransX(), 0); + assertEquals(50., batteryShortCircuit.getStepUpTransformerX(), 0); + assertNotNull(bat.getExtensionByName(BatteryShortCircuit.NAME)); + assertEquals(BatteryShortCircuit.NAME, batteryShortCircuit.getName()); + + assertThrows(PowsyblException.class, () -> batteryShortCircuit.setDirectTransX(Double.NaN)); + batteryShortCircuit.setDirectSubtransX(23.); + batteryShortCircuit.setDirectTransX(32.); + batteryShortCircuit.setStepUpTransformerX(44.); + assertEquals(23., batteryShortCircuit.getDirectSubtransX(), 0); + assertEquals(32., batteryShortCircuit.getDirectTransX(), 0); + assertEquals(44., batteryShortCircuit.getStepUpTransformerX(), 0); + } + } + @Test void testIdentifiableShortCircuit() { try (NetworkStoreService service = createNetworkStoreService(randomServerPort)) { @@ -289,7 +328,8 @@ void cgmesExtensionsTest() { .cgmesTopologyKind(CgmesTopologyKind.BUS_BRANCH) .build(); - ((NetworkImpl) readNetwork).updateResource(res -> res.getAttributes().setCimCharacteristics(cimCharacteristicsAttributes)); + ((NetworkImpl) readNetwork).updateResourceWithoutNotification(res -> + res.getAttributes().setCimCharacteristics(cimCharacteristicsAttributes)); service.flush(readNetwork); } @@ -1023,9 +1063,10 @@ void cgmesControlAreaDanglingLineTest() { try (NetworkStoreService service = createNetworkStoreService(randomServerPort)) { // import new network in the store Network network = service.importNetwork(CgmesConformity1Catalog.microGridBaseCaseBE().dataSource()); - CgmesControlAreas cgmesControlAreas = network.getExtension(CgmesControlAreas.class); - assertNotNull(cgmesControlAreas); - assertEquals(0, cgmesControlAreas.getCgmesControlAreas().size()); + Area cgmesControlAreas = network.getArea("ca1"); + assertNull(cgmesControlAreas); + List areas = network.getAreaStream().toList(); + assertEquals(0, areas.size()); } try (NetworkStoreService service = createNetworkStoreService(randomServerPort)) { @@ -1034,20 +1075,29 @@ void cgmesControlAreaDanglingLineTest() { UUID networkUuid = networkIds.keySet().iterator().next(); Network network = service.getNetwork(networkUuid); - CgmesControlAreas cgmesControlAreas = network.getExtension(CgmesControlAreas.class); - assertNotNull(cgmesControlAreas); - assertEquals(0, cgmesControlAreas.getCgmesControlAreas().size()); - CgmesControlArea cgmesControlArea = cgmesControlAreas.newCgmesControlArea() + assertEquals(0, network.getAreaStream().toList().size()); + Area cgmesControlArea = network.newArea() .setId("ca1") - .setEnergyIdentificationCodeEic("code") - .setNetInterchange(1000) + .setInterchangeTarget(1000) .add(); - cgmesControlArea.add(network.getGenerator("550ebe0d-f2b2-48c1-991f-cebea43a21aa").getTerminal()); - cgmesControlArea.add(network.getDanglingLine("a16b4a6c-70b1-4abf-9a9d-bd0fa47f9fe4").getBoundary()); - assertEquals(1, cgmesControlAreas.getCgmesControlAreas().size()); - CgmesControlArea ca1 = cgmesControlAreas.getCgmesControlArea("ca1"); + cgmesControlArea.addAlias("code", CgmesNames.ENERGY_IDENT_CODE_EIC); + cgmesControlArea.newAreaBoundary() + .setTerminal(network.getGenerator("550ebe0d-f2b2-48c1-991f-cebea43a21aa").getTerminal()) + .setAc(true) + .add(); + cgmesControlArea.newAreaBoundary() + .setBoundary(network.getDanglingLine("a16b4a6c-70b1-4abf-9a9d-bd0fa47f9fe4").getBoundary()) + .setAc(true) + .add(); + assertEquals(2, cgmesControlArea.getAreaBoundaryStream().toList().size()); + assertEquals(1, network.getAreaStream().toList().size()); + Area ca1 = network.getArea("ca1"); assertNotNull(ca1); - + assertEquals(2, ca1.getAreaBoundaryStream().toList().size()); + assertEquals(-91.19499400000001, ca1.getAcInterchange()); + assertEquals(0, ca1.getDcInterchange()); + assertEquals("code", ca1.getAliasFromType(CgmesNames.ENERGY_IDENT_CODE_EIC) + .orElse(null)); service.flush(network); } @@ -1057,17 +1107,13 @@ void cgmesControlAreaDanglingLineTest() { UUID networkUuid = networkIds.keySet().iterator().next(); Network network = service.getNetwork(networkUuid); - CgmesControlAreas cgmesControlAreas = network.getExtension(CgmesControlAreas.class); - assertNotNull(cgmesControlAreas); - assertEquals(1, cgmesControlAreas.getCgmesControlAreas().size()); - assertTrue(cgmesControlAreas.containsCgmesControlAreaId("ca1")); - CgmesControlArea cgmesControlArea = cgmesControlAreas.getCgmesControlArea("ca1"); + Area cgmesControlArea = network.getArea("ca1"); + assertNotNull(cgmesControlArea); + assertEquals(1, network.getAreaStream().toList().size()); assertEquals("ca1", cgmesControlArea.getId()); - assertNull(cgmesControlArea.getName()); - assertEquals("code", cgmesControlArea.getEnergyIdentificationCodeEIC()); - assertEquals(1000, cgmesControlArea.getNetInterchange(), 0); - assertEquals(1, cgmesControlArea.getTerminals().size()); - assertEquals(1, cgmesControlArea.getBoundaries().size()); + assertTrue(cgmesControlArea.getOptionalName().isEmpty()); + assertTrue(cgmesControlArea.getInterchangeTarget().isPresent()); + assertEquals(1000, cgmesControlArea.getInterchangeTarget().getAsDouble()); } } @@ -1142,19 +1188,23 @@ void cgmesControlAreaTieLineTest() { UUID networkUuid = networkIds.keySet().iterator().next(); Network network = service.getNetwork(networkUuid); - CgmesControlAreas cgmesControlAreas = network.getExtension(CgmesControlAreas.class); - assertNotNull(cgmesControlAreas); - - assertNotNull(cgmesControlAreas); - assertEquals(0, cgmesControlAreas.getCgmesControlAreas().size()); - CgmesControlArea cgmesControlArea = cgmesControlAreas.newCgmesControlArea() + assertEquals(0, network.getAreaStream().toList().size()); + Area cgmesControlArea = network.newArea() .setId("ca2") - .setEnergyIdentificationCodeEic("code2") - .setNetInterchange(800) + .setInterchangeTarget(800) + .addAreaBoundary(network.getTieLine("b18cd1aa-7808-49b9-a7cf-605eaf07b006 + e8acf6b6-99cb-45ad-b8dc-16c7866a4ddc").getDanglingLine1().getBoundary(), + true) .add(); - cgmesControlArea.add(((TieLine) network.getTieLine("b18cd1aa-7808-49b9-a7cf-605eaf07b006 + e8acf6b6-99cb-45ad-b8dc-16c7866a4ddc")).getDanglingLine1().getBoundary()); - assertEquals(1, cgmesControlAreas.getCgmesControlAreas().size()); - + cgmesControlArea.addAlias("code2", CgmesNames.ENERGY_IDENT_CODE_EIC); + assertEquals(1, cgmesControlArea.getAreaBoundaryStream().toList().size()); + Area ca2 = network.getArea("ca2"); + assertNotNull(ca2); + assertEquals(1, ca2.getAreaBoundaryStream().toList().size()); + assertTrue(ca2.getInterchangeTarget().isPresent()); + assertEquals(800, ca2.getInterchangeTarget().getAsDouble()); + assertEquals(90.07909111485668, ca2.getAcInterchange()); + assertEquals("code2", ca2.getAliasFromType(CgmesNames.ENERGY_IDENT_CODE_EIC) + .orElse(null)); service.flush(network); } @@ -1164,13 +1214,15 @@ void cgmesControlAreaTieLineTest() { UUID networkUuid = networkIds.keySet().iterator().next(); Network network = service.getNetwork(networkUuid); - CgmesControlAreas cgmesControlAreas = network.getExtension(CgmesControlAreas.class); - assertNotNull(cgmesControlAreas); - - assertEquals(1, cgmesControlAreas.getCgmesControlAreas().size()); - CgmesControlArea cgmesControlArea = cgmesControlAreas.getCgmesControlArea("ca2"); + Area cgmesControlArea = network.getAreaStream().findFirst().orElse(null); assertNotNull(cgmesControlArea); - assertEquals(1, cgmesControlArea.getBoundaries().size()); + assertEquals("ca2", cgmesControlArea.getId()); + assertTrue(cgmesControlArea.getInterchangeTarget().isPresent()); + assertEquals(800, cgmesControlArea.getInterchangeTarget().getAsDouble()); + assertEquals(90.07909111485668, cgmesControlArea.getAcInterchange()); + assertEquals("code2", cgmesControlArea.getAliasFromType(CgmesNames.ENERGY_IDENT_CODE_EIC) + .orElse(null)); + assertEquals(1, cgmesControlArea.getAreaBoundaryStream().toList().size()); } } diff --git a/network-store-integration-test/src/test/java/com/powsybl/network/store/integration/NetworkStoreIT.java b/network-store-integration-test/src/test/java/com/powsybl/network/store/integration/NetworkStoreIT.java index 01ec9066..9040c73c 100644 --- a/network-store-integration-test/src/test/java/com/powsybl/network/store/integration/NetworkStoreIT.java +++ b/network-store-integration-test/src/test/java/com/powsybl/network/store/integration/NetworkStoreIT.java @@ -684,7 +684,7 @@ void testSubstationUpdate() { verify(mockedListener, times(1)).onUpdate(s, "country", INITIAL_VARIANT_ID, Country.FR, Country.BB); verify(mockedListener, times(1)).onUpdate(s, "tso", INITIAL_VARIANT_ID, null, "New TSO"); - verify(mockedListener, times(1)).onPropertyAdded(s, "geographicalTags", "paris"); +// verify(mockedListener, times(1)).onPropertyAdded(s, "geographicalTags", "paris"); service.flush(readNetwork); } @@ -736,7 +736,7 @@ void substationTest() { verify(mockedListener, times(1)).onUpdate(s1, "country", INITIAL_VARIANT_ID, Country.FR, Country.BE); verify(mockedListener, times(1)).onUpdate(s1, "tso", INITIAL_VARIANT_ID, "TSO_FR", "TSO_BE"); - verify(mockedListener, times(1)).onPropertyAdded(s1, "geographicalTags", "BELGIUM"); +// verify(mockedListener, times(1)).onPropertyAdded(s1, "geographicalTags", "BELGIUM"); s1.setProperty("testProperty", "original"); verify(mockedListener, times(1)).onPropertyAdded(s1, "properties[testProperty]", "original"); @@ -3572,7 +3572,9 @@ void testVariants() { // check removal GEN2 in initial variant assertNull(network.getGenerator("GEN2")); // check that GEN2 object is not usable anymore - PowsyblException e = assertThrows(PowsyblException.class, gen2::getId); + PowsyblException e = assertThrows(PowsyblException.class, gen2::getEnergySource); + // id persits even with remove + assertEquals("GEN2", gen2.getId()); assertEquals("Object has been removed in current variant", e.getMessage()); // update a generator before clone, should be updated in both variants @@ -3604,7 +3606,7 @@ void testVariants() { // check removal on "v" variant assertNull(network.getGenerator("GEN2")); // check that GENERATOR2 object is not usable anymore - PowsyblException e1 = assertThrows(PowsyblException.class, gen2::getId); + PowsyblException e1 = assertThrows(PowsyblException.class, gen2::getEnergySource); assertEquals("Object has been removed in current variant", e1.getMessage()); // check that GENERATOR is modified @@ -3658,7 +3660,7 @@ void testVariants() { assertNull(network.getLoad("LOAD")); // check that LOAD object is not usable anymore - PowsyblException e = assertThrows(PowsyblException.class, load::getId); + PowsyblException e = assertThrows(PowsyblException.class, load::getP0); assertEquals("Object has been removed in current variant", e.getMessage()); // switch to "v" variant and check LOAD exists again diff --git a/network-store-server/src/main/java/com/powsybl/network/store/server/ExternalAttributesType.java b/network-store-server/src/main/java/com/powsybl/network/store/server/ExternalAttributesType.java index 901e6fd9..1028d22d 100644 --- a/network-store-server/src/main/java/com/powsybl/network/store/server/ExternalAttributesType.java +++ b/network-store-server/src/main/java/com/powsybl/network/store/server/ExternalAttributesType.java @@ -14,5 +14,6 @@ public enum ExternalAttributesType { PERMANENT_LIMIT, REACTIVE_CAPABILITY_CURVE_POINT, REGULATING_POINT, - TAP_CHANGER_STEP + TAP_CHANGER_STEP, + AREA_BOUNDARIES } diff --git a/network-store-server/src/main/java/com/powsybl/network/store/server/Mappings.java b/network-store-server/src/main/java/com/powsybl/network/store/server/Mappings.java index 2383d216..e0c628b5 100644 --- a/network-store-server/src/main/java/com/powsybl/network/store/server/Mappings.java +++ b/network-store-server/src/main/java/com/powsybl/network/store/server/Mappings.java @@ -53,10 +53,11 @@ public class Mappings { static final String LINE_TABLE = "line"; static final String TIE_LINE_TABLE = "tieLine"; static final String GROUND_TABLE = "ground"; + static final String AREA_TABLE = "area"; static final List ELEMENT_TABLES = List.of(SUBSTATION_TABLE, VOLTAGE_LEVEL_TABLE, BUSBAR_SECTION_TABLE, CONFIGURED_BUS_TABLE, SWITCH_TABLE, GENERATOR_TABLE, BATTERY_TABLE, LOAD_TABLE, SHUNT_COMPENSATOR_TABLE, STATIC_VAR_COMPENSATOR_TABLE, VSC_CONVERTER_STATION_TABLE, LCC_CONVERTER_STATION_TABLE, TWO_WINDINGS_TRANSFORMER_TABLE, - THREE_WINDINGS_TRANSFORMER_TABLE, LINE_TABLE, HVDC_LINE_TABLE, DANGLING_LINE_TABLE, TIE_LINE_TABLE, GROUND_TABLE); + THREE_WINDINGS_TRANSFORMER_TABLE, LINE_TABLE, HVDC_LINE_TABLE, DANGLING_LINE_TABLE, TIE_LINE_TABLE, GROUND_TABLE, AREA_TABLE); private final TableMapping lineMappings = new TableMapping(LINE_TABLE, ResourceType.LINE, Resource::lineBuilder, LineAttributes::new, Set.of(VOLTAGE_LEVEL_ID_1_COLUMN, VOLTAGE_LEVEL_ID_2_COLUMN)); private final TableMapping loadMappings = new TableMapping(LOAD_TABLE, ResourceType.LOAD, Resource::loadBuilder, LoadAttributes::new, Set.of(VOLTAGE_LEVEL_ID_COLUMN)); @@ -78,6 +79,7 @@ public class Mappings { private final TableMapping threeWindingsTransformerMappings = new TableMapping(THREE_WINDINGS_TRANSFORMER_TABLE, ResourceType.THREE_WINDINGS_TRANSFORMER, Resource::threeWindingsTransformerBuilder, THREE_WINDINGS_TRANSFORMER_ATTRIBUTES_SUPPLIER, Set.of(VOLTAGE_LEVEL_ID_1_COLUMN, VOLTAGE_LEVEL_ID_2_COLUMN, VOLTAGE_LEVEL_ID_3_COLUMN)); private final TableMapping tieLineMappings = new TableMapping(TIE_LINE_TABLE, ResourceType.TIE_LINE, Resource::tieLineBuilder, TieLineAttributes::new, Collections.emptySet()); private final TableMapping groundMappings = new TableMapping(GROUND_TABLE, ResourceType.GROUND, Resource::groundBuilder, GroundAttributes::new, Set.of(VOLTAGE_LEVEL_ID_COLUMN)); + private final TableMapping areaMappings = new TableMapping(AREA_TABLE, ResourceType.AREA, Resource::areaBuilder, AreaAttributes::new, Collections.emptySet()); private final List all = List.of(lineMappings, loadMappings, @@ -99,7 +101,8 @@ public class Mappings { twoWindingsTransformerMappings, threeWindingsTransformerMappings, tieLineMappings, - groundMappings); + groundMappings, + areaMappings); private final Map mappingByTable = new LinkedHashMap<>(); @@ -243,7 +246,7 @@ private void createGeneratorMappings() { generatorMappings.addColumnMapping(ALIAS_BY_TYPE, new ColumnMapping<>(Map.class, GeneratorAttributes::getAliasByType, GeneratorAttributes::setAliasByType)); generatorMappings.addColumnMapping(ALIASES_WITHOUT_TYPE, new ColumnMapping<>(Set.class, GeneratorAttributes::getAliasesWithoutType, GeneratorAttributes::setAliasesWithoutType)); generatorMappings.addColumnMapping(POSITION, new ColumnMapping<>(ConnectablePositionAttributes.class, GeneratorAttributes::getPosition, GeneratorAttributes::setPosition)); - generatorMappings.addColumnMapping("generatorShortCircuit", new ColumnMapping<>(GeneratorShortCircuitAttributes.class, GeneratorAttributes::getGeneratorShortCircuitAttributes, GeneratorAttributes::setGeneratorShortCircuitAttributes)); + generatorMappings.addColumnMapping("generatorShortCircuit", new ColumnMapping<>(ShortCircuitAttributes.class, GeneratorAttributes::getGeneratorShortCircuitAttributes, GeneratorAttributes::setGeneratorShortCircuitAttributes)); generatorMappings.addColumnMapping("condenser", new ColumnMapping<>(Boolean.class, GeneratorAttributes::isCondenser, GeneratorAttributes::setCondenser)); } @@ -304,7 +307,6 @@ private void createNetworkMappings() { networkMappings.addColumnMapping("connectedComponentsValid", new ColumnMapping<>(Boolean.class, NetworkAttributes::isConnectedComponentsValid, NetworkAttributes::setConnectedComponentsValid)); networkMappings.addColumnMapping("synchronousComponentsValid", new ColumnMapping<>(Boolean.class, NetworkAttributes::isSynchronousComponentsValid, NetworkAttributes::setSynchronousComponentsValid)); networkMappings.addColumnMapping("cimCharacteristics", new ColumnMapping<>(CimCharacteristicsAttributes.class, NetworkAttributes::getCimCharacteristics, NetworkAttributes::setCimCharacteristics)); - networkMappings.addColumnMapping("cgmesControlAreas", new ColumnMapping<>(CgmesControlAreasAttributes.class, NetworkAttributes::getCgmesControlAreas, NetworkAttributes::setCgmesControlAreas)); networkMappings.addColumnMapping("baseVoltageMapping", new ColumnMapping<>(BaseVoltageMappingAttributes.class, NetworkAttributes::getBaseVoltageMapping, NetworkAttributes::setBaseVoltageMapping)); } @@ -374,6 +376,7 @@ private void createBatteryMappings() { batteryMappings.addColumnMapping(ALIAS_BY_TYPE, new ColumnMapping<>(Map.class, BatteryAttributes::getAliasByType, BatteryAttributes::setAliasByType)); batteryMappings.addColumnMapping(ALIASES_WITHOUT_TYPE, new ColumnMapping<>(Set.class, BatteryAttributes::getAliasesWithoutType, BatteryAttributes::setAliasesWithoutType)); batteryMappings.addColumnMapping(POSITION, new ColumnMapping<>(ConnectablePositionAttributes.class, BatteryAttributes::getPosition, BatteryAttributes::setPosition)); + batteryMappings.addColumnMapping("batteryShortCircuit", new ColumnMapping<>(ShortCircuitAttributes.class, BatteryAttributes::getBatteryShortCircuitAttributes, BatteryAttributes::setBatteryShortCircuitAttributes)); } public TableMapping getBusbarSectionMappings() { @@ -437,6 +440,10 @@ private void createDanglingLineMappings() { danglingLineMappings.addColumnMapping(TIE_LINE_ID, new ColumnMapping<>(String.class, DanglingLineAttributes::getTieLineId, DanglingLineAttributes::setTieLineId)); } + public TableMapping getTieLineMappings() { + return tieLineMappings; + } + private void createTieLineMappings() { tieLineMappings.addColumnMapping("name", new ColumnMapping<>(String.class, TieLineAttributes::getName, TieLineAttributes::setName)); tieLineMappings.addColumnMapping("danglingLine1Id", new ColumnMapping<>(String.class, TieLineAttributes::getDanglingLine1Id, TieLineAttributes::setDanglingLine1Id)); @@ -447,6 +454,21 @@ private void createTieLineMappings() { tieLineMappings.addColumnMapping(ALIASES_WITHOUT_TYPE, new ColumnMapping<>(Set.class, TieLineAttributes::getAliasesWithoutType, TieLineAttributes::setAliasesWithoutType)); } + public TableMapping getAreaMappings() { + return areaMappings; + } + + private void createAreaMappings() { + areaMappings.addColumnMapping("name", new ColumnMapping<>(String.class, AreaAttributes::getName, AreaAttributes::setName)); + areaMappings.addColumnMapping("areaType", new ColumnMapping<>(String.class, AreaAttributes::getAreaType, AreaAttributes::setAreaType)); + areaMappings.addColumnMapping("voltageLevelIds", new ColumnMapping<>(Set.class, AreaAttributes::getVoltageLevelIds, AreaAttributes::setVoltageLevelIds)); + areaMappings.addColumnMapping("interchangeTarget", new ColumnMapping<>(Double.class, AreaAttributes::getInterchangeTarget, AreaAttributes::setInterchangeTarget)); + areaMappings.addColumnMapping(FICTITIOUS, new ColumnMapping<>(Boolean.class, AreaAttributes::isFictitious, AreaAttributes::setFictitious)); + areaMappings.addColumnMapping(PROPERTIES, new ColumnMapping<>(Map.class, AreaAttributes::getProperties, AreaAttributes::setProperties)); + areaMappings.addColumnMapping(ALIAS_BY_TYPE, new ColumnMapping<>(Map.class, AreaAttributes::getAliasByType, AreaAttributes::setAliasByType)); + areaMappings.addColumnMapping(ALIASES_WITHOUT_TYPE, new ColumnMapping<>(Set.class, AreaAttributes::getAliasesWithoutType, AreaAttributes::setAliasesWithoutType)); + } + public TableMapping getGroundMappings() { return groundMappings; } @@ -466,10 +488,6 @@ private void createGroundMappings() { groundMappings.addColumnMapping(POSITION, new ColumnMapping<>(ConnectablePositionAttributes.class, GroundAttributes::getPosition, GroundAttributes::setPosition)); } - public TableMapping getTieLineMappings() { - return tieLineMappings; - } - public TableMapping getShuntCompensatorMappings() { return shuntCompensatorMappings; } @@ -878,6 +896,7 @@ public Mappings() { createThreeWindingsTransformerMappings(); createTieLineMappings(); createGroundMappings(); + createAreaMappings(); for (TableMapping tableMapping : all) { mappingByTable.put(tableMapping.getTable().toLowerCase(), tableMapping); } diff --git a/network-store-server/src/main/java/com/powsybl/network/store/server/NetworkStoreController.java b/network-store-server/src/main/java/com/powsybl/network/store/server/NetworkStoreController.java index cadd01a2..f412c793 100644 --- a/network-store-server/src/main/java/com/powsybl/network/store/server/NetworkStoreController.java +++ b/network-store-server/src/main/java/com/powsybl/network/store/server/NetworkStoreController.java @@ -515,12 +515,12 @@ public ResponseEntity> getTieLines(@Paramete }) public ResponseEntity> getTieLine(@Parameter(description = "Network ID", required = true) @PathVariable("networkId") UUID networkId, @Parameter(description = "Variant number", required = true) @PathVariable("variantNum") int variantNum, - @Parameter(description = "Generator ID", required = true) @PathVariable("tieLineId") String tieLineId) { + @Parameter(description = "Tie Line ID", required = true) @PathVariable("tieLineId") String tieLineId) { return get(() -> repository.getTieLine(networkId, variantNum, tieLineId)); } @PutMapping(value = "/{networkId}/tie-lines") - @Operation(summary = "Update generators") + @Operation(summary = "Update tie lines") @ApiResponses(@ApiResponse(responseCode = "201", description = "Successfully update tie lines")) public ResponseEntity updateTieLines(@Parameter(description = "Network ID", required = true) @PathVariable("networkId") UUID networkId, @Parameter(description = "tie line resources", required = true) @RequestBody List> tieLineResources) { @@ -536,12 +536,64 @@ public ResponseEntity updateTieLines(@Parameter(description = "Network ID" }) public ResponseEntity deleteTieLines(@Parameter(description = "Network ID", required = true) @PathVariable("networkId") UUID networkId, @Parameter(description = "Variant number", required = true) @PathVariable("variantNum") int variantNum, - @Parameter(description = "List of tie line IDs to delete", required = true) @RequestBody List tieLineIds) { - repository.deleteTieLines(networkId, variantNum, tieLineIds); + @Parameter(description = "List of tie line IDs to delete", required = true) @RequestBody List tieLinesIds) { + repository.deleteTieLines(networkId, variantNum, tieLinesIds); return ResponseEntity.ok().build(); } - // battery + // area + + @PostMapping(value = "/{networkId}/areas") + @Operation(summary = "Create areas") + @ApiResponses(@ApiResponse(responseCode = "201", description = "Successfully create areas")) + public ResponseEntity createAreas(@Parameter(description = "Network ID", required = true) @PathVariable("networkId") UUID networkId, + @Parameter(description = "Tie line resources", required = true) @RequestBody List> areaResources) { + return createAll(resource -> repository.createAreas(networkId, resource), areaResources); + } + + @GetMapping(value = "/{networkId}/{variantNum}/areas", produces = APPLICATION_JSON_VALUE) + @Operation(summary = "Get areas") + @ApiResponses(@ApiResponse(responseCode = "200", description = "Successfully get tie line list")) + public ResponseEntity> getAreas(@Parameter(description = "Network ID", required = true) @PathVariable("networkId") UUID networkId, + @Parameter(description = "Variant number", required = true) @PathVariable("variantNum") int variantNum, + @Parameter(description = "Max number of tie lines to get") @RequestParam(required = false) Integer limit) { + return getAll(() -> repository.getAreas(networkId, variantNum), limit); + } + @GetMapping(value = "/{networkId}/{variantNum}/areas/{areaId}", produces = APPLICATION_JSON_VALUE) + @Operation(summary = "Get a area by id") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Successfully get tie line"), + @ApiResponse(responseCode = "404", description = "Tie line has not been found") + }) + public ResponseEntity> getArea(@Parameter(description = "Network ID", required = true) @PathVariable("networkId") UUID networkId, + @Parameter(description = "Variant number", required = true) @PathVariable("variantNum") int variantNum, + @Parameter(description = "area ID", required = true) @PathVariable("areaId") String areaId) { + return get(() -> repository.getArea(networkId, variantNum, areaId)); + } + + @PutMapping(value = "/{networkId}/areas") + @Operation(summary = "Update areas") + @ApiResponses(@ApiResponse(responseCode = "201", description = "Successfully update tie lines")) + public ResponseEntity updateAreas(@Parameter(description = "Network ID", required = true) @PathVariable("networkId") UUID networkId, + @Parameter(description = "areas resources", required = true) @RequestBody List> areasResources) { + + return updateAll(resources -> repository.updateAreas(networkId, resources), areasResources); + } + + @DeleteMapping(value = "/{networkId}/{variantNum}/areas", produces = APPLICATION_JSON_VALUE) + @Operation(summary = "Delete multiple areas by IDs") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Successfully delete areas"), + @ApiResponse(responseCode = "400", description = "Invalid request payload") + }) + public ResponseEntity deleteAreas(@Parameter(description = "Network ID", required = true) @PathVariable("networkId") UUID networkId, + @Parameter(description = "Variant number", required = true) @PathVariable("variantNum") int variantNum, + @Parameter(description = "List of tie line IDs to delete", required = true) @RequestBody List areaIds) { + repository.deleteAreas(networkId, variantNum, areaIds); + return ResponseEntity.ok().build(); + } + + // battery @PostMapping(value = "/{networkId}/batteries") @Operation(summary = "Create batteries") @ApiResponses(@ApiResponse(responseCode = "201", description = "Successfully create batteries")) diff --git a/network-store-server/src/main/java/com/powsybl/network/store/server/NetworkStoreRepository.java b/network-store-server/src/main/java/com/powsybl/network/store/server/NetworkStoreRepository.java index 62d898eb..32e88cb1 100644 --- a/network-store-server/src/main/java/com/powsybl/network/store/server/NetworkStoreRepository.java +++ b/network-store-server/src/main/java/com/powsybl/network/store/server/NetworkStoreRepository.java @@ -341,6 +341,7 @@ private static void deleteExternalAttributes(UUID uuid, Connection connection) t QueryCatalog.buildDeleteTemporaryLimitsQuery(), QueryCatalog.buildDeletePermanentLimitsQuery(), QueryCatalog.buildDeleteReactiveCapabilityCurvePointsQuery(), + QueryCatalog.buildDeleteAreaBoundariesQuery(), QueryCatalog.buildDeleteRegulatingPointsQuery(), QueryCatalog.buildDeleteTapChangerStepQuery(), QueryCatalog.buildDeleteTombstonedExternalAttributesQuery(), @@ -377,6 +378,7 @@ private static void deleteExternalAttributesVariant(UUID uuid, int variantNum, C QueryCatalog.buildDeleteTemporaryLimitsVariantQuery(), QueryCatalog.buildDeletePermanentLimitsVariantQuery(), QueryCatalog.buildDeleteReactiveCapabilityCurvePointsVariantQuery(), + QueryCatalog.buildDeleteAreaBoundariesVariantQuery(), QueryCatalog.buildDeleteRegulatingPointsVariantQuery(), QueryCatalog.buildDeleteTapChangerStepVariantQuery(), QueryCatalog.buildDeleteTombstonedExternalAttributesVariantQuery(), @@ -494,6 +496,7 @@ private void cloneExternalAttributes(Connection connection, UUID uuid, UUID targ QueryCatalog.buildCloneTemporaryLimitsQuery(), QueryCatalog.buildClonePermanentLimitsQuery(), QueryCatalog.buildCloneReactiveCapabilityCurvePointsQuery(), + QueryCatalog.buildCloneAreaBoundariesQuery(), QueryCatalog.buildCloneRegulatingPointsQuery(), QueryCatalog.buildCloneTapChangerStepQuery(), QueryExtensionCatalog.buildCloneExtensionsQuery() @@ -658,10 +661,18 @@ private Resource completeResourceInfos(Res case DANGLING_LINE -> completeDanglingLineInfos(resource, networkUuid, variantNum, equipmentId); case STATIC_VAR_COMPENSATOR -> completeStaticVarCompensatorInfos(resource, networkUuid, variantNum, equipmentId); case SHUNT_COMPENSATOR -> completeShuntCompensatorInfos(resource, networkUuid, variantNum, equipmentId); + case AREA -> completeAreaInfos(resource, networkUuid, variantNum, equipmentId); default -> resource; }; } + private Resource completeAreaInfos(Resource resource, UUID networkUuid, int variantNum, String areaId) { + Resource areaAttributesResource = (Resource) resource; + Map> areaBoundaries = getAreaBoundaries(networkUuid, variantNum, AREA_ID_COLUMN, areaId); + insertAreaBoundariesInAreas(networkUuid, List.of(areaAttributesResource), areaBoundaries); + return resource; + } + private Resource completeGeneratorInfos(Resource resource, UUID networkUuid, int variantNum, String equipmentId) { Resource generatorAttributesResource = (Resource) resource; Map> reactiveCapabilityCurvePoints = getReactiveCapabilityCurvePoints(networkUuid, variantNum, EQUIPMENT_ID_COLUMN, equipmentId); @@ -1181,6 +1192,45 @@ public List> getGenerators(UUID networkUuid, int v return generators; } + public List> getVoltageLevelGenerators(UUID networkUuid, int variantNum, String voltageLevelId) { + List> generators = getIdentifiablesInVoltageLevel(networkUuid, variantNum, voltageLevelId, mappings.getGeneratorMappings()); + + List equipmentsIds = generators.stream().map(Resource::getId).collect(Collectors.toList()); + + // regulating points + setRegulatingPointAndRegulatingEquipmentsWithIds(generators, networkUuid, variantNum, ResourceType.GENERATOR); + + // reactive capability curves + Map> reactiveCapabilityCurvePoints = getReactiveCapabilityCurvePointsWithInClause(networkUuid, variantNum, EQUIPMENT_ID_COLUMN, equipmentsIds); + insertReactiveCapabilityCurvePointsInEquipments(networkUuid, generators, reactiveCapabilityCurvePoints); + + return generators; + } + + public void updateGenerators(UUID networkUuid, List> resources) { + updateIdentifiables(networkUuid, resources, mappings.getGeneratorMappings(), VOLTAGE_LEVEL_ID_COLUMN); + + updateReactiveCapabilityCurvePoints(networkUuid, resources); + updateRegulatingPoints(networkUuid, resources, ResourceType.GENERATOR, getRegulatingPointFromEquipments(networkUuid, resources)); + } + + public void updateReactiveCapabilityCurvePoints(UUID networkUuid, List> resources) { + deleteReactiveCapabilityCurvePoints(networkUuid, resources); + Map> reactiveCapabilityCurvePointsToInsert = getReactiveCapabilityCurvePointsFromEquipments(networkUuid, resources); + insertReactiveCapabilityCurvePoints(reactiveCapabilityCurvePointsToInsert); + insertTombstonedReactiveCapabilityCurvePoints(networkUuid, reactiveCapabilityCurvePointsToInsert, resources); + } + + public void updateGeneratorsSv(UUID networkUuid, List> resources) { + updateInjectionsSv(networkUuid, resources, GENERATOR_TABLE, mappings.getGeneratorMappings()); + } + + public void deleteGenerators(UUID networkUuid, int variantNum, List generatorId) { + deleteIdentifiables(networkUuid, variantNum, generatorId, GENERATOR_TABLE); + deleteReactiveCapabilityCurvePoints(networkUuid, variantNum, generatorId); + deleteRegulatingPoints(networkUuid, variantNum, generatorId, ResourceType.GENERATOR); + } + private List> getIdentifiables(UUID networkUuid, int variantNum, TableMapping tableMapping) { try (var connection = dataSource.getConnection()) { return PartialVariantUtils.getIdentifiables( @@ -1275,35 +1325,6 @@ private boolean isTombstonedIdentifiable(Connection connection, UUID networkUuid } } - public List> getVoltageLevelGenerators(UUID networkUuid, int variantNum, String voltageLevelId) { - List> generators = getIdentifiablesInVoltageLevel(networkUuid, variantNum, voltageLevelId, mappings.getGeneratorMappings()); - - List equipmentsIds = generators.stream().map(Resource::getId).collect(Collectors.toList()); - - // regulating points - setRegulatingPointAndRegulatingEquipmentsWithIds(generators, networkUuid, variantNum, ResourceType.GENERATOR); - - // reactive capability curves - Map> reactiveCapabilityCurvePoints = getReactiveCapabilityCurvePointsWithInClause(networkUuid, variantNum, EQUIPMENT_ID_COLUMN, equipmentsIds); - insertReactiveCapabilityCurvePointsInEquipments(networkUuid, generators, reactiveCapabilityCurvePoints); - - return generators; - } - - public void updateGenerators(UUID networkUuid, List> resources) { - updateIdentifiables(networkUuid, resources, mappings.getGeneratorMappings(), VOLTAGE_LEVEL_ID_COLUMN); - - updateReactiveCapabilityCurvePoints(networkUuid, resources); - updateRegulatingPoints(networkUuid, resources, ResourceType.GENERATOR, getRegulatingPointFromEquipments(networkUuid, resources)); - } - - public void updateReactiveCapabilityCurvePoints(UUID networkUuid, List> resources) { - deleteReactiveCapabilityCurvePoints(networkUuid, resources); - Map> reactiveCapabilityCurvePointsToInsert = getReactiveCapabilityCurvePointsFromEquipments(networkUuid, resources); - insertReactiveCapabilityCurvePoints(reactiveCapabilityCurvePointsToInsert); - insertTombstonedReactiveCapabilityCurvePoints(networkUuid, reactiveCapabilityCurvePointsToInsert, resources); - } - private void insertTombstonedReactiveCapabilityCurvePoints(UUID networkUuid, Map> reactiveCapabilityCurvePointsToInsert, List> resources) { try (var connection = dataSource.getConnection()) { Map> resourcesByVariant = resources.stream() @@ -1351,15 +1372,53 @@ private Set getTombstonedReactiveCapabilityCurvePointsIds(Connection con return identifiableIds; } - public void updateGeneratorsSv(UUID networkUuid, List> resources) { - updateInjectionsSv(networkUuid, resources, GENERATOR_TABLE, mappings.getGeneratorMappings()); + private void insertTombstonedAreaBoundaries(UUID networkUuid, Map> areaBoundariesToInsert, List> resources) { + try (var connection = dataSource.getConnection()) { + Map> resourcesByVariant = resources.stream() + .collect(Collectors.groupingBy( + Resource::getVariantNum, + Collectors.mapping(Resource::getId, Collectors.toList()) + )); + Set tombstonedAreaBoundaries = PartialVariantUtils.getExternalAttributesToTombstone( + resourcesByVariant, + variantNum -> getNetworkAttributes(connection, networkUuid, variantNum), + (fullVariantNum, variantNum, ids) -> getAreaBoundariesWithInClauseForVariant(connection, networkUuid, fullVariantNum, AREA_ID_COLUMN, ids, variantNum).keySet(), + variantNum -> getTombstonedAreaBoundariesIds(connection, networkUuid, variantNum), + getExternalAttributesListToTombstoneFromEquipment(networkUuid, areaBoundariesToInsert, resources) + ); + + try (var preparedStmt = connection.prepareStatement(buildInsertTombstonedExternalAttributesQuery())) { + for (OwnerInfo areaBoundary : tombstonedAreaBoundaries) { + preparedStmt.setObject(1, areaBoundary.getNetworkUuid()); + preparedStmt.setInt(2, areaBoundary.getVariantNum()); + preparedStmt.setString(3, areaBoundary.getEquipmentId()); + preparedStmt.setString(4, ExternalAttributesType.AREA_BOUNDARIES.toString()); + preparedStmt.addBatch(); + } + preparedStmt.executeBatch(); + } + } catch (SQLException e) { + throw new UncheckedSqlException(e); + } } - public void deleteGenerators(UUID networkUuid, int variantNum, List generatorId) { - deleteIdentifiables(networkUuid, variantNum, generatorId, GENERATOR_TABLE); - deleteReactiveCapabilityCurvePoints(networkUuid, variantNum, generatorId); - deleteRegulatingPoints(networkUuid, variantNum, generatorId, ResourceType.GENERATOR); + private Set getTombstonedAreaBoundariesIds(Connection connection, UUID networkUuid, int variantNum) { + Set identifiableIds = new HashSet<>(); + try (var preparedStmt = connection.prepareStatement(buildGetTombstonedExternalAttributesIdsQuery())) { + preparedStmt.setObject(1, networkUuid); + preparedStmt.setInt(2, variantNum); + preparedStmt.setString(3, ExternalAttributesType.AREA_BOUNDARIES.toString()); + try (var resultSet = preparedStmt.executeQuery()) { + while (resultSet.next()) { + identifiableIds.add(resultSet.getString(EQUIPMENT_ID_COLUMN)); + } + } + } catch (SQLException e) { + throw new UncheckedSqlException(e); + } + return identifiableIds; } + // battery public void createBatteries(UUID networkUuid, List> resources) { @@ -2171,6 +2230,44 @@ public void updateTieLines(UUID networkUuid, List> r updateIdentifiables(networkUuid, resources, mappings.getTieLineMappings()); } + // Areas + public List> getAreas(UUID networkUuid, int variantNum) { + List> areas = getIdentifiables(networkUuid, variantNum, mappings.getAreaMappings()); + Map> areaBoundaries = getAreaBoundaries(networkUuid, variantNum, null, null); + insertAreaBoundariesInAreas(networkUuid, areas, areaBoundaries); + return areas; + } + + public Optional> getArea(UUID networkUuid, int variantNum, String areaId) { + return getIdentifiable(networkUuid, variantNum, areaId, mappings.getAreaMappings()); + } + + public void createAreas(UUID networkUuid, List> resources) { + createIdentifiables(networkUuid, resources, mappings.getAreaMappings()); + Map> areaBoundaries = new HashMap<>(); + resources.forEach(area -> + areaBoundaries.put(new OwnerInfo(area.getId(), null, networkUuid, area.getVariantNum()), + area.getAttributes().getAreaBoundaries())); + insertAreaBoundaries(areaBoundaries); + } + + public void deleteAreas(UUID networkUuid, int variantNum, List areaIds) { + deleteIdentifiables(networkUuid, variantNum, areaIds, AREA_TABLE); + deleteAreaBoundaries(networkUuid, variantNum, areaIds); + } + + public void updateAreas(UUID networkUuid, List> resources) { + updateIdentifiables(networkUuid, resources, mappings.getAreaMappings()); + updateAreaBoundaries(networkUuid, resources); + } + + public void updateAreaBoundaries(UUID networkUuid, List> resources) { + deleteAreaBoundaries(networkUuid, resources); + Map> areaBoundariesToInsert = getAreaBoundariesFromEquipments(networkUuid, resources); + insertAreaBoundaries(areaBoundariesToInsert); + insertTombstonedAreaBoundaries(networkUuid, areaBoundariesToInsert, resources); + } + // configured buses public void createBuses(UUID networkUuid, List> resources) { @@ -2965,6 +3062,124 @@ private Map> innerGetRea } } + // Area Boundaries + public void insertAreaBoundaries(Map> areaBoundaries) { + try (var connection = dataSource.getConnection()) { + try (var preparedStmt = connection.prepareStatement(buildInsertAreaBoundariesQuery())) { + List values = new ArrayList<>(7); + List>> list = new ArrayList<>(areaBoundaries.entrySet()); + for (List>> subUnit : Lists.partition(list, BATCH_SIZE)) { + for (Map.Entry> myPair : subUnit) { + for (AreaBoundaryAttributes areaBoundary : myPair.getValue()) { + values.clear(); + // In order, from the QueryCatalog.buildInsertAreaBoundariesQuery SQL query : + // equipmentId (areaId), networkUuid, variantNum, boundarydanglinglineid, terminal connectable id, terminal side, ac + values.add(myPair.getKey().getEquipmentId()); + values.add(myPair.getKey().getNetworkUuid()); + values.add(myPair.getKey().getVariantNum()); + values.add(areaBoundary.getBoundaryDanglingLineId()); + if (areaBoundary.getTerminal() != null) { + values.add(areaBoundary.getTerminal().getConnectableId()); + values.add(areaBoundary.getTerminal().getSide()); + } else { + values.add(null); + values.add(null); + } + values.add(areaBoundary.getAc()); + bindValues(preparedStmt, values, mapper); + preparedStmt.addBatch(); + } + } + preparedStmt.executeBatch(); + } + } + } catch (SQLException e) { + throw new UncheckedSqlException(e); + } + } + + public Map> getAreaBoundariesWithInClause(UUID networkUuid, int variantNum, String columnNameForWhereClause, List valuesForInClause) { + try (var connection = dataSource.getConnection()) { + return PartialVariantUtils.getExternalAttributes( + variantNum, + getNetworkAttributes(connection, networkUuid, variantNum).getFullVariantNum(), + () -> getTombstonedAreaBoundariesIds(connection, networkUuid, variantNum), + () -> getTombstonedIdentifiableIds(connection, networkUuid, variantNum), + variant -> getAreaBoundariesWithInClauseForVariant(connection, networkUuid, variant, columnNameForWhereClause, valuesForInClause, variantNum), + OwnerInfo::getEquipmentId); + } catch (SQLException e) { + throw new UncheckedSqlException(e); + } + } + + private Map> getAreaBoundariesWithInClauseForVariant(Connection connection, UUID networkUuid, int variantNum, String columnNameForWhereClause, List valuesForInClause, int variantNumOverride) { + if (valuesForInClause.isEmpty()) { + return Collections.emptyMap(); + } + try (var preparedStmt = connection.prepareStatement(buildAreaBoundaryWithInClauseQuery(columnNameForWhereClause, valuesForInClause.size()))) { + preparedStmt.setObject(1, networkUuid); + preparedStmt.setInt(2, variantNum); + for (int i = 0; i < valuesForInClause.size(); i++) { + preparedStmt.setString(3 + i, valuesForInClause.get(i)); + } + return innerGetAreaBoundaries(preparedStmt, variantNumOverride); + } catch (SQLException e) { + throw new UncheckedSqlException(e); + } + } + + public Map> getAreaBoundaries(UUID networkUuid, int variantNum, String columnNameForWhereClause, String valueForWhereClause) { + try (var connection = dataSource.getConnection()) { + return PartialVariantUtils.getExternalAttributes( + variantNum, + getNetworkAttributes(connection, networkUuid, variantNum).getFullVariantNum(), + () -> getTombstonedAreaBoundariesIds(connection, networkUuid, variantNum), + () -> getTombstonedIdentifiableIds(connection, networkUuid, variantNum), + variant -> getAreaBoundariesForVariant(connection, networkUuid, variant, columnNameForWhereClause, valueForWhereClause, variantNum), + OwnerInfo::getEquipmentId); + } catch (SQLException e) { + throw new UncheckedSqlException(e); + } + } + + public Map> getAreaBoundariesForVariant(Connection connection, UUID networkUuid, int variantNum, String columnNameForWhereClause, String valueForWhereClause, int variantNumOverride) { + try (var preparedStmt = connection.prepareStatement(buildAreaBoundaryQuery(columnNameForWhereClause))) { + preparedStmt.setObject(1, networkUuid); + preparedStmt.setInt(2, variantNum); + if (valueForWhereClause != null) { + preparedStmt.setString(3, valueForWhereClause); + } + return innerGetAreaBoundaries(preparedStmt, variantNumOverride); + } catch (SQLException e) { + throw new UncheckedSqlException(e); + } + } + + private Map> innerGetAreaBoundaries(PreparedStatement preparedStmt, int variantNumOverride) throws SQLException { + try (ResultSet resultSet = preparedStmt.executeQuery()) { + Map> map = new HashMap<>(); + while (resultSet.next()) { + OwnerInfo owner = new OwnerInfo(); + AreaBoundaryAttributes areaBoundary = new AreaBoundaryAttributes(); + // In order, from the QueryCatalog.buildAreaBoundariesQuery SQL query : + // areaId, networkUuid, boundarydanglinglineid, terminalconnectableid, terminalside, ac + owner.setEquipmentId(resultSet.getString(1)); + areaBoundary.setAreaId(resultSet.getString(1)); + owner.setNetworkUuid(UUID.fromString(resultSet.getString(2))); + owner.setVariantNum(variantNumOverride); + areaBoundary.setBoundaryDanglingLineId(resultSet.getString(3)); + Optional connectableId = Optional.ofNullable(resultSet.getString(4)); + if (connectableId.isPresent()) { + areaBoundary.setTerminal(new TerminalRefAttributes(connectableId.get(), resultSet.getString(5))); + } + areaBoundary.setAc(resultSet.getBoolean(6)); + map.computeIfAbsent(owner, k -> new ArrayList<>()); + map.get(owner).add(areaBoundary); + } + return map; + } + } + // using the request on a small number of ids and not on all elements private void setRegulatingPointAndRegulatingEquipmentsWithIds(List> elements, UUID networkUuid, int variantNum, ResourceType type) { // regulating points @@ -3393,6 +3608,23 @@ protected Map> getAreaBoundariesFromEquipments(UUID networkUuid, List> resources) { + Map> map = new HashMap<>(); + + if (!resources.isEmpty()) { + for (Resource resource : resources) { + OwnerInfo info = new OwnerInfo( + resource.getId(), + null, + networkUuid, + resource.getVariantNum() + ); + map.put(info, resource.getAttributes().getAreaBoundaries()); + } + } + return map; + } + private void insertRegulatingPointIntoInjection(UUID networkUuid, int variantNum, String equipmentId, Resource resource, ResourceType resourceType) { Map regulatingPointAttributes = getRegulatingPointsWithInClause(networkUuid, variantNum, REGULATING_EQUIPMENT_ID, Collections.singletonList(equipmentId), resourceType); @@ -3499,6 +3731,55 @@ private void deleteReactiveCapabilityCurvePoi resourceIdsByVariant.forEach((k, v) -> deleteReactiveCapabilityCurvePoints(networkUuid, k, v)); } + // area boundaries + protected void insertAreaBoundariesInAreas(UUID networkUuid, List> areas, Map> areaBoundries) { + + if (!areaBoundries.isEmpty() && !areas.isEmpty()) { + for (Resource areaResource : areas) { + OwnerInfo owner = new OwnerInfo( + areaResource.getId(), + null, + networkUuid, + areaResource.getVariantNum() + ); + if (areaBoundries.containsKey(owner)) { + AreaAttributes area = areaResource.getAttributes(); + area.setAreaBoundaries(areaBoundries.get(owner)); + } + } + } + } + + private void deleteAreaBoundaries(UUID networkUuid, int variantNum, List areaIds) { + try (var connection = dataSource.getConnection()) { + try (var preparedStmt = connection.prepareStatement(QueryCatalog.buildDeleteAreaBoundariesVariantEquipmentINQuery(areaIds.size()))) { + preparedStmt.setObject(1, networkUuid); + preparedStmt.setInt(2, variantNum); + for (int i = 0; i < areaIds.size(); i++) { + preparedStmt.setString(3 + i, areaIds.get(i)); + } + preparedStmt.executeUpdate(); + } + } catch (SQLException e) { + throw new UncheckedSqlException(e); + } + } + + private void deleteAreaBoundaries(UUID networkUuid, List> resources) { + Map> resourceIdsByVariant = new HashMap<>(); + for (Resource resource : resources) { + List resourceIds = resourceIdsByVariant.get(resource.getVariantNum()); + if (resourceIds != null) { + resourceIds.add(resource.getId()); + } else { + resourceIds = new ArrayList<>(); + resourceIds.add(resource.getId()); + } + resourceIdsByVariant.put(resource.getVariantNum(), resourceIds); + } + resourceIdsByVariant.forEach((k, v) -> deleteAreaBoundaries(networkUuid, k, v)); + } + // TapChanger Steps public Map> getTapChangerStepsWithInClause(UUID networkUuid, int variantNum, String columnNameForWhereClause, List valuesForInClause) { try (var connection = dataSource.getConnection()) { diff --git a/network-store-server/src/main/java/com/powsybl/network/store/server/QueryCatalog.java b/network-store-server/src/main/java/com/powsybl/network/store/server/QueryCatalog.java index 713c8090..70b14917 100644 --- a/network-store-server/src/main/java/com/powsybl/network/store/server/QueryCatalog.java +++ b/network-store-server/src/main/java/com/powsybl/network/store/server/QueryCatalog.java @@ -39,6 +39,7 @@ public final class QueryCatalog { static final String REGULATED_EQUIPMENT_TYPE_COLUMN = "regulatedEquipmentType"; static final String REGULATING_TAP_CHANGER_TYPE = "regulatingTapChangerType"; public static final String EQUIPMENT_ID_COLUMN = "equipmentId"; + public static final String AREA_ID_COLUMN = "areaId"; static final String REGULATING_EQUIPMENT_ID = "regulatingEquipmentId"; public static final String INDEX_COLUMN = "index"; public static final String TAPCHANGER_TYPE_COLUMN = "tapChangerType"; @@ -585,6 +586,70 @@ public static String buildDeleteReactiveCapabilityCurvePointsQuery() { NETWORK_UUID_COLUMN + " = ?"; } + // Area Boundaries + public static String buildCloneAreaBoundariesQuery() { + return "insert into AreaBoundary(" + AREA_ID_COLUMN + ", " + NETWORK_UUID_COLUMN + ", " + + VARIANT_NUM_COLUMN + ", boundarydanglinglineid, terminalconnectableid, terminalside, ac) select " + + AREA_ID_COLUMN + + ", ?, ?, boundarydanglinglineid, terminalconnectableid, terminalside, ac from AreaBoundary where " + NETWORK_UUID_COLUMN + + " = ? and " + VARIANT_NUM_COLUMN + " = ?"; + } + + public static String buildAreaBoundaryQuery(String columnNameForWhereClause) { + String baseQuiery = "select " + AREA_ID_COLUMN + ", " + + NETWORK_UUID_COLUMN + ", " + + "boundarydanglinglineid, terminalconnectableid, terminalside, ac " + + "from AreaBoundary where " + + NETWORK_UUID_COLUMN + " = ? and " + + VARIANT_NUM_COLUMN + " = ? "; + if (columnNameForWhereClause != null) { + baseQuiery += " and " + columnNameForWhereClause + " = ?"; + } + return baseQuiery; + } + + public static String buildAreaBoundaryWithInClauseQuery(String columnNameForInClause, int numberOfValues) { + if (numberOfValues < 1) { + throw new IllegalArgumentException(MINIMAL_VALUE_REQUIREMENT_ERROR); + } + return "select " + AREA_ID_COLUMN + ", " + + NETWORK_UUID_COLUMN + ", " + + "boundarydanglinglineid, terminalconnectableid, terminalside, ac " + + "from AreaBoundary where " + + NETWORK_UUID_COLUMN + " = ? and " + + VARIANT_NUM_COLUMN + " = ? and " + + columnNameForInClause + " in (" + generateInPlaceholders(numberOfValues) + ")"; + } + + public static String buildInsertAreaBoundariesQuery() { + return "insert into AreaBoundary(" + + AREA_ID_COLUMN + ", " + + NETWORK_UUID_COLUMN + " ," + + VARIANT_NUM_COLUMN + ", boundarydanglinglineid, terminalconnectableid, terminalside, ac)" + + " values (?, ?, ?, ?, ?, ?, ?)"; + } + + public static String buildDeleteAreaBoundariesVariantEquipmentINQuery(int numberOfValues) { + if (numberOfValues < 1) { + throw new IllegalArgumentException(MINIMAL_VALUE_REQUIREMENT_ERROR); + } + return "delete from AreaBoundary where " + + NETWORK_UUID_COLUMN + " = ? and " + + VARIANT_NUM_COLUMN + " = ? and " + + AREA_ID_COLUMN + " in (" + generateInPlaceholders(numberOfValues) + ")"; + } + + public static String buildDeleteAreaBoundariesVariantQuery() { + return "delete from AreaBoundary where " + + NETWORK_UUID_COLUMN + " = ? and " + + VARIANT_NUM_COLUMN + " = ?"; + } + + public static String buildDeleteAreaBoundariesQuery() { + return "delete from AreaBoundary where " + + NETWORK_UUID_COLUMN + " = ?"; + } + // Regulating point public static String buildInsertRegulatingPointsQuery() { return "insert into " + REGULATING_POINT_TABLE + " (" + diff --git a/network-store-server/src/main/resources/db/changelog/changesets/changelog_20250415T064500Z.xml b/network-store-server/src/main/resources/db/changelog/changesets/changelog_20250415T064500Z.xml new file mode 100644 index 00000000..830acea8 --- /dev/null +++ b/network-store-server/src/main/resources/db/changelog/changesets/changelog_20250415T064500Z.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/network-store-server/src/main/resources/db/changelog/db.changelog-master.yaml b/network-store-server/src/main/resources/db/changelog/db.changelog-master.yaml index e82144ba..d90fc7d3 100644 --- a/network-store-server/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/network-store-server/src/main/resources/db/changelog/db.changelog-master.yaml @@ -124,6 +124,9 @@ databaseChangeLog: file: changesets/changelog_20250130T150000Z.xml relativeToChangelogFile: true + - include: + file: changesets/changelog_20250415T064500Z.xml + relativeToChangelogFile: true # Deletion of V2.14 tap changer steps. To be added before tag v2.17.0 is deployed # - include: # file: changesets/changelog_20250130T160000Z.xml diff --git a/pom.xml b/pom.xml index 0ab57006..9df53bff 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,10 @@ 1.0 - 2.21.0-SNAPSHOT + 2.20.0 + + 2025.0.0 + 1.25.0-SNAPSHOT @@ -75,6 +78,37 @@ + + + com.powsybl + powsybl-network-store-iidm-impl + ${powsybl-network-store.version} + + + + com.powsybl + powsybl-network-store-client + ${powsybl-network-store.version} + + + + com.powsybl + powsybl-network-store-model + ${powsybl-network-store.version} + + + + com.powsybl + powsybl-dependencies + ${powsybl-dependencies.version} + pom + import + + + org.projectlombok + lombok + 1.18.34 + com.powsybl powsybl-ws-dependencies From 7a34ed3f45d2013af09be8275d8040b8b15beafa Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Tue, 22 Apr 2025 13:32:43 +0200 Subject: [PATCH 3/6] add sql migration Signed-off-by: Etienne LESOT --- .../changesets/changelog_20250415T064500Z.xml | 9 +++++ ...ationCgmesControlArea_20250415T120000Z.sql | 40 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 network-store-server/src/main/resources/db/changelog/changesets/migrationCgmesControlArea_20250415T120000Z.sql diff --git a/network-store-server/src/main/resources/db/changelog/changesets/changelog_20250415T064500Z.xml b/network-store-server/src/main/resources/db/changelog/changesets/changelog_20250415T064500Z.xml index 830acea8..57466557 100644 --- a/network-store-server/src/main/resources/db/changelog/changesets/changelog_20250415T064500Z.xml +++ b/network-store-server/src/main/resources/db/changelog/changesets/changelog_20250415T064500Z.xml @@ -50,4 +50,13 @@ + + + + diff --git a/network-store-server/src/main/resources/db/changelog/changesets/migrationCgmesControlArea_20250415T120000Z.sql b/network-store-server/src/main/resources/db/changelog/changesets/migrationCgmesControlArea_20250415T120000Z.sql new file mode 100644 index 00000000..74f5b1e5 --- /dev/null +++ b/network-store-server/src/main/resources/db/changelog/changesets/migrationCgmesControlArea_20250415T120000Z.sql @@ -0,0 +1,40 @@ +-- set area +INSERT INTO area(networkuuid, variantnum, id, name, areatype, voltagelevelids, interchangetarget, fictitious, + properties, aliasbytype) +SELECT uuid, + variantnum, + valuesTest.el ->> 'id', + valuesTest.el ->> 'name', + 'ControlAreaTypeKind.Interchange', + '[]', + cast(valuesTest.el ->> 'netInterchange' as double precision), + false, + CONCAT('{"pTolerance":"', valuesTest.el ->> 'ptolerance', '"}'), + CONCAT('{"energyIdentCodeEic":"', valuesTest.el ->> 'energyIdentificationCodeEic', '"}') +FROM (SELECT uuid, variantnum, jsonb_array_elements(cgmescontrolareas::jsonb -> 'controlAreas') as el + FROM network) AS valuesTest; + +-- set area boundaries with terminals +INSERT INTO areaboundary (areaid, networkuuid, variantnum, terminalconnectableid, terminalside) +SELECT areaid, uuid, variantnum, term ->> 'connectableId', term ->> 'side' +FROM (SELECT el ->> 'id' as areaid, + uuid, + variantnum, + jsonb_array_elements(el -> 'terminals') as term + FROM (SELECT uuid, variantnum, jsonb_array_elements(cgmescontrolareas::jsonb -> 'controlAreas') as el + FROM network) as valueTest) as valueTest2; +-- set area boundaries with dangling lines +INSERT INTO areaboundary (areaid, networkuuid, variantnum, boundarydanglinglineid, ac) +SELECT valuesTest.el ->> 'id', + uuid, + variantnum, + jsonb_array_elements(valuesTest.el -> 'boundaries') ->> 'connectableId', + true +FROM (SELECT uuid, variantnum, jsonb_array_elements(cgmescontrolareas::jsonb -> 'controlAreas') as el + FROM network) as valuesTest; +-- set ac boolean for terminal check if it is a hvdc terminal +Update areaboundary +set ac = terminalconnectableid in (SELECT id FROM hvdcline) OR + terminalconnectableid in (SELECT converterstationid1 FROM hvdcline) OR + terminalconnectableid in (SELECT converterstationid2 FROM hvdcline) +where terminalconnectableid is not null; \ No newline at end of file From ef5399eab62b5294f19c8ba4cbdeb959a0ac866a Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Mon, 28 Apr 2025 11:27:12 +0200 Subject: [PATCH 4/6] review Signed-off-by: Etienne LESOT --- .../com/powsybl/network/store/tck/AreaIt.java | 22 +---- .../integration/NetworkStoreExtensionsIT.java | 4 +- .../network/store/server/Mappings.java | 86 +------------------ .../store/server/NetworkStoreController.java | 16 ++-- .../store/server/NetworkStoreRepository.java | 23 +++-- .../network/store/server/QueryCatalog.java | 6 +- .../changesets/changelog_20250415T064500Z.xml | 9 +- pom.xml | 37 +------- 8 files changed, 34 insertions(+), 169 deletions(-) diff --git a/network-store-iidm-tck/src/test/java/com/powsybl/network/store/tck/AreaIt.java b/network-store-iidm-tck/src/test/java/com/powsybl/network/store/tck/AreaIt.java index 7e4edebe..fd4779b0 100644 --- a/network-store-iidm-tck/src/test/java/com/powsybl/network/store/tck/AreaIt.java +++ b/network-store-iidm-tck/src/test/java/com/powsybl/network/store/tck/AreaIt.java @@ -25,27 +25,7 @@ public void mergeAndFlatten() { @Override public void throwAddVoltageLevelOtherNetwork() { - // problem - } - - @Override - public void removeArea() { - // removed equipments is managed differently in powsybl core implementation - } - - @Override - public void throwRemovedVoltageLevel() { - // removed equipments is managed differently in powsybl core implementation - } - - @Override - public void testGetAreaBoundary() { - // problem with removal - } - - @Override - public void testSetterGetterInMultiVariants() { - // problem with removal + // creation of subnetwork needed } @Override diff --git a/network-store-integration-test/src/test/java/com/powsybl/network/store/integration/NetworkStoreExtensionsIT.java b/network-store-integration-test/src/test/java/com/powsybl/network/store/integration/NetworkStoreExtensionsIT.java index cf093d0b..6c1da0a5 100644 --- a/network-store-integration-test/src/test/java/com/powsybl/network/store/integration/NetworkStoreExtensionsIT.java +++ b/network-store-integration-test/src/test/java/com/powsybl/network/store/integration/NetworkStoreExtensionsIT.java @@ -1063,8 +1063,8 @@ void cgmesControlAreaDanglingLineTest() { try (NetworkStoreService service = createNetworkStoreService(randomServerPort)) { // import new network in the store Network network = service.importNetwork(CgmesConformity1Catalog.microGridBaseCaseBE().dataSource()); - Area cgmesControlAreas = network.getArea("ca1"); - assertNull(cgmesControlAreas); + Area cgmesControlArea = network.getArea("ca1"); + assertNull(cgmesControlArea); List areas = network.getAreaStream().toList(); assertEquals(0, areas.size()); } diff --git a/network-store-server/src/main/java/com/powsybl/network/store/server/Mappings.java b/network-store-server/src/main/java/com/powsybl/network/store/server/Mappings.java index e0c628b5..f5cf8c96 100644 --- a/network-store-server/src/main/java/com/powsybl/network/store/server/Mappings.java +++ b/network-store-server/src/main/java/com/powsybl/network/store/server/Mappings.java @@ -8,6 +8,7 @@ import com.powsybl.iidm.network.*; import com.powsybl.network.store.model.*; +import lombok.Getter; import org.springframework.stereotype.Service; import java.time.Instant; @@ -23,6 +24,7 @@ * @author Franck Lecuyer */ @Service +@Getter public class Mappings { private static final Supplier THREE_WINDINGS_TRANSFORMER_ATTRIBUTES_SUPPLIER = () -> { @@ -145,10 +147,6 @@ public TableMapping getTableMapping(String table) { return tableMapping; } - public TableMapping getLineMappings() { - return lineMappings; - } - private void createLineMappings() { lineMappings.addColumnMapping("name", new ColumnMapping<>(String.class, LineAttributes::getName, LineAttributes::setName)); lineMappings.addColumnMapping(VOLTAGE_LEVEL_ID_1, new ColumnMapping<>(String.class, LineAttributes::getVoltageLevelId1, LineAttributes::setVoltageLevelId1)); @@ -180,10 +178,6 @@ private void createLineMappings() { lineMappings.addColumnMapping(SELECTED_OPERATIONAL_LIMITS_GROUP_ID2_COLUMN, new ColumnMapping<>(String.class, LineAttributes::getSelectedOperationalLimitsGroupId2, LineAttributes::setSelectedOperationalLimitsGroupId2)); } - public TableMapping getLoadMappings() { - return loadMappings; - } - private void createLoadMappings() { loadMappings.addColumnMapping("name", new ColumnMapping<>(String.class, LoadAttributes::getName, LoadAttributes::setName)); loadMappings.addColumnMapping(VOLTAGE_LEVEL_ID, new ColumnMapping<>(String.class, LoadAttributes::getVoltageLevelId, LoadAttributes::setVoltageLevelId)); @@ -203,10 +197,6 @@ private void createLoadMappings() { loadMappings.addColumnMapping("loadDetail", new ColumnMapping<>(LoadDetailAttributes.class, LoadAttributes::getLoadDetail, LoadAttributes::setLoadDetail)); } - public TableMapping getGeneratorMappings() { - return generatorMappings; - } - private void createGeneratorMappings() { generatorMappings.addColumnMapping("name", new ColumnMapping<>(String.class, GeneratorAttributes::getName, GeneratorAttributes::setName)); generatorMappings.addColumnMapping(VOLTAGE_LEVEL_ID, new ColumnMapping<>(String.class, GeneratorAttributes::getVoltageLevelId, GeneratorAttributes::setVoltageLevelId)); @@ -250,10 +240,6 @@ private void createGeneratorMappings() { generatorMappings.addColumnMapping("condenser", new ColumnMapping<>(Boolean.class, GeneratorAttributes::isCondenser, GeneratorAttributes::setCondenser)); } - public TableMapping getSwitchMappings() { - return switchMappings; - } - private void createSwitchMappings() { switchMappings.addColumnMapping("name", new ColumnMapping<>(String.class, SwitchAttributes::getName, SwitchAttributes::setName)); switchMappings.addColumnMapping(VOLTAGE_LEVEL_ID, new ColumnMapping<>(String.class, SwitchAttributes::getVoltageLevelId, SwitchAttributes::setVoltageLevelId)); @@ -270,10 +256,6 @@ private void createSwitchMappings() { switchMappings.addColumnMapping(ALIASES_WITHOUT_TYPE, new ColumnMapping<>(Set.class, SwitchAttributes::getAliasesWithoutType, SwitchAttributes::setAliasesWithoutType)); } - public TableMapping getSubstationMappings() { - return substationMappings; - } - private void createSubstationMappings() { substationMappings.addColumnMapping("name", new ColumnMapping<>(String.class, SubstationAttributes::getName, SubstationAttributes::setName)); substationMappings.addColumnMapping(FICTITIOUS, new ColumnMapping<>(Boolean.class, SubstationAttributes::isFictitious, SubstationAttributes::setFictitious)); @@ -286,10 +268,6 @@ private void createSubstationMappings() { substationMappings.addColumnMapping("entsoeArea", new ColumnMapping<>(EntsoeAreaAttributes.class, SubstationAttributes::getEntsoeArea, SubstationAttributes::setEntsoeArea)); } - public TableMapping getNetworkMappings() { - return networkMappings; - } - private void createNetworkMappings() { networkMappings.addColumnMapping("uuid", new ColumnMapping<>(UUID.class, NetworkAttributes::getUuid, NetworkAttributes::setUuid)); networkMappings.addColumnMapping("variantId", new ColumnMapping<>(String.class, NetworkAttributes::getVariantId, NetworkAttributes::setVariantId)); @@ -310,10 +288,6 @@ private void createNetworkMappings() { networkMappings.addColumnMapping("baseVoltageMapping", new ColumnMapping<>(BaseVoltageMappingAttributes.class, NetworkAttributes::getBaseVoltageMapping, NetworkAttributes::setBaseVoltageMapping)); } - public TableMapping getVoltageLevelMappings() { - return voltageLevelMappings; - } - private void createVoltageLevelMappings() { voltageLevelMappings.addColumnMapping("substationId", new ColumnMapping<>(String.class, VoltageLevelAttributes::getSubstationId, VoltageLevelAttributes::setSubstationId)); voltageLevelMappings.addColumnMapping("name", new ColumnMapping<>(String.class, VoltageLevelAttributes::getName, VoltageLevelAttributes::setName)); @@ -339,10 +313,6 @@ private void createVoltageLevelMappings() { voltageLevelMappings.addColumnMapping("nodeToFictitiousQ0", new ColumnMapping<>(null, VoltageLevelAttributes::getNodeToFictitiousQ0, VoltageLevelAttributes::setNodeToFictitiousQ0, Integer.class, Double.class)); } - public TableMapping getBatteryMappings() { - return batteryMappings; - } - private void createBatteryMappings() { batteryMappings.addColumnMapping("name", new ColumnMapping<>(String.class, BatteryAttributes::getName, BatteryAttributes::setName)); batteryMappings.addColumnMapping(VOLTAGE_LEVEL_ID, new ColumnMapping<>(String.class, BatteryAttributes::getVoltageLevelId, BatteryAttributes::setVoltageLevelId)); @@ -379,10 +349,6 @@ private void createBatteryMappings() { batteryMappings.addColumnMapping("batteryShortCircuit", new ColumnMapping<>(ShortCircuitAttributes.class, BatteryAttributes::getBatteryShortCircuitAttributes, BatteryAttributes::setBatteryShortCircuitAttributes)); } - public TableMapping getBusbarSectionMappings() { - return busbarSectionMappings; - } - private void createBusbarSectionMappings() { busbarSectionMappings.addColumnMapping("name", new ColumnMapping<>(String.class, BusbarSectionAttributes::getName, BusbarSectionAttributes::setName)); busbarSectionMappings.addColumnMapping(VOLTAGE_LEVEL_ID, new ColumnMapping<>(String.class, BusbarSectionAttributes::getVoltageLevelId, BusbarSectionAttributes::setVoltageLevelId)); @@ -394,10 +360,6 @@ private void createBusbarSectionMappings() { busbarSectionMappings.addColumnMapping(POSITION, new ColumnMapping<>(BusbarSectionPositionAttributes.class, BusbarSectionAttributes::getPosition, BusbarSectionAttributes::setPosition)); } - public TableMapping getConfiguredBusMappings() { - return configuredBusMappings; - } - private void createConfiguredBusMappings() { configuredBusMappings.addColumnMapping("name", new ColumnMapping<>(String.class, ConfiguredBusAttributes::getName, ConfiguredBusAttributes::setName)); configuredBusMappings.addColumnMapping(VOLTAGE_LEVEL_ID, new ColumnMapping<>(String.class, ConfiguredBusAttributes::getVoltageLevelId, ConfiguredBusAttributes::setVoltageLevelId)); @@ -411,10 +373,6 @@ private void createConfiguredBusMappings() { configuredBusMappings.addColumnMapping("fictitiousq0", new ColumnMapping<>(Double.class, ConfiguredBusAttributes::getFictitiousQ0, ConfiguredBusAttributes::setFictitiousQ0)); } - public TableMapping getDanglingLineMappings() { - return danglingLineMappings; - } - private void createDanglingLineMappings() { danglingLineMappings.addColumnMapping("name", new ColumnMapping<>(String.class, DanglingLineAttributes::getName, DanglingLineAttributes::setName)); danglingLineMappings.addColumnMapping(VOLTAGE_LEVEL_ID, new ColumnMapping<>(String.class, DanglingLineAttributes::getVoltageLevelId, DanglingLineAttributes::setVoltageLevelId)); @@ -440,10 +398,6 @@ private void createDanglingLineMappings() { danglingLineMappings.addColumnMapping(TIE_LINE_ID, new ColumnMapping<>(String.class, DanglingLineAttributes::getTieLineId, DanglingLineAttributes::setTieLineId)); } - public TableMapping getTieLineMappings() { - return tieLineMappings; - } - private void createTieLineMappings() { tieLineMappings.addColumnMapping("name", new ColumnMapping<>(String.class, TieLineAttributes::getName, TieLineAttributes::setName)); tieLineMappings.addColumnMapping("danglingLine1Id", new ColumnMapping<>(String.class, TieLineAttributes::getDanglingLine1Id, TieLineAttributes::setDanglingLine1Id)); @@ -454,10 +408,6 @@ private void createTieLineMappings() { tieLineMappings.addColumnMapping(ALIASES_WITHOUT_TYPE, new ColumnMapping<>(Set.class, TieLineAttributes::getAliasesWithoutType, TieLineAttributes::setAliasesWithoutType)); } - public TableMapping getAreaMappings() { - return areaMappings; - } - private void createAreaMappings() { areaMappings.addColumnMapping("name", new ColumnMapping<>(String.class, AreaAttributes::getName, AreaAttributes::setName)); areaMappings.addColumnMapping("areaType", new ColumnMapping<>(String.class, AreaAttributes::getAreaType, AreaAttributes::setAreaType)); @@ -469,10 +419,6 @@ private void createAreaMappings() { areaMappings.addColumnMapping(ALIASES_WITHOUT_TYPE, new ColumnMapping<>(Set.class, AreaAttributes::getAliasesWithoutType, AreaAttributes::setAliasesWithoutType)); } - public TableMapping getGroundMappings() { - return groundMappings; - } - private void createGroundMappings() { groundMappings.addColumnMapping(NAME_COLUMN, new ColumnMapping<>(String.class, GroundAttributes::getName, GroundAttributes::setName)); groundMappings.addColumnMapping(VOLTAGE_LEVEL_ID, new ColumnMapping<>(String.class, GroundAttributes::getVoltageLevelId, GroundAttributes::setVoltageLevelId)); @@ -488,10 +434,6 @@ private void createGroundMappings() { groundMappings.addColumnMapping(POSITION, new ColumnMapping<>(ConnectablePositionAttributes.class, GroundAttributes::getPosition, GroundAttributes::setPosition)); } - public TableMapping getShuntCompensatorMappings() { - return shuntCompensatorMappings; - } - private void createShuntCompensatorMappings() { shuntCompensatorMappings.addColumnMapping("name", new ColumnMapping<>(String.class, ShuntCompensatorAttributes::getName, ShuntCompensatorAttributes::setName)); shuntCompensatorMappings.addColumnMapping(VOLTAGE_LEVEL_ID, new ColumnMapping<>(String.class, ShuntCompensatorAttributes::getVoltageLevelId, ShuntCompensatorAttributes::setVoltageLevelId)); @@ -524,10 +466,6 @@ private void createShuntCompensatorMappings() { shuntCompensatorMappings.addColumnMapping(POSITION, new ColumnMapping<>(ConnectablePositionAttributes.class, ShuntCompensatorAttributes::getPosition, ShuntCompensatorAttributes::setPosition)); } - public TableMapping getVscConverterStationMappings() { - return vscConverterStationMappings; - } - private void createVscConverterStationMappings() { vscConverterStationMappings.addColumnMapping("name", new ColumnMapping<>(String.class, VscConverterStationAttributes::getName, VscConverterStationAttributes::setName)); vscConverterStationMappings.addColumnMapping(VOLTAGE_LEVEL_ID, new ColumnMapping<>(String.class, VscConverterStationAttributes::getVoltageLevelId, VscConverterStationAttributes::setVoltageLevelId)); @@ -562,10 +500,6 @@ private void createVscConverterStationMappings() { vscConverterStationMappings.addColumnMapping(POSITION, new ColumnMapping<>(ConnectablePositionAttributes.class, VscConverterStationAttributes::getPosition, VscConverterStationAttributes::setPosition)); } - public TableMapping getLccConverterStationMappings() { - return lccConverterStationMappings; - } - private void createLccConverterStationMappings() { lccConverterStationMappings.addColumnMapping("name", new ColumnMapping<>(String.class, LccConverterStationAttributes::getName, LccConverterStationAttributes::setName)); lccConverterStationMappings.addColumnMapping(VOLTAGE_LEVEL_ID, new ColumnMapping<>(String.class, LccConverterStationAttributes::getVoltageLevelId, LccConverterStationAttributes::setVoltageLevelId)); @@ -583,10 +517,6 @@ private void createLccConverterStationMappings() { lccConverterStationMappings.addColumnMapping(POSITION, new ColumnMapping<>(ConnectablePositionAttributes.class, LccConverterStationAttributes::getPosition, LccConverterStationAttributes::setPosition)); } - public TableMapping getStaticVarCompensatorMappings() { - return staticVarCompensatorMappings; - } - private void createStaticVarCompensatorMappings() { staticVarCompensatorMappings.addColumnMapping("name", new ColumnMapping<>(String.class, StaticVarCompensatorAttributes::getName, StaticVarCompensatorAttributes::setName)); staticVarCompensatorMappings.addColumnMapping(VOLTAGE_LEVEL_ID, new ColumnMapping<>(String.class, StaticVarCompensatorAttributes::getVoltageLevelId, StaticVarCompensatorAttributes::setVoltageLevelId)); @@ -608,10 +538,6 @@ private void createStaticVarCompensatorMappings() { staticVarCompensatorMappings.addColumnMapping("standbyAutomaton", new ColumnMapping<>(StandbyAutomatonAttributes.class, StaticVarCompensatorAttributes::getStandbyAutomaton, StaticVarCompensatorAttributes::setStandbyAutomaton)); } - public TableMapping getHvdcLineMappings() { - return hvdcLineMappings; - } - private void createHvdcLineMappings() { hvdcLineMappings.addColumnMapping("name", new ColumnMapping<>(String.class, HvdcLineAttributes::getName, HvdcLineAttributes::setName)); hvdcLineMappings.addColumnMapping(FICTITIOUS, new ColumnMapping<>(Boolean.class, HvdcLineAttributes::isFictitious, HvdcLineAttributes::setFictitious)); @@ -629,10 +555,6 @@ private void createHvdcLineMappings() { hvdcLineMappings.addColumnMapping("hvdcOperatorActivePowerRange", new ColumnMapping<>(HvdcOperatorActivePowerRangeAttributes.class, HvdcLineAttributes::getHvdcOperatorActivePowerRange, HvdcLineAttributes::setHvdcOperatorActivePowerRange)); } - public TableMapping getTwoWindingsTransformerMappings() { - return twoWindingsTransformerMappings; - } - private void createTwoWindingsTransformerMappings() { twoWindingsTransformerMappings.addColumnMapping("name", new ColumnMapping<>(String.class, TwoWindingsTransformerAttributes::getName, TwoWindingsTransformerAttributes::setName)); twoWindingsTransformerMappings.addColumnMapping(VOLTAGE_LEVEL_ID_1, new ColumnMapping<>(String.class, TwoWindingsTransformerAttributes::getVoltageLevelId1, TwoWindingsTransformerAttributes::setVoltageLevelId1)); @@ -741,10 +663,6 @@ private void createTwoWindingsTransformerMappings() { })); } - public TableMapping getThreeWindingsTransformerMappings() { - return threeWindingsTransformerMappings; - } - private void createThreeWindingsTransformerMappings() { threeWindingsTransformerMappings.addColumnMapping("name", new ColumnMapping<>(String.class, ThreeWindingsTransformerAttributes::getName, ThreeWindingsTransformerAttributes::setName)); threeWindingsTransformerMappings.addColumnMapping("p1", new ColumnMapping<>(Double.class, ThreeWindingsTransformerAttributes::getP1, ThreeWindingsTransformerAttributes::setP1)); diff --git a/network-store-server/src/main/java/com/powsybl/network/store/server/NetworkStoreController.java b/network-store-server/src/main/java/com/powsybl/network/store/server/NetworkStoreController.java index f412c793..a76e20e9 100644 --- a/network-store-server/src/main/java/com/powsybl/network/store/server/NetworkStoreController.java +++ b/network-store-server/src/main/java/com/powsybl/network/store/server/NetworkStoreController.java @@ -546,24 +546,24 @@ public ResponseEntity deleteTieLines(@Parameter(description = "Network ID" @Operation(summary = "Create areas") @ApiResponses(@ApiResponse(responseCode = "201", description = "Successfully create areas")) public ResponseEntity createAreas(@Parameter(description = "Network ID", required = true) @PathVariable("networkId") UUID networkId, - @Parameter(description = "Tie line resources", required = true) @RequestBody List> areaResources) { + @Parameter(description = "Area resources", required = true) @RequestBody List> areaResources) { return createAll(resource -> repository.createAreas(networkId, resource), areaResources); } @GetMapping(value = "/{networkId}/{variantNum}/areas", produces = APPLICATION_JSON_VALUE) @Operation(summary = "Get areas") - @ApiResponses(@ApiResponse(responseCode = "200", description = "Successfully get tie line list")) + @ApiResponses(@ApiResponse(responseCode = "200", description = "Successfully get area list")) public ResponseEntity> getAreas(@Parameter(description = "Network ID", required = true) @PathVariable("networkId") UUID networkId, @Parameter(description = "Variant number", required = true) @PathVariable("variantNum") int variantNum, - @Parameter(description = "Max number of tie lines to get") @RequestParam(required = false) Integer limit) { + @Parameter(description = "Max number of areas to get") @RequestParam(required = false) Integer limit) { return getAll(() -> repository.getAreas(networkId, variantNum), limit); } @GetMapping(value = "/{networkId}/{variantNum}/areas/{areaId}", produces = APPLICATION_JSON_VALUE) @Operation(summary = "Get a area by id") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully get tie line"), - @ApiResponse(responseCode = "404", description = "Tie line has not been found") + @ApiResponse(responseCode = "200", description = "Successfully get area"), + @ApiResponse(responseCode = "404", description = "Area has not been found") }) public ResponseEntity> getArea(@Parameter(description = "Network ID", required = true) @PathVariable("networkId") UUID networkId, @Parameter(description = "Variant number", required = true) @PathVariable("variantNum") int variantNum, @@ -573,7 +573,7 @@ public ResponseEntity> getArea(@Parameter(descr @PutMapping(value = "/{networkId}/areas") @Operation(summary = "Update areas") - @ApiResponses(@ApiResponse(responseCode = "201", description = "Successfully update tie lines")) + @ApiResponses(@ApiResponse(responseCode = "201", description = "Successfully update areas")) public ResponseEntity updateAreas(@Parameter(description = "Network ID", required = true) @PathVariable("networkId") UUID networkId, @Parameter(description = "areas resources", required = true) @RequestBody List> areasResources) { @@ -583,12 +583,12 @@ public ResponseEntity updateAreas(@Parameter(description = "Network ID", r @DeleteMapping(value = "/{networkId}/{variantNum}/areas", produces = APPLICATION_JSON_VALUE) @Operation(summary = "Delete multiple areas by IDs") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully delete areas"), + @ApiResponse(responseCode = "200", description = "Successfully deleted areas"), @ApiResponse(responseCode = "400", description = "Invalid request payload") }) public ResponseEntity deleteAreas(@Parameter(description = "Network ID", required = true) @PathVariable("networkId") UUID networkId, @Parameter(description = "Variant number", required = true) @PathVariable("variantNum") int variantNum, - @Parameter(description = "List of tie line IDs to delete", required = true) @RequestBody List areaIds) { + @Parameter(description = "List of area IDs to delete", required = true) @RequestBody List areaIds) { repository.deleteAreas(networkId, variantNum, areaIds); return ResponseEntity.ok().build(); } diff --git a/network-store-server/src/main/java/com/powsybl/network/store/server/NetworkStoreRepository.java b/network-store-server/src/main/java/com/powsybl/network/store/server/NetworkStoreRepository.java index 32e88cb1..3e8dad17 100644 --- a/network-store-server/src/main/java/com/powsybl/network/store/server/NetworkStoreRepository.java +++ b/network-store-server/src/main/java/com/powsybl/network/store/server/NetworkStoreRepository.java @@ -2261,15 +2261,7 @@ public void updateAreas(UUID networkUuid, List> resourc updateAreaBoundaries(networkUuid, resources); } - public void updateAreaBoundaries(UUID networkUuid, List> resources) { - deleteAreaBoundaries(networkUuid, resources); - Map> areaBoundariesToInsert = getAreaBoundariesFromEquipments(networkUuid, resources); - insertAreaBoundaries(areaBoundariesToInsert); - insertTombstonedAreaBoundaries(networkUuid, areaBoundariesToInsert, resources); - } - // configured buses - public void createBuses(UUID networkUuid, List> resources) { createIdentifiables(networkUuid, resources, mappings.getConfiguredBusMappings()); } @@ -3063,6 +3055,13 @@ private Map> innerGetRea } // Area Boundaries + public void updateAreaBoundaries(UUID networkUuid, List> resources) { + deleteAreaBoundaries(networkUuid, resources); + Map> areaBoundariesToInsert = getAreaBoundariesFromEquipments(networkUuid, resources); + insertAreaBoundaries(areaBoundariesToInsert); + insertTombstonedAreaBoundaries(networkUuid, areaBoundariesToInsert, resources); + } + public void insertAreaBoundaries(Map> areaBoundaries) { try (var connection = dataSource.getConnection()) { try (var preparedStmt = connection.prepareStatement(buildInsertAreaBoundariesQuery())) { @@ -3732,9 +3731,9 @@ private void deleteReactiveCapabilityCurvePoi } // area boundaries - protected void insertAreaBoundariesInAreas(UUID networkUuid, List> areas, Map> areaBoundries) { + protected void insertAreaBoundariesInAreas(UUID networkUuid, List> areas, Map> areaBoundaries) { - if (!areaBoundries.isEmpty() && !areas.isEmpty()) { + if (!areaBoundaries.isEmpty() && !areas.isEmpty()) { for (Resource areaResource : areas) { OwnerInfo owner = new OwnerInfo( areaResource.getId(), @@ -3742,9 +3741,9 @@ protected void insertAreaBoundariesInAreas(UUID networkUuid, List - + - + - + + + + diff --git a/pom.xml b/pom.xml index 31b2caab..09af7520 100644 --- a/pom.xml +++ b/pom.xml @@ -49,10 +49,7 @@ 1.0 - 2.20.0 - - 2025.0.0 - 1.25.0-SNAPSHOT + 2.21.0 @@ -77,38 +74,6 @@ - - - - com.powsybl - powsybl-network-store-iidm-impl - ${powsybl-network-store.version} - - - - com.powsybl - powsybl-network-store-client - ${powsybl-network-store.version} - - - - com.powsybl - powsybl-network-store-model - ${powsybl-network-store.version} - - - - com.powsybl - powsybl-dependencies - ${powsybl-dependencies.version} - pom - import - - - org.projectlombok - lombok - 1.18.34 - com.powsybl powsybl-ws-dependencies From ef5a622442cdd687127e52ef997648dd4d6554ae Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Mon, 28 Apr 2025 14:23:25 +0200 Subject: [PATCH 5/6] fix sql migration Signed-off-by: Etienne LESOT --- .../migrationCgmesControlArea_20250415T120000Z.sql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/network-store-server/src/main/resources/db/changelog/changesets/migrationCgmesControlArea_20250415T120000Z.sql b/network-store-server/src/main/resources/db/changelog/changesets/migrationCgmesControlArea_20250415T120000Z.sql index 74f5b1e5..5a5f8686 100644 --- a/network-store-server/src/main/resources/db/changelog/changesets/migrationCgmesControlArea_20250415T120000Z.sql +++ b/network-store-server/src/main/resources/db/changelog/changesets/migrationCgmesControlArea_20250415T120000Z.sql @@ -12,7 +12,7 @@ SELECT uuid, CONCAT('{"pTolerance":"', valuesTest.el ->> 'ptolerance', '"}'), CONCAT('{"energyIdentCodeEic":"', valuesTest.el ->> 'energyIdentificationCodeEic', '"}') FROM (SELECT uuid, variantnum, jsonb_array_elements(cgmescontrolareas::jsonb -> 'controlAreas') as el - FROM network) AS valuesTest; + FROM network WHERE variantnum = 0) AS valuesTest; -- set area boundaries with terminals INSERT INTO areaboundary (areaid, networkuuid, variantnum, terminalconnectableid, terminalside) @@ -22,7 +22,7 @@ FROM (SELECT el ->> 'id' as areaid, variantnum, jsonb_array_elements(el -> 'terminals') as term FROM (SELECT uuid, variantnum, jsonb_array_elements(cgmescontrolareas::jsonb -> 'controlAreas') as el - FROM network) as valueTest) as valueTest2; + FROM network WHERE variantnum = 0) as valueTest) as valueTest2; -- set area boundaries with dangling lines INSERT INTO areaboundary (areaid, networkuuid, variantnum, boundarydanglinglineid, ac) SELECT valuesTest.el ->> 'id', @@ -31,7 +31,7 @@ SELECT valuesTest.el ->> 'id', jsonb_array_elements(valuesTest.el -> 'boundaries') ->> 'connectableId', true FROM (SELECT uuid, variantnum, jsonb_array_elements(cgmescontrolareas::jsonb -> 'controlAreas') as el - FROM network) as valuesTest; + FROM network WHERE variantnum = 0) as valuesTest; -- set ac boolean for terminal check if it is a hvdc terminal Update areaboundary set ac = terminalconnectableid in (SELECT id FROM hvdcline) OR From c57bbb6de9a39c46987c1d5be8ec6638dae10565 Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Mon, 28 Apr 2025 14:38:13 +0200 Subject: [PATCH 6/6] fix test Signed-off-by: Etienne LESOT --- .../com/powsybl/network/store/integration/NetworkStoreIT.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/network-store-integration-test/src/test/java/com/powsybl/network/store/integration/NetworkStoreIT.java b/network-store-integration-test/src/test/java/com/powsybl/network/store/integration/NetworkStoreIT.java index 9040c73c..de440b95 100644 --- a/network-store-integration-test/src/test/java/com/powsybl/network/store/integration/NetworkStoreIT.java +++ b/network-store-integration-test/src/test/java/com/powsybl/network/store/integration/NetworkStoreIT.java @@ -684,7 +684,7 @@ void testSubstationUpdate() { verify(mockedListener, times(1)).onUpdate(s, "country", INITIAL_VARIANT_ID, Country.FR, Country.BB); verify(mockedListener, times(1)).onUpdate(s, "tso", INITIAL_VARIANT_ID, null, "New TSO"); -// verify(mockedListener, times(1)).onPropertyAdded(s, "geographicalTags", "paris"); + verify(mockedListener, times(1)).onUpdate(s, "geographicalTags", null, Set.of(), Set.of("paris")); service.flush(readNetwork); } @@ -736,7 +736,7 @@ void substationTest() { verify(mockedListener, times(1)).onUpdate(s1, "country", INITIAL_VARIANT_ID, Country.FR, Country.BE); verify(mockedListener, times(1)).onUpdate(s1, "tso", INITIAL_VARIANT_ID, "TSO_FR", "TSO_BE"); -// verify(mockedListener, times(1)).onPropertyAdded(s1, "geographicalTags", "BELGIUM"); + verify(mockedListener, times(1)).onUpdate(s1, "geographicalTags", null, Set.of(), Set.of("BELGIUM")); s1.setProperty("testProperty", "original"); verify(mockedListener, times(1)).onPropertyAdded(s1, "properties[testProperty]", "original");