-
Notifications
You must be signed in to change notification settings - Fork 8
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
AC Security Analysis with operator strategies #590
Changes from all commits
ea07d2d
3dcf4b6
bb753a2
eb55d67
9c61ead
9f10f61
79949cf
14a066f
38ddfa7
c4e727d
5c7c2cf
f94e2e1
469648a
973ab64
12c68da
8cacc54
d308bd3
33da158
bddb21a
1b36f58
fb97b1d
5940385
5e04f88
f37978f
185ae3e
bf89e63
4781777
2f4b49c
10d28f5
6065c26
01ef28b
5e75f63
ae7241a
c902c32
f0f3b99
beeaef0
bde6467
914a1a5
69db0bf
0c6507c
2b87a24
7b941a1
7db0284
f1bc076
e104e73
a4f72f4
0d17aff
a5106c4
e2885fa
d1f79db
1d5aafe
496635b
3b281fa
d0d15d5
f73596a
322ff56
f687551
4ce609d
fb670ca
0247979
6acd8ff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
/** | ||
* Copyright (c) 2022, 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.openloadflow.network; | ||
|
||
import com.powsybl.commons.PowsyblException; | ||
import com.powsybl.openloadflow.graph.GraphConnectivity; | ||
import com.powsybl.security.action.Action; | ||
import com.powsybl.security.action.LineConnectionAction; | ||
import com.powsybl.security.action.PhaseTapChangerTapPositionAction; | ||
import com.powsybl.security.action.SwitchAction; | ||
|
||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.Set; | ||
|
||
/** | ||
* @author Anne Tilloy <anne.tilloy at rte-france.com> | ||
*/ | ||
public class LfAction { | ||
|
||
private static final class TapPositionChange { | ||
|
||
private final LfBranch branch; | ||
|
||
private final int value; | ||
|
||
private final boolean relative; | ||
|
||
private TapPositionChange(LfBranch branch, int value, boolean relative) { | ||
this.branch = Objects.requireNonNull(branch); | ||
this.value = value; | ||
this.relative = relative; | ||
} | ||
|
||
public LfBranch getBranch() { | ||
return branch; | ||
} | ||
|
||
public int getValue() { | ||
return value; | ||
} | ||
|
||
public boolean isRelative() { | ||
return relative; | ||
} | ||
} | ||
|
||
private final String id; | ||
|
||
private LfBranch disabledBranch; // switch to open | ||
|
||
private LfBranch enabledBranch; // switch to close | ||
|
||
private TapPositionChange tapPositionChange; | ||
|
||
public LfAction(Action action, LfNetwork network) { | ||
this.id = Objects.requireNonNull(action.getId()); | ||
Objects.requireNonNull(network); | ||
LfBranch branch; | ||
switch (action.getType()) { | ||
case SwitchAction.NAME: | ||
SwitchAction switchAction = (SwitchAction) action; | ||
branch = network.getBranchById(switchAction.getSwitchId()); | ||
checkBranch(branch, switchAction.getSwitchId()); | ||
if (switchAction.isOpen()) { | ||
disabledBranch = branch; | ||
} else { | ||
enabledBranch = branch; | ||
} | ||
break; | ||
case LineConnectionAction.NAME: | ||
LineConnectionAction lineConnectionAction = (LineConnectionAction) action; | ||
branch = network.getBranchById(lineConnectionAction.getLineId()); | ||
checkBranch(branch, lineConnectionAction.getLineId()); | ||
if (lineConnectionAction.isOpenSide1() && lineConnectionAction.isOpenSide2()) { | ||
disabledBranch = branch; | ||
} else { | ||
throw new UnsupportedOperationException("Line connection action: only open line at both sides is supported yet."); | ||
} | ||
break; | ||
case PhaseTapChangerTapPositionAction.NAME: | ||
PhaseTapChangerTapPositionAction phaseTapChangerTapPositionAction = (PhaseTapChangerTapPositionAction) action; | ||
branch = network.getBranchById(phaseTapChangerTapPositionAction.getTransformerId()); // only two windings transformer for the moment. | ||
checkBranch(branch, phaseTapChangerTapPositionAction.getTransformerId()); // how to check that it is really a phase tap changer? | ||
if (branch.getPiModel() instanceof SimplePiModel) { | ||
throw new UnsupportedOperationException("Phase tap changer tap connection action: only one tap in the branch {" + phaseTapChangerTapPositionAction.getTransformerId() + "}"); | ||
} else { | ||
tapPositionChange = new TapPositionChange(branch, phaseTapChangerTapPositionAction.getValue(), phaseTapChangerTapPositionAction.isRelativeValue()); | ||
} | ||
break; | ||
default: | ||
throw new UnsupportedOperationException("Unsupported action type: " + action.getType()); | ||
} | ||
} | ||
|
||
public String getId() { | ||
return id; | ||
} | ||
|
||
public LfBranch getDisabledBranch() { | ||
return disabledBranch; | ||
} | ||
|
||
public LfBranch getEnabledBranch() { | ||
return enabledBranch; | ||
} | ||
|
||
public static void apply(List<LfAction> actions, LfNetwork network, LfContingency contingency) { | ||
Objects.requireNonNull(actions); | ||
Objects.requireNonNull(network); | ||
|
||
// first process connectivity part of actions | ||
updateConnectivity(actions, network, contingency); | ||
|
||
// then process remaining changes of actions | ||
for (LfAction action : actions) { | ||
action.apply(); | ||
} | ||
} | ||
|
||
private static void updateConnectivity(List<LfAction> actions, LfNetwork network, LfContingency contingency) { | ||
GraphConnectivity<LfBus, LfBranch> connectivity = network.getConnectivity(); | ||
|
||
// re-update connectivity according to post contingency state (revert after LfContingency apply) | ||
connectivity.startTemporaryChanges(); | ||
contingency.getDisabledBranches().forEach(connectivity::removeEdge); | ||
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 support a bus contingency (bus/bar section or bus from a bus/breaker topology)? If one day yes, we also have to remove the disabled buses. 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. yes, we should add it now to not forget it later |
||
|
||
// update connectivity according to post action state | ||
connectivity.startTemporaryChanges(); | ||
for (LfAction action : actions) { | ||
action.updateConnectivity(connectivity); | ||
} | ||
|
||
// add to action description buses and branches that won't be part of the main connected | ||
// component in post action state. | ||
Set<LfBus> removedBuses = connectivity.getVerticesRemovedFromMainComponent(); | ||
removedBuses.forEach(bus -> bus.setDisabled(true)); | ||
Set<LfBranch> removedBranches = new HashSet<>(connectivity.getEdgesRemovedFromMainComponent()); | ||
// we should manage branches open at one side. | ||
for (LfBus bus : removedBuses) { | ||
bus.getBranches().stream().filter(b -> !b.isConnectedAtBothSides()).forEach(removedBranches::add); | ||
} | ||
removedBranches.forEach(branch -> branch.setDisabled(true)); | ||
|
||
// add to action description buses and branches that will be part of the main connected | ||
// component in post action state. | ||
Set<LfBus> addedBuses = connectivity.getVerticesAddedToMainComponent(); | ||
addedBuses.forEach(bus -> bus.setDisabled(false)); | ||
Set<LfBranch> addedBranches = new HashSet<>(connectivity.getEdgesAddedToMainComponent()); | ||
// we should manage branches open at one side. | ||
for (LfBus bus : addedBuses) { | ||
bus.getBranches().stream().filter(b -> !b.isConnectedAtBothSides()).forEach(addedBranches::add); | ||
} | ||
addedBranches.forEach(branch -> branch.setDisabled(false)); | ||
|
||
// reset connectivity to discard post contingency connectivity and post action connectivity | ||
connectivity.undoTemporaryChanges(); | ||
connectivity.undoTemporaryChanges(); | ||
} | ||
|
||
public void updateConnectivity(GraphConnectivity<LfBus, LfBranch> connectivity) { | ||
if (disabledBranch != null && disabledBranch.getBus1() != null && disabledBranch.getBus2() != null) { | ||
connectivity.removeEdge(disabledBranch); | ||
} | ||
if (enabledBranch != null) { | ||
connectivity.addEdge(enabledBranch.getBus1(), enabledBranch.getBus2(), enabledBranch); | ||
} | ||
} | ||
|
||
public void apply() { | ||
if (tapPositionChange != null) { | ||
LfBranch branch = tapPositionChange.getBranch(); | ||
int tapPosition = branch.getPiModel().getTapPosition(); | ||
int value = tapPositionChange.getValue(); | ||
int newTapPosition = tapPositionChange.isRelative() ? tapPosition + value : value; | ||
branch.getPiModel().setTapPosition(newTapPosition); | ||
} | ||
} | ||
|
||
private static void checkBranch(LfBranch branch, String branchId) { | ||
if (branch == null) { | ||
throw new PowsyblException("Branch " + branchId + " not found in the network"); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -546,6 +546,7 @@ public GraphConnectivity<LfBus, LfBranch> getConnectivity() { | |
getBranches().stream() | ||
.filter(b -> b.getBus1() != null && b.getBus2() != null) | ||
.forEach(b -> connectivity.addEdge(b.getBus1(), b.getBus2(), b)); | ||
connectivity.setMainComponentVertex(getSlackBus()); | ||
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. @flo-dup can you please just take a look at this change and tell us if it is okay for you. Thanks! |
||
} | ||
return connectivity; | ||
} | ||
|
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.
So the plan here is to support a list of action and that LfAction will be the sum/result of PowSyBl Core actions for the current strategy?
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.
No: we keep a list of LfAction for an operator strategy. I am not able to do better...
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.
When all design issues will be solved it should be easy to support