Skip to content
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f411ee4
add new modification MoveVoltageLevelFeederBays
EtienneLt Aug 25, 2025
a2b69bf
Merge branch 'main' into add-new-modification-MoveVoltageLevelFeederBays
EtienneLt Aug 25, 2025
7b3c860
add tests
EtienneLt Aug 25, 2025
d70059e
fix checkstyle
EtienneLt Aug 25, 2025
1e86744
more test
EtienneLt Aug 25, 2025
bb52932
fix
EtienneLt Aug 26, 2025
3a12caa
fix
EtienneLt Aug 26, 2025
4645f9e
fix checkstyle
EtienneLt Aug 26, 2025
d19a435
Merge branch 'main' into add-new-modification-MoveVoltageLevelFeederBays
EtienneLt Aug 26, 2025
f9cef7d
Merge branch 'main' into add-new-modification-MoveVoltageLevelFeederBays
EtienneLt Sep 1, 2025
f557713
fix
EtienneLt Sep 1, 2025
1481bc0
fix and add coverage
EtienneLt Sep 3, 2025
7645010
add test
EtienneLt Sep 3, 2025
2a3e8c7
code review remarks
ghazwarhili Sep 8, 2025
d01731e
Merge branch 'main' into add-new-modification-MoveVoltageLevelFeederBays
ipirog Sep 10, 2025
c92216f
Merge branch 'main' into add-new-modification-MoveVoltageLevelFeederBays
ghazwarhili Sep 14, 2025
3cb7471
fix BusbarSectionFinderTraverser
ghazwarhili Sep 14, 2025
ef32d7b
Merge branch 'main' into add-new-modification-MoveVoltageLevelFeederBays
ipirog Sep 16, 2025
1059d5f
code remarks review
ghazwarhili Sep 21, 2025
cd66318
Merge remote-tracking branch 'origin/add-new-modification-MoveVoltage…
ghazwarhili Sep 22, 2025
6f13d08
Revert all the changes about the Traverser
ghazwarhili Sep 23, 2025
9061f79
fix sonar issues
ghazwarhili Sep 23, 2025
68cb0a3
Merge branch 'main' into add-new-modification-MoveVoltageLevelFeederBays
ghazwarhili Sep 23, 2025
79fc076
code review remarks
ghazwarhili Sep 24, 2025
1527dda
Merge branch 'main' into add-new-modification-MoveVoltageLevelFeederBays
ghazwarhili Sep 24, 2025
0aac0d9
fix sonar issue
ghazwarhili Sep 24, 2025
f97c2c5
Merge remote-tracking branch 'origin/add-new-modification-MoveVoltage…
ghazwarhili Sep 24, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ public enum ModificationType {
CREATE_COUPLING_DEVICE(PreloadingStrategy.NONE),
CREATE_VOLTAGE_LEVEL_TOPOLOGY(PreloadingStrategy.NONE),
LIMIT_SETS_TABULAR_MODIFICATION(PreloadingStrategy.COLLECTION),
CREATE_VOLTAGE_LEVEL_SECTION(PreloadingStrategy.NONE);
CREATE_VOLTAGE_LEVEL_SECTION(PreloadingStrategy.NONE),
MOVE_VOLTAGE_LEVEL_FEEDER_BAYS(PreloadingStrategy.NONE);

private final PreloadingStrategy strategy;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ public enum Type {
MODIFY_VOLTAGE_LEVEL_TOPOLOGY_ERROR(HttpStatus.INTERNAL_SERVER_ERROR),
CREATE_COUPLING_DEVICE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR),
CREATE_VOLTAGE_LEVEL_TOPOLOGY_ERROR(HttpStatus.INTERNAL_SERVER_ERROR),
CREATE_VOLTAGE_LEVEL_SECTION_ERROR(HttpStatus.INTERNAL_SERVER_ERROR);
CREATE_VOLTAGE_LEVEL_SECTION_ERROR(HttpStatus.INTERNAL_SERVER_ERROR),
MOVE_VOLTAGE_LEVEL_FEEDER_BAYS_ERROR(HttpStatus.INTERNAL_SERVER_ERROR),;

public final HttpStatus status;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
@JsonSubTypes.Type(value = CreateVoltageLevelTopologyInfos.class),
@JsonSubTypes.Type(value = LimitSetsTabularModificationInfos.class),
@JsonSubTypes.Type(value = CreateVoltageLevelSectionInfos.class),
@JsonSubTypes.Type(value = MoveVoltageLevelFeederBaysInfos.class),
})
@SuperBuilder
@NoArgsConstructor
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* 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.dto;

import com.powsybl.iidm.network.extensions.ConnectablePosition;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.SuperBuilder;

/**
* @author Etienne Lesot <etienne.lesot at rte-france.com>
*/
@SuperBuilder
@NoArgsConstructor
@Getter
@ToString(callSuper = true)
@Schema(description = "Move feeder bay")
public class MoveFeederBayInfos {
@Schema(description = "Equipment id")
private String equipmentId;

@Schema(description = "busbar section id")
private String busbarSectionId;

@Schema(description = "connection side")
private String connectionSide;

@Schema(description = "connection position")
private Integer connectionPosition;

@Schema(description = "connection name")
private String connectionName;

@Schema(description = "connection direction")
private ConnectablePosition.Direction connectionDirection;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* 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.dto;

import com.fasterxml.jackson.annotation.JsonTypeName;
import com.powsybl.commons.report.ReportNode;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
import org.gridsuite.modification.dto.annotation.ModificationErrorTypeName;
import org.gridsuite.modification.modifications.AbstractModification;
import org.gridsuite.modification.modifications.MoveVoltageLevelFeederBays;

import java.util.List;
import java.util.Map;

/**
* @author Etienne Lesot <etienne.lesot at rte-france.com>
*/
@SuperBuilder
@NoArgsConstructor
@Getter
@Setter
@Schema(description = "Move voltage level feeder bays")
@JsonTypeName("MOVE_VOLTAGE_LEVEL_FEEDER_BAYS")
@ModificationErrorTypeName("MOVE_VOLTAGE_LEVEL_FEEDER_BAYS_ERROR")
public class MoveVoltageLevelFeederBaysInfos extends ModificationInfos {

@Schema(description = "Voltage level id")
private String voltageLevelId;

@Schema(description = "Feeder bays list")
private List<MoveFeederBayInfos> feederBays;

@Override
public AbstractModification toModification() {
return new MoveVoltageLevelFeederBays(this);
}

@Override
public ReportNode createSubReportNode(ReportNode reportNode) {
return reportNode.newReportNode()
.withMessageTemplate("network.modification.MOVE_VOLTAGE_LEVEL_FEEDER_BAYS")
.withUntypedValue("voltageLevelId", getVoltageLevelId())
.add();
}

@Override
public Map<String, String> getMapMessageValues() {
return Map.of("voltageLevelId", getVoltageLevelId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ private ReportNode modifyBranchConnectivityAttributes(BranchModificationInfos br

private void modifyBranchVoltageLevelBusOrBusBarSectionAttributesSide1(BranchModificationInfos modificationInfos,
Branch<?> branch, ReportNode subReportNode) {
ModificationUtils.getInstance().modifyVoltageLevelBusOrBusBarSectionAttributes(
ModificationUtils.getInstance().moveFeederBay(
(Connectable<?>) branch, branch.getTerminal1(),
modificationInfos.getVoltageLevelId1(),
modificationInfos.getBusOrBusbarSectionId1(),
Expand All @@ -605,7 +605,7 @@ private void modifyBranchVoltageLevelBusOrBusBarSectionAttributesSide1(BranchMod

private void modifyBranchVoltageLevelBusOrBusBarSectionAttributesSide2(BranchModificationInfos modificationInfos,
Branch<?> branch, ReportNode subReportNode) {
ModificationUtils.getInstance().modifyVoltageLevelBusOrBusBarSectionAttributes(
ModificationUtils.getInstance().moveFeederBay(
(Connectable<?>) branch, branch.getTerminal2(),
modificationInfos.getVoltageLevelId2(),
modificationInfos.getBusOrBusbarSectionId2(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public static void modifyBatterySetpointsAttributes(AttributeModification<Double

private void modifyBatteryVoltageLevelBusOrBusBarSectionAttributes(BatteryModificationInfos modificationInfos,
Battery battery, ReportNode subReportNode) {
ModificationUtils.getInstance().modifyVoltageLevelBusOrBusBarSectionAttributes(
ModificationUtils.getInstance().moveFeederBay(
battery, battery.getTerminal(),
modificationInfos.getVoltageLevelId(),
modificationInfos.getBusOrBusbarSectionId(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ private void modifyGeneratorLimitsAttributes(GeneratorModificationInfos modifica

private void modifyGeneratorVoltageLevelBusOrBusBarSectionAttributes(GeneratorModificationInfos modificationInfos,
Generator generator, ReportNode subReportNode) {
ModificationUtils.getInstance().modifyVoltageLevelBusOrBusBarSectionAttributes(
ModificationUtils.getInstance().moveFeederBay(
generator, generator.getTerminal(),
modificationInfos.getVoltageLevelId(),
modificationInfos.getBusOrBusbarSectionId(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public static void modifyP0(Load load, AttributeModification<Double> p0, ReportN

private void modifyLoadVoltageLevelBusOrBusBarSectionAttributes(LoadModificationInfos modificationInfos,
Load load, ReportNode subReportNode) {
ModificationUtils.getInstance().modifyVoltageLevelBusOrBusBarSectionAttributes(
ModificationUtils.getInstance().moveFeederBay(
load, load.getTerminal(),
modificationInfos.getVoltageLevelId(),
modificationInfos.getBusOrBusbarSectionId(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/**
* 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.modifications;

import com.powsybl.commons.report.ReportNode;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.ConnectablePosition;
import com.powsybl.iidm.network.extensions.ConnectablePositionAdder;
import org.gridsuite.modification.ModificationType;
import org.gridsuite.modification.NetworkModificationException;
import org.gridsuite.modification.dto.*;
import org.gridsuite.modification.utils.ModificationUtils;

import static org.gridsuite.modification.NetworkModificationException.Type.MOVE_VOLTAGE_LEVEL_FEEDER_BAYS_ERROR;

/**
* @author Etienne Lesot <etienne.lesot at rte-france.com>
*/
public class MoveVoltageLevelFeederBays extends AbstractModification {
private static final String VOLTAGE_LEVEL_NOT_FOUND = "Voltage level %s is not found";
private static final String CONNECTABLE_NOT_FOUND = "Connectable %s not found";
private static final String BUSBAR_NOT_FOUND = "Bus or busbar section %s where connectable %s is supposed to be is not found in voltage level %s";
private static final String UNSUPPORTED_CONNECTABLE = "MoveVoltageLevelFeederBays is not implemented for %s";
private static final String INVALID_CONNECTION_SIDE = "Invalid connection side: %s for branch %s";

private final MoveVoltageLevelFeederBaysInfos modificationInfos;

public MoveVoltageLevelFeederBays(MoveVoltageLevelFeederBaysInfos modificationInfos) {
this.modificationInfos = modificationInfos;
}

@Override
public void check(Network network) throws NetworkModificationException {
VoltageLevel voltageLevel = getVoltageLevelOrThrow(network, modificationInfos.getVoltageLevelId());
for (MoveFeederBayInfos info : modificationInfos.getFeederBays()) {
checkBusOrBusbarSectionExist(voltageLevel, info);
checkConnectable(network, info);
}
}

private VoltageLevel getVoltageLevelOrThrow(Network network, String voltageLevelId) {
VoltageLevel voltageLevel = network.getVoltageLevel(voltageLevelId);
if (voltageLevel == null) {
throw new NetworkModificationException(MOVE_VOLTAGE_LEVEL_FEEDER_BAYS_ERROR, String.format(VOLTAGE_LEVEL_NOT_FOUND, voltageLevelId));
}
return voltageLevel;
}

private void checkBusOrBusbarSectionExist(VoltageLevel voltageLevel, MoveFeederBayInfos info) {
boolean busOrBusbarSectionExists = voltageLevel.getTopologyKind().equals(TopologyKind.NODE_BREAKER)
? voltageLevel.getNodeBreakerView().getBusbarSection(info.getBusbarSectionId()) != null
: voltageLevel.getBusBreakerView().getBus(info.getBusbarSectionId()) != null;
if (!busOrBusbarSectionExists) {
throw new NetworkModificationException(MOVE_VOLTAGE_LEVEL_FEEDER_BAYS_ERROR, String.format(BUSBAR_NOT_FOUND,
info.getBusbarSectionId(), info.getEquipmentId(), modificationInfos.getVoltageLevelId()));
}
}

private void checkConnectable(Network network, MoveFeederBayInfos info) {
Connectable<?> connectable = network.getConnectable(info.getEquipmentId());
if (connectable == null) {
throw new NetworkModificationException(MOVE_VOLTAGE_LEVEL_FEEDER_BAYS_ERROR, String.format(CONNECTABLE_NOT_FOUND, info.getEquipmentId()));
}
if (connectable instanceof BusbarSection || connectable instanceof ThreeWindingsTransformer) {
throw new NetworkModificationException(MOVE_VOLTAGE_LEVEL_FEEDER_BAYS_ERROR, String.format(UNSUPPORTED_CONNECTABLE, connectable.getClass()));
}
}

@Override
public void apply(Network network, ReportNode subReportNode) {
for (MoveFeederBayInfos info : modificationInfos.getFeederBays()) {
Connectable<?> connectable = network.getConnectable(info.getEquipmentId());
modifyConnectablePosition(network, connectable, info, subReportNode);
}
}

@Override
public String getName() {
return ModificationType.MOVE_VOLTAGE_LEVEL_FEEDER_BAYS.name();
}

private void modifyConnectablePosition(Network network, Connectable<?> connectable, MoveFeederBayInfos newConnectablePositionInfos, ReportNode subReportNode) {
ConnectablePosition<?> oldConnectablePosition = (ConnectablePosition<?>) connectable.getExtension(ConnectablePosition.class);
ConnectablePositionAdder<?> connectablePositionAdder = connectable.newExtension(ConnectablePositionAdder.class);

switch (connectable) {
case Injection<?> injection -> {
InjectionModificationInfos injectionModificationInfos = buildInjectionModificationInfos(newConnectablePositionInfos);
ModificationUtils.getInstance().modifyInjectionConnectivityAttributes(oldConnectablePosition, connectablePositionAdder, injection, injectionModificationInfos, subReportNode);
}
case Branch<?> branch -> {
BranchModificationInfos branchModificationInfos = buildBranchModificationInfos(newConnectablePositionInfos);
ModificationUtils.getInstance().modifyBranchConnectivityAttributes(oldConnectablePosition, connectablePositionAdder, branch, branchModificationInfos, subReportNode);
}
default -> {
throw new NetworkModificationException(MOVE_VOLTAGE_LEVEL_FEEDER_BAYS_ERROR, String.format(UNSUPPORTED_CONNECTABLE, connectable.getClass()));
}
}
moveFeederBay(network, connectable, newConnectablePositionInfos, subReportNode);
}

private InjectionModificationInfos buildInjectionModificationInfos(MoveFeederBayInfos newConnectablePositionInfos) {
InjectionModificationInfos injectionInfos = new InjectionModificationInfos();
injectionInfos.setEquipmentId(newConnectablePositionInfos.getEquipmentId());
setConnectionAttributes(injectionInfos::setConnectionPosition,
injectionInfos::setConnectionName,
injectionInfos::setConnectionDirection,
newConnectablePositionInfos);
return injectionInfos;
}

private BranchModificationInfos buildBranchModificationInfos(MoveFeederBayInfos info) {
BranchModificationInfos branchInfos = new BranchModificationInfos();
branchInfos.setEquipmentId(info.getEquipmentId());
ThreeSides connectionSide = ThreeSides.valueOf(info.getConnectionSide());
switch (connectionSide) {
case ONE -> setConnectionAttributes(branchInfos::setConnectionPosition1,
branchInfos::setConnectionName1,
branchInfos::setConnectionDirection1,
info);
case TWO -> setConnectionAttributes(branchInfos::setConnectionPosition2,
branchInfos::setConnectionName2,
branchInfos::setConnectionDirection2,
info);
default -> throw new NetworkModificationException(MOVE_VOLTAGE_LEVEL_FEEDER_BAYS_ERROR, String.format(INVALID_CONNECTION_SIDE, info.getConnectionSide(), branchInfos.getEquipmentId()));
}
return branchInfos;
}

private void setConnectionAttributes(java.util.function.Consumer<AttributeModification<Integer>> setPosition,
java.util.function.Consumer<AttributeModification<String>> setName,
java.util.function.Consumer<AttributeModification<ConnectablePosition.Direction>> setDirection,
MoveFeederBayInfos info) {
setPosition.accept(new AttributeModification<>(info.getConnectionPosition(), OperationType.SET));
setName.accept(new AttributeModification<>(info.getConnectionName(), OperationType.SET));
setDirection.accept(new AttributeModification<>(info.getConnectionDirection(), OperationType.SET));
}

private void moveFeederBay(Network network, Connectable<?> connectable, MoveFeederBayInfos info, ReportNode subReportNode) {
Terminal terminal = getTerminal(network, info);
String currentBusbarId = ModificationUtils.getInstance().getBusOrBusbarSection(terminal);
String targetBusbarId = info.getBusbarSectionId();
if (!currentBusbarId.equals(targetBusbarId)) {
ModificationUtils.getInstance().moveFeederBay(
connectable, terminal,
new AttributeModification<>(modificationInfos.getVoltageLevelId(), OperationType.SET),
new AttributeModification<>(targetBusbarId, OperationType.SET),
subReportNode);
}
}

public Terminal getTerminal(Network network, MoveFeederBayInfos info) {
Connectable<?> connectable = network.getConnectable(info.getEquipmentId());
return switch (connectable) {
case Injection<?> injection -> injection.getTerminal();
case Branch<?> branch -> {
try {
TwoSides side = TwoSides.valueOf(info.getConnectionSide());
yield branch.getTerminal(side);
} catch (IllegalArgumentException e) {
throw new NetworkModificationException(MOVE_VOLTAGE_LEVEL_FEEDER_BAYS_ERROR,
String.format(INVALID_CONNECTION_SIDE, info.getConnectionSide(), branch.getId()));
}
}
default -> throw new NetworkModificationException(MOVE_VOLTAGE_LEVEL_FEEDER_BAYS_ERROR, String.format(UNSUPPORTED_CONNECTABLE, connectable.getClass()));
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ private void reportSwitchedOnAndPerSectionValues(List<ReportNode> reports, doubl

private void modifyShuntCompensatorVoltageLevelBusOrBusBarSectionAttributes(ShuntCompensatorModificationInfos modificationInfos,
ShuntCompensator shuntCompensator, ReportNode subReportNode) {
ModificationUtils.getInstance().modifyVoltageLevelBusOrBusBarSectionAttributes(
ModificationUtils.getInstance().moveFeederBay(
shuntCompensator, shuntCompensator.getTerminal(),
modificationInfos.getVoltageLevelId(),
modificationInfos.getBusOrBusbarSectionId(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1862,10 +1862,10 @@ private boolean isNotModificationVoltageLevelBusOrBusBarInfos(AttributeModificat
Optional.ofNullable(busOrBusbarSectionId).map(AttributeModification::getValue).isEmpty();
}

public void modifyVoltageLevelBusOrBusBarSectionAttributes(Connectable<?> connectable, Terminal terminal,
AttributeModification<String> voltageLevelId,
AttributeModification<String> busOrBusbarSectionId,
ReportNode subReportNode) {
public void moveFeederBay(Connectable<?> connectable, Terminal terminal,
AttributeModification<String> voltageLevelId,
AttributeModification<String> busOrBusbarSectionId,
ReportNode subReportNode) {
if (isNotModificationVoltageLevelBusOrBusBarInfos(voltageLevelId, busOrBusbarSectionId)) {
return;
}
Expand Down
Loading