-
Notifications
You must be signed in to change notification settings - Fork 0
add new modification MoveVoltageLevelFeederBays #87
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
base: main
Are you sure you want to change the base?
Changes from all commits
f411ee4
a2b69bf
7b3c860
d70059e
1e86744
bb52932
3a12caa
4645f9e
d19a435
f9cef7d
f557713
1481bc0
7645010
2a3e8c7
d01731e
c92216f
3cb7471
ef32d7b
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,44 @@ | ||
/** | ||
* 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.Setter; | ||
import lombok.ToString; | ||
import lombok.experimental.SuperBuilder; | ||
|
||
/** | ||
* @author Etienne Lesot <etienne.lesot at rte-france.com> | ||
*/ | ||
@SuperBuilder | ||
@NoArgsConstructor | ||
@Getter | ||
@Setter | ||
@ToString(callSuper = true) | ||
@Schema(description = "Connectable position modification") | ||
public class ConnectablePositionModificationInfos { | ||
@Schema(description = "Connectable 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<ConnectablePositionModificationInfos> feederBaysAttributeList; | ||||||
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.
Suggested change
|
||||||
|
||||||
@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 |
---|---|---|
|
@@ -8,42 +8,83 @@ | |
|
||
import com.powsybl.iidm.network.IdentifiableType; | ||
import com.powsybl.iidm.network.Switch; | ||
import com.powsybl.iidm.network.SwitchKind; | ||
import com.powsybl.iidm.network.Terminal; | ||
import com.powsybl.math.graph.TraverseResult; | ||
import lombok.Getter; | ||
|
||
import java.util.ArrayList; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Set; | ||
|
||
/** | ||
* @author Slimane Amar <slimane.amar at rte-france.com> | ||
*/ | ||
// FIXME : to remove when this class is available in network-store | ||
public class BusbarSectionFinderTraverser implements Terminal.TopologyTraverser { | ||
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. Move those changes in another PR. So the review can be done with gridsuite/network-map-server#288. And the changes in the tests will be reviewed with it |
||
|
||
private final boolean onlyConnectedBbs; | ||
|
||
private String firstTraversedBbsId; | ||
|
||
public BusbarSectionFinderTraverser(boolean onlyConnectedBbs) { | ||
this.onlyConnectedBbs = onlyConnectedBbs; | ||
} | ||
private final List<BusbarCandidate> busbarCandidates = new ArrayList<>(); | ||
private final Set<String> visitedTerminals = new HashSet<>(); | ||
private static final int MAX_VISITED = 50; | ||
|
||
@Override | ||
public TraverseResult traverse(Terminal terminal, boolean connected) { | ||
if (terminal.getConnectable().getType() == IdentifiableType.BUSBAR_SECTION) { | ||
firstTraversedBbsId = terminal.getConnectable().getId(); | ||
String terminalId = terminal.getConnectable().getId(); | ||
if (visitedTerminals.contains(terminalId)) { | ||
return TraverseResult.TERMINATE_PATH; | ||
} | ||
visitedTerminals.add(terminalId); | ||
if (visitedTerminals.size() > MAX_VISITED) { | ||
return TraverseResult.TERMINATE_TRAVERSER; | ||
} | ||
|
||
// If a busbar section is found, add it as a candidate | ||
if (terminal.getConnectable().getType() == IdentifiableType.BUSBAR_SECTION) { | ||
busbarCandidates.add(new BusbarCandidate(terminalId, connected)); | ||
// CONTINUE to explore other paths to other busbars | ||
return TraverseResult.CONTINUE; | ||
} | ||
return TraverseResult.CONTINUE; | ||
} | ||
|
||
@Override | ||
public TraverseResult traverse(Switch aSwitch) { | ||
if (onlyConnectedBbs && aSwitch.isOpen()) { | ||
return TraverseResult.TERMINATE_PATH; | ||
if (visitedTerminals.size() > MAX_VISITED) { | ||
return TraverseResult.TERMINATE_TRAVERSER; | ||
} | ||
|
||
// KEY: Open disconnectors end this path but not the overall traversal | ||
// They block access to this busbar but not to the others | ||
if (aSwitch.isOpen() && aSwitch.getKind() == SwitchKind.DISCONNECTOR) { | ||
return TraverseResult.TERMINATE_PATH; // Ends this path, not the whole traversal | ||
} | ||
return TraverseResult.CONTINUE; | ||
} | ||
|
||
public String getFirstTraversedBbsId() { | ||
return firstTraversedBbsId; | ||
public String getBusbarWithClosedDisconnector() { | ||
// Search for a connected busbar (disconnector closed) | ||
for (BusbarCandidate candidate : busbarCandidates) { | ||
if (candidate.isConnected()) { | ||
return candidate.getId(); | ||
} | ||
} | ||
|
||
// If none is connected, return the first one found (fallback) | ||
if (!busbarCandidates.isEmpty()) { | ||
return busbarCandidates.getFirst().getId(); | ||
} | ||
return null; | ||
} | ||
} | ||
|
||
@Getter | ||
private static class BusbarCandidate { | ||
private final String id; | ||
private final boolean connected; | ||
|
||
public BusbarCandidate(String id, boolean connected) { | ||
this.id = id; | ||
this.connected = connected; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,165 @@ | ||||||
/** | ||||||
* 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 = "ConnectablePositionModification 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 = checkVoltageLevelOrThrow(network, modificationInfos.getVoltageLevelId()); | ||||||
for (ConnectablePositionModificationInfos info : modificationInfos.getFeederBaysAttributeList()) { | ||||||
checkBusOrBusbarSection(voltageLevel, info); | ||||||
checkConnectable(network, info); | ||||||
} | ||||||
} | ||||||
|
||||||
private VoltageLevel checkVoltageLevelOrThrow(Network network, String voltageLevelId) { | ||||||
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.
Suggested change
|
||||||
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 checkBusOrBusbarSection(VoltageLevel voltageLevel, ConnectablePositionModificationInfos info) { | ||||||
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.
Suggested change
|
||||||
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, ConnectablePositionModificationInfos 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 Injection<?>) && !(connectable instanceof Branch<?>)) { | ||||||
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. Do we need this ? 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. And it excudes 3WT 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. We should rather exclude busbarSection as it is done in MoveFeederBay. Something like : |
||||||
throw new NetworkModificationException(MOVE_VOLTAGE_LEVEL_FEEDER_BAYS_ERROR, String.format(UNSUPPORTED_CONNECTABLE, connectable.getClass())); | ||||||
} | ||||||
} | ||||||
|
||||||
@Override | ||||||
public void apply(Network network, ReportNode subReportNode) { | ||||||
for (ConnectablePositionModificationInfos info : modificationInfos.getFeederBaysAttributeList()) { | ||||||
Connectable<?> connectable = network.getConnectable(info.getEquipmentId()); | ||||||
switch (connectable) { | ||||||
case Injection<?> injection -> modifyInjectionConnectablePosition(network, injection, info, subReportNode); | ||||||
case Branch<?> branch -> modifyBranchConnectablePosition(network, branch, info, subReportNode); | ||||||
default -> throw new NetworkModificationException(MOVE_VOLTAGE_LEVEL_FEEDER_BAYS_ERROR, String.format(UNSUPPORTED_CONNECTABLE, connectable.getClass())); | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
@Override | ||||||
public String getName() { | ||||||
return ModificationType.MOVE_VOLTAGE_LEVEL_FEEDER_BAYS.name(); | ||||||
} | ||||||
|
||||||
private void modifyInjectionConnectablePosition(Network network, Injection<?> injection, ConnectablePositionModificationInfos info, ReportNode subReportNode) { | ||||||
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. modifyInjectionConnectablePosition and modifyBranchConnectablePosition should be one method modifyConnectablePosition(). 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.
Suggested change
|
||||||
ConnectablePosition connectablePosition = injection.getExtension(ConnectablePosition.class); | ||||||
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.
Suggested change
|
||||||
ConnectablePositionAdder connectablePositionAdder = injection.newExtension(ConnectablePositionAdder.class); | ||||||
InjectionModificationInfos injectionModificationInfos = buildInjectionModificationInfos(info); | ||||||
ModificationUtils.getInstance().modifyInjectionConnectivityAttributes(connectablePosition, connectablePositionAdder, injection, injectionModificationInfos, subReportNode); | ||||||
moveVoltageLevelBusOrBusbarSection(network, injection, info, subReportNode); | ||||||
} | ||||||
|
||||||
private void modifyBranchConnectablePosition(Network network, Branch<?> branch, ConnectablePositionModificationInfos info, ReportNode subReportNode) { | ||||||
ConnectablePosition connectablePosition = branch.getExtension(ConnectablePosition.class); | ||||||
ConnectablePositionAdder connectablePositionAdder = branch.newExtension(ConnectablePositionAdder.class); | ||||||
BranchModificationInfos branchModificationInfos = buildBranchModificationInfos(info); | ||||||
ModificationUtils.getInstance().modifyBranchConnectivityAttributes(connectablePosition, connectablePositionAdder, branch, branchModificationInfos, subReportNode); | ||||||
moveVoltageLevelBusOrBusbarSection(network, (Connectable<?>) branch, info, subReportNode); | ||||||
} | ||||||
|
||||||
private InjectionModificationInfos buildInjectionModificationInfos(ConnectablePositionModificationInfos info) { | ||||||
InjectionModificationInfos injectionInfos = new InjectionModificationInfos(); | ||||||
injectionInfos.setEquipmentId(info.getEquipmentId()); | ||||||
injectionInfos.setConnectionPosition(new AttributeModification<>(info.getConnectionPosition(), OperationType.SET)); | ||||||
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. Those 3 rows can be a method. And the method used here and in buildBranchModificationInfos() |
||||||
injectionInfos.setConnectionName(new AttributeModification<>(info.getConnectionName(), OperationType.SET)); | ||||||
injectionInfos.setConnectionDirection(new AttributeModification<>(info.getConnectionDirection(), OperationType.SET)); | ||||||
return injectionInfos; | ||||||
} | ||||||
|
||||||
private BranchModificationInfos buildBranchModificationInfos(ConnectablePositionModificationInfos info) { | ||||||
BranchModificationInfos branchInfos = new BranchModificationInfos(); | ||||||
branchInfos.setEquipmentId(info.getEquipmentId()); | ||||||
|
||||||
ThreeSides connectionSide = ThreeSides.valueOf(info.getConnectionSide()); | ||||||
switch (connectionSide) { | ||||||
case ONE -> { | ||||||
branchInfos.setConnectionPosition1(new AttributeModification<>(info.getConnectionPosition(), OperationType.SET)); | ||||||
branchInfos.setConnectionName1(new AttributeModification<>(info.getConnectionName(), OperationType.SET)); | ||||||
branchInfos.setConnectionDirection1(new AttributeModification<>(info.getConnectionDirection(), OperationType.SET)); | ||||||
} | ||||||
case TWO -> { | ||||||
branchInfos.setConnectionPosition2(new AttributeModification<>(info.getConnectionPosition(), OperationType.SET)); | ||||||
branchInfos.setConnectionName2(new AttributeModification<>(info.getConnectionName(), OperationType.SET)); | ||||||
branchInfos.setConnectionDirection2(new AttributeModification<>(info.getConnectionDirection(), OperationType.SET)); | ||||||
} | ||||||
default -> throw new NetworkModificationException(MOVE_VOLTAGE_LEVEL_FEEDER_BAYS_ERROR, String.format(INVALID_CONNECTION_SIDE, info.getConnectionSide(), branchInfos.getEquipmentId())); | ||||||
} | ||||||
return branchInfos; | ||||||
} | ||||||
|
||||||
private void moveVoltageLevelBusOrBusbarSection(Network network, Connectable<?> connectable, ConnectablePositionModificationInfos info, ReportNode subReportNode) { | ||||||
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. This method should be named moveFeederBay(). And also modifyVoltageLevelBusOrBusBarSectionAttributes() should be named moveFeederBay(). As the only thing they do is apply moveFeederBay() modfication from powsybl-core. |
||||||
Terminal terminal = getTerminal(network, info); | ||||||
String currentBusbarId = ModificationUtils.getInstance().getBusOrBusbarSection(terminal); | ||||||
String targetBusbarId = info.getBusbarSectionId(); | ||||||
if (!currentBusbarId.equals(targetBusbarId)) { | ||||||
ModificationUtils.getInstance().modifyVoltageLevelBusOrBusBarSectionAttributes( | ||||||
connectable, terminal, | ||||||
new AttributeModification<>(modificationInfos.getVoltageLevelId(), OperationType.SET), | ||||||
new AttributeModification<>(targetBusbarId, OperationType.SET), | ||||||
subReportNode); | ||||||
} | ||||||
} | ||||||
|
||||||
public Terminal getTerminal(Network network, ConnectablePositionModificationInfos info) { | ||||||
Connectable<?> connectable = network.getConnectable(info.getEquipmentId()); | ||||||
return switch (connectable) { | ||||||
case Injection<?> injection -> injection.getTerminal(); | ||||||
case Branch<?> branch -> getTerminalFromBranch(branch, info); | ||||||
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.
Suggested change
|
||||||
default -> throw new NetworkModificationException(MOVE_VOLTAGE_LEVEL_FEEDER_BAYS_ERROR, String.format(UNSUPPORTED_CONNECTABLE, connectable.getClass())); | ||||||
}; | ||||||
} | ||||||
|
||||||
private Terminal getTerminalFromBranch(Branch<?> branch, ConnectablePositionModificationInfos info) { | ||||||
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. remove method |
||||||
return switch (ThreeSides.valueOf(info.getConnectionSide())) { | ||||||
case ONE -> branch.getTerminal1(); | ||||||
case TWO -> branch.getTerminal2(); | ||||||
default -> throw new NetworkModificationException(MOVE_VOLTAGE_LEVEL_FEEDER_BAYS_ERROR, String.format(INVALID_CONNECTION_SIDE, info.getConnectionSide(), branch.getId())); | ||||||
}; | ||||||
} | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.