Skip to content

add voltage level topology modification #628

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

Merged
merged 8 commits into from
May 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
<mockwebserver3.version>5.0.0-alpha.14</mockwebserver3.version>
<liquibase-hibernate-package>org.gridsuite.modification.server</liquibase-hibernate-package>
<sonar.coverage.exclusions>**/migration/**/*</sonar.coverage.exclusions>
<network-modification.version>0.13.0</network-modification.version>
<network-modification.version>0.14.0</network-modification.version>
<!-- FIXME: powsybl-network-store modules'version is overloaded in the dependencies section.The overloads and this property below have to be removed at next powsybl-ws-dependencies.version upgrade -->
<powsybl-network-store.version>1.24.0</powsybl-network-store.version>
<sonar.organization>gridsuite</sonar.organization>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ private EntityRegistry() {
register(ByFormulaModificationInfos.class, ByFormulaModificationEntity.class);
register(ModificationByAssignmentInfos.class, ModificationByAssignmentEntity.class);
register(EquipmentAttributeModificationInfos.class, EquipmentAttributeModificationEntity.class);
register(VoltageLevelTopologyModificationInfos.class, VoltageLevelTopologyModificationEntity.class);

// // attatching and splitting
register(LineAttachToVoltageLevelInfos.class, LineAttachToVoltageLevelEntity.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/**
* 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 org.gridsuite.modification.server.entities.equipment.modification;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import org.gridsuite.modification.dto.ModificationInfos;
import org.gridsuite.modification.dto.VoltageLevelTopologyModificationInfos;
import org.gridsuite.modification.server.entities.equipment.modification.attribute.BooleanEquipmentAttributeModificationEntity;
import org.gridsuite.modification.server.entities.equipment.modification.attribute.EquipmentAttributeModificationEntity;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
* @author REHILI Ghazwa <[email protected]>
*/

@NoArgsConstructor
@Getter
@Entity
@Table(name = "voltage_level_topology_modification")
@PrimaryKeyJoinColumn(foreignKey = @ForeignKey(name = "voltageLevelTopologyModification_id_fk_constraint"))
public class VoltageLevelTopologyModificationEntity extends EquipmentModificationEntity {

@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@JoinColumn(
name = "voltage_level_topology_modification_id",
referencedColumnName = "id",
foreignKey = @ForeignKey(
name = "voltageLevelTopologyModification_booleanEquipmentAttributeModification_fk"
))
@OrderBy
private List<BooleanEquipmentAttributeModificationEntity> equipmentAttributeModification;

public VoltageLevelTopologyModificationEntity(VoltageLevelTopologyModificationInfos voltageLevelTopologyModificationInfos) {
super(voltageLevelTopologyModificationInfos);
assignAttributes(voltageLevelTopologyModificationInfos);
}

@Override
public void update(@NonNull ModificationInfos modificationInfos) {
super.update(modificationInfos);
assignAttributes((VoltageLevelTopologyModificationInfos) modificationInfos);
}

private void assignAttributes(VoltageLevelTopologyModificationInfos voltageLevelTopologyModificationInfos) {
// Initialize the collection if it's null
if (this.equipmentAttributeModification == null) {
this.equipmentAttributeModification = new ArrayList<>();
} else {
this.equipmentAttributeModification.clear();
}

// Add new entities to the existing collection
if (voltageLevelTopologyModificationInfos.getEquipmentAttributeModificationList() != null) {
List<BooleanEquipmentAttributeModificationEntity> newEntities =
voltageLevelTopologyModificationInfos.getEquipmentAttributeModificationList().stream()
.map(BooleanEquipmentAttributeModificationEntity::new)
.toList();

this.equipmentAttributeModification.addAll(newEntities);
}
}

@Override
public VoltageLevelTopologyModificationInfos toModificationInfos() {
return toVoltageLevelTopologyModificationInfosBuilder().build();
}

private VoltageLevelTopologyModificationInfos.VoltageLevelTopologyModificationInfosBuilder<?, ?> toVoltageLevelTopologyModificationInfosBuilder() {
List<BooleanEquipmentAttributeModificationEntity> attributeModificationEntities = getEquipmentAttributeModification();
return VoltageLevelTopologyModificationInfos.builder()
.uuid(getId())
.equipmentId(getEquipmentId())
.date(getDate())
.stashed(getStashed())
.activated(getActivated())
.equipmentAttributeModificationList(Optional.ofNullable(attributeModificationEntities)
.map(list -> list.stream()
.map(EquipmentAttributeModificationEntity::toModificationInfos)
.toList())
.orElse(null));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet author="rehiligha (generated)" id="1745319776062-25">
<createTable tableName="voltage_level_topology_modification">
<column name="equipment_id" type="VARCHAR(255)"/>
<column name="id" type="UUID">
<constraints nullable="false" primaryKey="true" primaryKeyName="voltage_level_topology_modificationPK"/>
</column>
</createTable>
</changeSet>
<changeSet author="rehiligha (generated)" id="1745319776062-26">
<addColumn tableName="boolean_equipment_attribute_modification">
<column name="voltage_level_topology_modification_id" type="uuid"/>
</addColumn>
</changeSet>
<changeSet author="rehiligha (generated)" id="1745319776062-44">
<addForeignKeyConstraint baseColumnNames="id" baseTableName="voltage_level_topology_modification" constraintName="voltageLevelTopologyModification_id_fk_constraint" deferrable="false" initiallyDeferred="false" referencedColumnNames="id" referencedTableName="modification" validate="true"/>
</changeSet>
<changeSet author="rehiligha (generated)" id="1745319776062-45">
<addForeignKeyConstraint baseColumnNames="voltage_level_topology_modification_id" baseTableName="boolean_equipment_attribute_modification" constraintName="voltageLevelTopologyModification_booleanEquipmentAttributeModification_fk" deferrable="false" initiallyDeferred="false" referencedColumnNames="id" referencedTableName="voltage_level_topology_modification" validate="true"/>
</changeSet>
</databaseChangeLog>
3 changes: 3 additions & 0 deletions src/main/resources/db/changelog/db.changelog-master.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -351,3 +351,6 @@ databaseChangeLog:
- include:
file: changesets/changelog_20250430T135010Z.xml
relativeToChangelogFile: true
- include:
file: changesets/changelog_20250422T110241Z.xml
relativeToChangelogFile: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
/**
* 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 org.gridsuite.modification.server.modifications;

import com.fasterxml.jackson.core.type.TypeReference;
import com.powsybl.iidm.network.IdentifiableType;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.Switch;
import com.powsybl.iidm.network.VoltageLevel;
import org.gridsuite.modification.dto.EquipmentAttributeModificationInfos;
import org.gridsuite.modification.dto.ModificationInfos;
import org.gridsuite.modification.dto.VoltageLevelTopologyModificationInfos;
import org.gridsuite.modification.server.utils.NetworkCreation;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;

import java.util.*;

import static org.junit.jupiter.api.Assertions.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

/**
* @author REHILI Ghazwa <[email protected]>
*/
@Tag("IntegrationTest")
class VoltageLevelTopologyModificationTest extends AbstractNetworkModificationTest {

@Override
protected Network createNetwork(UUID networkUuid) {
return NetworkCreation.create(networkUuid, true);
}

@Override
protected ModificationInfos buildModification() {
List<EquipmentAttributeModificationInfos> equipmentAttributeModificationInfos = new ArrayList<>(
Arrays.asList(
EquipmentAttributeModificationInfos.builder()
.equipmentId("v1d1")
.equipmentAttributeName("open")
.equipmentAttributeValue(false)
.equipmentType(IdentifiableType.SWITCH)
.build(),
EquipmentAttributeModificationInfos.builder()
.equipmentId("v1b1")
.equipmentAttributeName("open")
.equipmentAttributeValue(false)
.equipmentType(IdentifiableType.SWITCH)
.build(),
EquipmentAttributeModificationInfos.builder()
.equipmentId("v1blcc")
.equipmentAttributeName("open")
.equipmentAttributeValue(false)
.equipmentType(IdentifiableType.SWITCH)
.build(),
EquipmentAttributeModificationInfos.builder()
.equipmentId("v1dlcc")
.equipmentAttributeName("open")
.equipmentAttributeValue(false)
.equipmentType(IdentifiableType.SWITCH)
.build()
)
);
return VoltageLevelTopologyModificationInfos.builder()
.stashed(false)
.activated(true)
.equipmentId("v1")
.equipmentAttributeModificationList(equipmentAttributeModificationInfos)
.build();
}

@Override
protected ModificationInfos buildModificationUpdate() {
List<EquipmentAttributeModificationInfos> equipmentAttributeModificationInfos = new ArrayList<>(
Arrays.asList(
EquipmentAttributeModificationInfos.builder()
.equipmentId("v1d1")
.equipmentAttributeName("open")
.equipmentAttributeValue(true)
.equipmentType(IdentifiableType.SWITCH)
.build(),
EquipmentAttributeModificationInfos.builder()
.equipmentId("v1b1")
.equipmentAttributeName("open")
.equipmentAttributeValue(true)
.equipmentType(IdentifiableType.SWITCH)
.build()
)
);
return VoltageLevelTopologyModificationInfos.builder()
.stashed(false)
.activated(true)
.equipmentId("v1")
.equipmentAttributeModificationList(equipmentAttributeModificationInfos)
.build();
}

@Override
protected void assertAfterNetworkModificationCreation() {
VoltageLevel voltageLevel = getNetwork().getVoltageLevel("v1");
assertNotNull(voltageLevel);

Switch switch1 = getNetwork().getSwitch("v1d1");
assertNotNull(switch1);
assertFalse(switch1.isOpen());

Switch switch2 = getNetwork().getSwitch("v1b1");
assertNotNull(switch2);
assertFalse(switch2.isOpen());

Switch switch3 = getNetwork().getSwitch("v1blcc");
assertNotNull(switch3);
assertFalse(switch3.isOpen());

Switch switch4 = getNetwork().getSwitch("v1dlcc");
assertNotNull(switch4);
assertFalse(switch4.isOpen());
}

@Override
protected void assertAfterNetworkModificationDeletion() {
VoltageLevel voltageLevel = getNetwork().getVoltageLevel("v1");
assertNotNull(voltageLevel);

Switch switch1 = getNetwork().getSwitch("v1d1");
assertNotNull(switch1);
assertFalse(switch1.isOpen());

Switch switch2 = getNetwork().getSwitch("v1b1");
assertNotNull(switch2);
assertFalse(switch2.isOpen());

Switch switch3 = getNetwork().getSwitch("v1blcc");
assertNotNull(switch3);
assertFalse(switch3.isOpen());

Switch switch4 = getNetwork().getSwitch("v1dlcc");
assertNotNull(switch4);
assertFalse(switch4.isOpen());
}

@Test
void testInvalidVoltageLevel() throws Exception {
VoltageLevelTopologyModificationInfos infos = VoltageLevelTopologyModificationInfos.builder()
.stashed(false)
.activated(true)
.equipmentId("nonexistent_vl")
.equipmentAttributeModificationList(List.of())
.build();

String body = getJsonBody(infos, null);
mockMvc.perform(post(getNetworkModificationUri())
.content(body)
.contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andReturn();
}

@Test
void testEmptyModifications() throws Exception {
List<EquipmentAttributeModificationInfos> emptyModifications = new ArrayList<>();

VoltageLevelTopologyModificationInfos infos = VoltageLevelTopologyModificationInfos.builder()
.stashed(false)
.activated(true)
.equipmentId("v1")
.equipmentAttributeModificationList(emptyModifications)
.build();

String body = getJsonBody(infos, null);
mockMvc.perform(post(getNetworkModificationUri())
.content(body)
.contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andReturn();
}

@Test
void testNonExistentSwitch() throws Exception {
List<EquipmentAttributeModificationInfos> equipmentAttributeModificationInfos = new ArrayList<>(
Arrays.asList(
EquipmentAttributeModificationInfos.builder()
.equipmentId("nonexistent_switch")
.equipmentAttributeName("open")
.equipmentAttributeValue(false)
.equipmentType(IdentifiableType.SWITCH)
.build()
)
);

VoltageLevelTopologyModificationInfos infos = VoltageLevelTopologyModificationInfos.builder()
.stashed(false)
.equipmentId("v1")
.equipmentAttributeModificationList(equipmentAttributeModificationInfos)
.build();

String body = getJsonBody(infos, null);
mockMvc.perform(post(getNetworkModificationUri())
.content(body)
.contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andReturn();
}

@Override
protected void testCreationModificationMessage(ModificationInfos modificationInfos) throws Exception {
assertEquals("VOLTAGE_LEVEL_TOPOLOGY_MODIFICATION", modificationInfos.getMessageType());
Map<String, String> createdValues = mapper.readValue(modificationInfos.getMessageValues(), new TypeReference<>() { });
assertEquals("v1", createdValues.get("equipmentId"));
}

@Override
protected void testUpdateModificationMessage(ModificationInfos modificationInfos) throws Exception {
assertEquals("VOLTAGE_LEVEL_TOPOLOGY_MODIFICATION", modificationInfos.getMessageType());
Map<String, String> updatedValues = mapper.readValue(modificationInfos.getMessageValues(), new TypeReference<>() { });
assertEquals("v1", updatedValues.get("equipmentId"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1352,4 +1352,28 @@ void testStaticVarCompensatorCreation() {
assertThrows(NetworkModificationException.class, () -> networkModificationRepository.getModifications(TEST_GROUP_ID, true, true),
new NetworkModificationException(MODIFICATION_GROUP_NOT_FOUND, TEST_GROUP_ID.toString()).getMessage());
}

@Test
void testVoltageLevelTopologyModification() {
List<EquipmentAttributeModificationInfos> equipmentAttributeModificationInfos = new ArrayList<>(
Arrays.asList(
EquipmentAttributeModificationInfos.builder()
.equipmentId("sw1")
.equipmentAttributeName("open")
.equipmentAttributeValue(false)
.equipmentType(IdentifiableType.SWITCH)
.build()
)
);
var voltageLevelTopologyModificationEntity = ModificationEntity.fromDTO(VoltageLevelTopologyModificationInfos.builder()
.equipmentId("VL1")
.equipmentAttributeModificationList(equipmentAttributeModificationInfos)
.build());

networkModificationRepository.saveModifications(TEST_GROUP_ID, List.of(voltageLevelTopologyModificationEntity));
assertRequestsCount(2, 5, 1, 0);

List<ModificationInfos> modificationInfos = networkModificationRepository.getModifications(TEST_GROUP_ID, true, true);
assertEquals(1, modificationInfos.size());
}
}