Skip to content
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

Switch contingency support #501

Merged
merged 9 commits into from
Apr 19, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ public Set<String> getBranchIdsToOpen() {
return branchIdsToOpen;
}

public Set<Switch> getSwitchesToOpen() {
return switchesToOpen;
}

public Set<String> getHvdcIdsToOpen() {
return hvdcIdsToOpen;
}
Expand Down Expand Up @@ -191,6 +195,13 @@ private static PropagatedContingency create(Network network, Contingency conting
}
shuntsToLose.add(shuntCompensator);
break;
case SWITCH:
Switch aSwitch = network.getSwitch(element.getId());
if (aSwitch == null) {
throw new PowsyblException("Switch '" + element.getId() + "' not found in the network");
}
switchesToOpen.add(aSwitch);
break;
default:
throw new UnsupportedOperationException("Unsupported contingency element type: " + element.getType());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -685,31 +685,43 @@ protected SensitivityFactorHolder<V, E> writeInvalidFactors(SensitivityFactorHol
return validFactorHolder;
}

private static void cleanBranchIdsToOpen(LfNetwork lfNetwork, PropagatedContingency contingency) {
// Elements have already been checked and found in PropagatedContingency, so there is no need to
// check them again
Set<String> branchesToRemove = new HashSet<>(); // branches connected to one side, or switches
for (String branchId : contingency.getBranchIdsToOpen()) {
LfBranch lfBranch = lfNetwork.getBranchById(branchId);
if (lfBranch == null) {
branchesToRemove.add(branchId); // disconnected branch
continue;
}
if (lfBranch.getBus2() == null || lfBranch.getBus1() == null) {
branchesToRemove.add(branchId); // branch connected only on one side
}
}
contingency.getBranchIdsToOpen().removeAll(branchesToRemove);
}

public void checkContingencies(LfNetwork lfNetwork, List<PropagatedContingency> contingencies) {
Set<String> contingenciesIds = new HashSet<>();
for (PropagatedContingency contingency : contingencies) {
if (!contingency.getSwitchesToOpen().isEmpty()) {
throw new PowsyblException("Switch opening not supported in sensitivity analysis");
}

// check ID are unique because, later contingency are indexed by their IDs
String contingencyId = contingency.getContingency().getId();
if (contingenciesIds.contains(contingencyId)) {
throw new PowsyblException("Contingency '" + contingencyId + "' already exists");
}
contingenciesIds.add(contingencyId);

// Elements have already been checked and found in PropagatedContingency, so there is no need to
// check them again
Set<String> branchesToRemove = new HashSet<>(); // branches connected to one side, or switches
for (String branchId : contingency.getBranchIdsToOpen()) {
LfBranch lfBranch = lfNetwork.getBranchById(branchId);
if (lfBranch == null) {
branchesToRemove.add(branchId); // disconnected branch
continue;
}
if (lfBranch.getBus2() == null || lfBranch.getBus1() == null) {
branchesToRemove.add(branchId); // branch connected only on one side
}
}
contingency.getBranchIdsToOpen().removeAll(branchesToRemove);
if (contingency.getBranchIdsToOpen().isEmpty() && contingency.getHvdcIdsToOpen().isEmpty() && contingency.getGeneratorIdsToLose().isEmpty() && contingency.getLoadIdsToShift().isEmpty()) {
cleanBranchIdsToOpen(lfNetwork, contingency);

if (contingency.getBranchIdsToOpen().isEmpty()
&& contingency.getHvdcIdsToOpen().isEmpty()
&& contingency.getGeneratorIdsToLose().isEmpty()
&& contingency.getLoadIdsToShift().isEmpty()) {
LOGGER.warn("Contingency {} has no impact", contingency.getContingency().getId());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
package com.powsybl.openloadflow.sa;

import com.powsybl.commons.PowsyblException;
import com.powsybl.computation.ComputationManager;
import com.powsybl.contingency.*;
import com.powsybl.ieeecdf.converter.IeeeCdfNetworkFactory;
Expand Down Expand Up @@ -1336,4 +1337,45 @@ void testDivergenceStatus() {
SecurityAnalysisResult result = runSecurityAnalysis(network);
assertFalse(result.getPreContingencyResult().getLimitViolationsResult().isComputationOk());
}

@Test
void testSwitchContingency() {
Network network = createNodeBreakerNetwork();

List<Contingency> contingencies = List.of(new Contingency("C", new SwitchContingency("C")));

List<StateMonitor> monitors = createAllBranchesMonitors(network);

SecurityAnalysisResult result = runSecurityAnalysis(network, contingencies, monitors);

assertTrue(result.getPreContingencyResult().getLimitViolationsResult().isComputationOk());
assertTrue(result.getPostContingencyResults().get(0).getLimitViolationsResult().isComputationOk());

// pre-contingency tests
PreContingencyResult preContingencyResult = result.getPreContingencyResult();
assertEquals(301.884, preContingencyResult.getPreContingencyBranchResult("L1").getP1(), LoadFlowAssert.DELTA_POWER);
assertEquals(-300, preContingencyResult.getPreContingencyBranchResult("L1").getP2(), LoadFlowAssert.DELTA_POWER);
assertEquals(301.884, preContingencyResult.getPreContingencyBranchResult("L2").getP1(), LoadFlowAssert.DELTA_POWER);
assertEquals(-300, preContingencyResult.getPreContingencyBranchResult("L2").getP2(), LoadFlowAssert.DELTA_POWER);

// post-contingency tests
PostContingencyResult postContingencyResult = getPostContingencyResult(result, "C");
assertEquals(3.912, postContingencyResult.getBranchResult("L1").getP1(), LoadFlowAssert.DELTA_POWER);
assertEquals(-3.895, postContingencyResult.getBranchResult("L1").getP2(), LoadFlowAssert.DELTA_POWER);
assertEquals(603.769, postContingencyResult.getBranchResult("L2").getP1(), LoadFlowAssert.DELTA_POWER);
assertEquals(-596.104, postContingencyResult.getBranchResult("L2").getP2(), LoadFlowAssert.DELTA_POWER);
}

@Test
void testSwitchContingencyNotFound() {
Network network = createNodeBreakerNetwork();

List<Contingency> contingencies = List.of(new Contingency("X", new SwitchContingency("X")));

List<StateMonitor> monitors = createAllBranchesMonitors(network);

var e = assertThrows(CompletionException.class, () -> runSecurityAnalysis(network, contingencies, monitors));
assertTrue(e.getCause() instanceof PowsyblException);
assertEquals("Switch 'X' not found in the network", e.getCause().getMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.powsybl.contingency.BranchContingency;
import com.powsybl.contingency.Contingency;
import com.powsybl.contingency.ContingencyContext;
import com.powsybl.contingency.SwitchContingency;
import com.powsybl.iidm.network.Branch;
import com.powsybl.iidm.network.Injection;
import com.powsybl.iidm.network.Network;
Expand All @@ -24,9 +25,11 @@
import com.powsybl.openloadflow.OpenLoadFlowParameters;
import com.powsybl.openloadflow.OpenLoadFlowProvider;
import com.powsybl.openloadflow.network.HvdcNetworkFactory;
import com.powsybl.openloadflow.network.NodeBreakerNetworkFactory;
import com.powsybl.openloadflow.network.SlackBusSelectionMode;
import com.powsybl.openloadflow.util.LoadFlowAssert;
import com.powsybl.sensitivity.*;
import org.junit.jupiter.api.Test;

import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -427,4 +430,21 @@ protected void testGlskPartiallyOutsideMainComponent(boolean dc) {

assertEquals(resultInjection.getValues().iterator().next().getValue(), result.getValues().iterator().next().getValue(), LoadFlowAssert.DELTA_POWER);
}

@Test
void testSwitchContingency() {
Network network = NodeBreakerNetworkFactory.create();

SensitivityAnalysisParameters sensiParameters = createParameters(false, "VL1_0");

List<SensitivityFactor> factors = List.of(createBranchFlowPerInjectionIncrease("L1", "LD"));

List<Contingency> contingencies = List.of(new Contingency("C", new SwitchContingency("C")));

List<SensitivityVariableSet> variableSets = Collections.emptyList();

var e = assertThrows(CompletionException.class, () -> sensiRunner.run(network, factors, contingencies, variableSets, sensiParameters));
assertTrue(e.getCause() instanceof PowsyblException);
assertEquals("Switch opening not supported in sensitivity analysis", e.getCause().getMessage());
}
}