-
Notifications
You must be signed in to change notification settings - Fork 0
voltage measurements modification for busbar-section network-modification #821
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ac74cb4
7e6d920
fd9afd1
0f06b65
648e344
573a6c4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| /** | ||
| * Copyright (c) 2026, 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 org.gridsuite.modification.server.entities.equipment.modification; | ||
|
|
||
| import jakarta.persistence.*; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
| import org.gridsuite.modification.dto.BusbarSectionVMeasurementInfos; | ||
| import org.gridsuite.modification.server.entities.equipment.modification.attribute.BooleanModificationEmbedded; | ||
| import org.gridsuite.modification.server.entities.equipment.modification.attribute.DoubleModificationEmbedded; | ||
|
|
||
| import java.util.UUID; | ||
|
|
||
| import static org.gridsuite.modification.server.entities.equipment.modification.attribute.IAttributeModificationEmbeddable.toAttributeModification; | ||
|
|
||
| /** | ||
| * @author Mohamed Ben Rejeb <mohamed.ben-rejeb at rte-france.com> | ||
| */ | ||
| @NoArgsConstructor | ||
| @Getter | ||
| @Entity | ||
| @Table(name = "busbar_section_v_measurement") | ||
| public class BusbarSectionVMeasurementEntity { | ||
| @Id | ||
| @GeneratedValue(strategy = GenerationType.AUTO) | ||
| @Column(name = "id") | ||
| private UUID id; | ||
|
|
||
| @Column(name = "busbar_section_id") | ||
| private String busbarSectionId; | ||
|
|
||
| @Embedded | ||
| @AttributeOverrides(value = { | ||
| @AttributeOverride(name = "value", column = @Column(name = "v_measurement_value")), | ||
| @AttributeOverride(name = "opType", column = @Column(name = "v_measurement_value_op")) | ||
| }) | ||
| private DoubleModificationEmbedded vMeasurementValue; | ||
|
|
||
| @Embedded | ||
| @AttributeOverrides(value = { | ||
| @AttributeOverride(name = "value", column = @Column(name = "v_measurement_validity")), | ||
| @AttributeOverride(name = "opType", column = @Column(name = "v_measurement_validity_op")) | ||
| }) | ||
| private BooleanModificationEmbedded vMeasurementValidity; | ||
|
|
||
| public BusbarSectionVMeasurementEntity(BusbarSectionVMeasurementInfos infos) { | ||
| this.busbarSectionId = infos.getBusbarSectionId(); | ||
| this.vMeasurementValue = infos.getVMeasurementValue() != null ? new DoubleModificationEmbedded(infos.getVMeasurementValue()) : null; | ||
| this.vMeasurementValidity = infos.getVMeasurementValidity() != null ? new BooleanModificationEmbedded(infos.getVMeasurementValidity()) : null; | ||
| } | ||
|
|
||
| public BusbarSectionVMeasurementInfos toInfos() { | ||
| return BusbarSectionVMeasurementInfos.builder() | ||
| .busbarSectionId(busbarSectionId) | ||
| .vMeasurementValue(toAttributeModification(vMeasurementValue)) | ||
| .vMeasurementValidity(toAttributeModification(vMeasurementValidity)) | ||
| .build(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| <?xml version="1.1" encoding="UTF-8" standalone="no"?> | ||
| <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd"> | ||
| <changeSet author="benrejebmoh (generated)" id="1779788708250-3"> | ||
| <createTable tableName="busbar_section_v_measurement"> | ||
| <column name="id" type="UUID"> | ||
| <constraints nullable="false" primaryKey="true" primaryKeyName="busbar_section_v_measurementPK"/> | ||
| </column> | ||
| <column name="busbar_section_id" type="VARCHAR(255)"/> | ||
| <column name="v_measurement_validity_op" type="VARCHAR(255)"/> | ||
| <column name="v_measurement_validity" type="BOOLEAN"/> | ||
| <column name="v_measurement_value_op" type="VARCHAR(255)"/> | ||
| <column name="v_measurement_value" type="FLOAT(53)"/> | ||
| <column name="voltage_level_modification_id" type="UUID"> | ||
| <constraints nullable="false"/> | ||
| </column> | ||
| </createTable> | ||
| </changeSet> | ||
| <changeSet author="benrejebmoh (generated)" id="1779788708250-6"> | ||
| <addForeignKeyConstraint baseColumnNames="voltage_level_modification_id" baseTableName="busbar_section_v_measurement" constraintName="busbar_section_v_measurement_vl_id_fk" deferrable="false" initiallyDeferred="false" referencedColumnNames="id" referencedTableName="voltage_level_modification" validate="true"/> | ||
| </changeSet> | ||
|
Comment on lines
+4
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Enforce busbar measurement row uniqueness and required target busbar. The schema currently allows multiple rows for the same Suggested migration hardening <changeSet author="benrejebmoh (generated)" id="1779788708250-3">
<createTable tableName="busbar_section_v_measurement">
@@
- <column name="busbar_section_id" type="VARCHAR(255)"/>
+ <column name="busbar_section_id" type="VARCHAR(255)">
+ <constraints nullable="false"/>
+ </column>
@@
</createTable>
+ <addUniqueConstraint
+ tableName="busbar_section_v_measurement"
+ columnNames="voltage_level_modification_id,busbar_section_id"
+ constraintName="uk_busbar_section_v_measurement_vl_bbs"/>
</changeSet>🤖 Prompt for AI Agents |
||
| </databaseChangeLog> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,10 +7,13 @@ | |
| package org.gridsuite.modification.server.modifications; | ||
|
|
||
| import com.fasterxml.jackson.core.type.TypeReference; | ||
| import com.powsybl.iidm.network.BusbarSection; | ||
| import com.powsybl.iidm.network.Network; | ||
| import com.powsybl.iidm.network.VoltageLevel; | ||
| import com.powsybl.iidm.network.extensions.IdentifiableShortCircuit; | ||
| import com.powsybl.iidm.network.extensions.IdentifiableShortCircuitAdder; | ||
| import com.powsybl.iidm.network.extensions.Measurement; | ||
| import com.powsybl.iidm.network.extensions.Measurements; | ||
| import org.gridsuite.modification.NetworkModificationException; | ||
| import org.gridsuite.modification.dto.*; | ||
| import org.gridsuite.modification.server.utils.NetworkCreation; | ||
|
|
@@ -19,10 +22,13 @@ | |
| import org.springframework.http.MediaType; | ||
| import org.springframework.test.web.servlet.ResultActions; | ||
|
|
||
| import java.util.Collection; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.UUID; | ||
|
|
||
| import static org.assertj.core.api.Assertions.assertThat; | ||
|
|
||
| import static org.gridsuite.modification.NetworkModificationException.Type.MODIFY_VOLTAGE_LEVEL_ERROR; | ||
| import static org.gridsuite.modification.server.report.NetworkModificationServerReportResourceBundle.ERROR_MESSAGE_KEY; | ||
| import static org.gridsuite.modification.server.utils.TestUtils.assertLogMessage; | ||
|
|
@@ -39,6 +45,8 @@ | |
| class VoltageLevelModificationTest extends AbstractNetworkModificationTest { | ||
| private static final String PROPERTY_NAME = "property-name"; | ||
| private static final String PROPERTY_VALUE = "property-value"; | ||
| private static final Double MEASUREMENT_V_VALUE = 400.0; | ||
| private static final Boolean MEASUREMENT_V_VALID = true; | ||
|
|
||
| @Override | ||
| protected Network createNetwork(UUID networkUuid) { | ||
|
|
@@ -57,6 +65,12 @@ protected ModificationInfos buildModification() { | |
| .ipMax(new AttributeModification<>(0.8, OperationType.SET)) | ||
| .ipMin(new AttributeModification<>(0.7, OperationType.SET)) | ||
| .properties(List.of(FreePropertyInfos.builder().name(PROPERTY_NAME).value(PROPERTY_VALUE).build())) | ||
| .busbarSectionVMeasurements(List.of( | ||
| BusbarSectionVMeasurementInfos.builder() | ||
| .busbarSectionId("1.1") | ||
| .vMeasurementValue(new AttributeModification<>(MEASUREMENT_V_VALUE, OperationType.SET)) | ||
| .vMeasurementValidity(new AttributeModification<>(MEASUREMENT_V_VALID, OperationType.SET)) | ||
| .build())) | ||
| .build(); | ||
| } | ||
|
|
||
|
|
@@ -71,6 +85,12 @@ protected ModificationInfos buildModificationUpdate() { | |
| .highVoltageLimit(new AttributeModification<>(55D, OperationType.SET)) | ||
| .ipMax(new AttributeModification<>(0.9, OperationType.SET)) | ||
| .ipMin(new AttributeModification<>(0.5, OperationType.SET)) | ||
| .busbarSectionVMeasurements(List.of( | ||
| BusbarSectionVMeasurementInfos.builder() | ||
| .busbarSectionId("1.1") | ||
| .vMeasurementValue(new AttributeModification<>(380D, OperationType.SET)) | ||
| .vMeasurementValidity(new AttributeModification<>(false, OperationType.SET)) | ||
| .build())) | ||
| .build(); | ||
| } | ||
|
|
||
|
|
@@ -87,6 +107,18 @@ protected void assertAfterNetworkModificationCreation() { | |
| assertEquals(0.8, identifiableShortCircuit.getIpMax(), 0); | ||
| assertEquals(0.7, identifiableShortCircuit.getIpMin(), 0); | ||
| assertEquals(PROPERTY_VALUE, getNetwork().getVoltageLevel("v1").getProperty(PROPERTY_NAME)); | ||
| assertBusbarSectionMeasurement(getNetwork().getBusbarSection("1.1"), MEASUREMENT_V_VALUE, MEASUREMENT_V_VALID); | ||
| } | ||
|
|
||
| private void assertBusbarSectionMeasurement(BusbarSection bbs, double expectedValue, boolean expectedValid) { | ||
| assertNotNull(bbs); | ||
| Measurements<?> measurements = (Measurements<?>) bbs.getExtension(Measurements.class); | ||
| assertNotNull(measurements); | ||
| Collection<Measurement> voltageMeasurements = measurements.getMeasurements(Measurement.Type.VOLTAGE).stream().toList(); | ||
| assertThat(voltageMeasurements).isNotEmpty().allSatisfy(m -> { | ||
| assertThat(m.getValue()).isEqualTo(expectedValue); | ||
| assertThat(m.isValid()).isEqualTo(expectedValid); | ||
| }); | ||
|
Comment on lines
+117
to
+121
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Assert single voltage measurement to actually validate upsert semantics. Current checks allow duplicate measurements with the same value/validity. For the update-existing path, assert cardinality is exactly 1 before validating fields. Suggested test tightening- Collection<Measurement> voltageMeasurements = measurements.getMeasurements(Measurement.Type.VOLTAGE).stream().toList();
- assertThat(voltageMeasurements).isNotEmpty().allSatisfy(m -> {
+ Collection<Measurement> voltageMeasurements = measurements.getMeasurements(Measurement.Type.VOLTAGE).stream().toList();
+ assertThat(voltageMeasurements).hasSize(1).allSatisfy(m -> {
assertThat(m.getValue()).isEqualTo(expectedValue);
assertThat(m.isValid()).isEqualTo(expectedValid);
});Also applies to: 279-300 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -243,6 +275,30 @@ void testSetIpMaxOnEquipmentWitOnlyIpMaxExtension() throws Exception { | |
| assertEquals(targetIpMax, identifiableShortCircuit1.getIpMax(), 0); | ||
| } | ||
|
|
||
| @Test | ||
| void testBusbarSectionMeasurementUpdateExistingPath() throws Exception { | ||
| // Apply first modification: adds a new voltage measurement to the BBS (add path) | ||
| applyModification((VoltageLevelModificationInfos) buildModification()); | ||
| assertBusbarSectionMeasurement(getNetwork().getBusbarSection("1.1"), MEASUREMENT_V_VALUE, MEASUREMENT_V_VALID); | ||
|
|
||
| // Apply second modification: updates the existing voltage measurement (update/upsert path) | ||
| final double updatedValue = 380.0; | ||
| final boolean updatedValidity = false; | ||
| VoltageLevelModificationInfos updateModif = VoltageLevelModificationInfos.builder() | ||
| .stashed(false) | ||
| .equipmentId("v1") | ||
| .busbarSectionVMeasurements(List.of( | ||
| BusbarSectionVMeasurementInfos.builder() | ||
| .busbarSectionId("1.1") | ||
| .vMeasurementValue(new AttributeModification<>(updatedValue, OperationType.SET)) | ||
| .vMeasurementValidity(new AttributeModification<>(updatedValidity, OperationType.SET)) | ||
| .build())) | ||
| .build(); | ||
| applyModification(updateModif); | ||
|
|
||
| assertBusbarSectionMeasurement(getNetwork().getBusbarSection("1.1"), updatedValue, updatedValidity); | ||
| } | ||
|
|
||
| private void applyModification(VoltageLevelModificationInfos infos) throws Exception { | ||
| String body = getJsonBody(infos, null); | ||
| ResultActions mockMvcResultActions = mockMvc.perform(post(getNetworkModificationUri()) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.