Skip to content

Commit

Permalink
Current limit violations detection in DC security analysis (#549)
Browse files Browse the repository at this point in the history
Signed-off-by: Hadrien <hadrien.godard@artelys.com>
Co-authored-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@gmail.com>
Co-authored-by: Anne Tilloy <anne.tilloy@rte-france.com>
  • Loading branch information
3 people authored Jun 14, 2022
1 parent dcce602 commit 881b629
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 6 deletions.
25 changes: 23 additions & 2 deletions src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ public class OpenLoadFlowParameters extends AbstractExtension<LoadFlowParameters

public static final boolean VOLTAGE_PER_REACTIVE_POWER_CONTROL_DEFAULT_VALUE = false;

public static final double DC_POWER_FACTOR_DEFAULT_VALUE = 1.0;

public static final String SLACK_BUS_SELECTION_PARAM_NAME = "slackBusSelectionMode";

public static final String SLACK_BUSES_IDS_PARAM_NAME = "slackBusesIds";
Expand Down Expand Up @@ -91,6 +93,8 @@ public class OpenLoadFlowParameters extends AbstractExtension<LoadFlowParameters

public static final String TRANSFORMER_VOLTAGE_CONTROL_MODE_NAME = "transformerVoltageControlMode";

public static final String DC_POWER_FACTOR_NAME = "dcPowerFactor";

public static final List<String> SPECIFIC_PARAMETERS_NAMES = List.of(SLACK_BUS_SELECTION_PARAM_NAME,
SLACK_BUSES_IDS_PARAM_NAME,
LOW_IMPEDANCE_BRANCH_MODE_PARAM_NAME,
Expand All @@ -105,7 +109,8 @@ public class OpenLoadFlowParameters extends AbstractExtension<LoadFlowParameters
MAX_ITERATION_NAME,
NEWTON_RAPHSON_CONV_EPS_PER_EQ_NAME,
VOLTAGE_INIT_MODE_OVERRIDE_NAME,
TRANSFORMER_VOLTAGE_CONTROL_MODE_NAME);
TRANSFORMER_VOLTAGE_CONTROL_MODE_NAME,
DC_POWER_FACTOR_NAME);

public enum VoltageInitModeOverride {
NONE,
Expand Down Expand Up @@ -157,6 +162,8 @@ public enum LowImpedanceBranchMode {

private TransformerVoltageControlMode transformerVoltageControlMode = TRANSFORMER_VOLTAGE_CONTROL_MODE_DEFAULT_VALUE;

private double dcPowerFactor = DC_POWER_FACTOR_DEFAULT_VALUE;

@Override
public String getName() {
return "open-load-flow-parameters";
Expand Down Expand Up @@ -305,6 +312,15 @@ public OpenLoadFlowParameters setTransformerVoltageControlMode(TransformerVoltag
return this;
}

public double getDcPowerFactor() {
return dcPowerFactor;
}

public OpenLoadFlowParameters setDcPowerFactor(double dcPowerFactor) {
this.dcPowerFactor = dcPowerFactor;
return this;
}

public static OpenLoadFlowParameters load() {
return load(PlatformConfig.defaultConfig());
}
Expand All @@ -329,7 +345,8 @@ public static OpenLoadFlowParameters load(PlatformConfig platformConfig) {
.setMaxIteration(config.getIntProperty(MAX_ITERATION_NAME, NewtonRaphsonParameters.DEFAULT_MAX_ITERATION))
.setNewtonRaphsonConvEpsPerEq(config.getDoubleProperty(NEWTON_RAPHSON_CONV_EPS_PER_EQ_NAME, DefaultNewtonRaphsonStoppingCriteria.DEFAULT_CONV_EPS_PER_EQ))
.setVoltageInitModeOverride(config.getEnumProperty(VOLTAGE_INIT_MODE_OVERRIDE_NAME, VoltageInitModeOverride.class, VOLTAGE_INIT_MODE_OVERRIDE_DEFAULT_VALUE))
.setTransformerVoltageControlMode(config.getEnumProperty(TRANSFORMER_VOLTAGE_CONTROL_MODE_NAME, TransformerVoltageControlMode.class, TRANSFORMER_VOLTAGE_CONTROL_MODE_DEFAULT_VALUE)));
.setTransformerVoltageControlMode(config.getEnumProperty(TRANSFORMER_VOLTAGE_CONTROL_MODE_NAME, TransformerVoltageControlMode.class, TRANSFORMER_VOLTAGE_CONTROL_MODE_DEFAULT_VALUE))
.setDcPowerFactor(config.getDoubleProperty(DC_POWER_FACTOR_NAME, DC_POWER_FACTOR_DEFAULT_VALUE)));
return parameters;
}

Expand Down Expand Up @@ -368,6 +385,8 @@ public OpenLoadFlowParameters update(Map<String, String> properties) {
.ifPresent(prop -> this.setVoltageInitModeOverride(VoltageInitModeOverride.valueOf(prop)));
Optional.ofNullable(properties.get(TRANSFORMER_VOLTAGE_CONTROL_MODE_NAME))
.ifPresent(prop -> this.setTransformerVoltageControlMode(TransformerVoltageControlMode.valueOf(prop)));
Optional.ofNullable(properties.get(DC_POWER_FACTOR_NAME))
.ifPresent(prop -> this.setDcPowerFactor(Double.parseDouble(prop)));
return this;
}

Expand All @@ -389,6 +408,7 @@ public String toString() {
", newtonRaphsonConvEpsPerEq=" + newtonRaphsonConvEpsPerEq +
", voltageInitModeOverride=" + voltageInitModeOverride +
", transformerVoltageControlMode=" + transformerVoltageControlMode +
", dcPowerFactor=" + dcPowerFactor +
')';
}

Expand Down Expand Up @@ -424,6 +444,7 @@ public static void logDc(LoadFlowParameters parameters, OpenLoadFlowParameters p
LOGGER.info("Plausible active power limit: {}", parametersExt.getPlausibleActivePowerLimit());
LOGGER.info("Add ratio to lines with different nominal voltage at both ends: {}", parametersExt.isAddRatioToLinesWithDifferentNominalVoltageAtBothEnds());
LOGGER.info("Connected component mode: {}", parameters.getConnectedComponentMode());
LOGGER.info("DC power factor: {}", parametersExt.getDcPowerFactor());
}

/**
Expand Down
26 changes: 24 additions & 2 deletions src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.powsybl.iidm.network.Branch;
import com.powsybl.iidm.network.Network;
import com.powsybl.math.matrix.MatrixFactory;
import com.powsybl.openloadflow.OpenLoadFlowParameters;
import com.powsybl.openloadflow.graph.GraphDecrementalConnectivityFactory;
import com.powsybl.openloadflow.network.LfBranch;
import com.powsybl.openloadflow.network.LfBus;
Expand Down Expand Up @@ -63,14 +64,24 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete
StateMonitor monitor = monitorIndex.getAllStateMonitor();
Map<String, BranchResult> preContingencyBranchResults = new HashMap<>();

// CosPhi for DC power to current conversion
OpenLoadFlowParameters parametersExt = OpenLoadFlowParameters.get(securityAnalysisParameters.getLoadFlowParameters());
double dcPowerFactor = parametersExt.getDcPowerFactor();

Map<Pair<String, Branch.Side>, LimitViolation> preContingencyLimitViolationsMap = new HashMap<>();
for (SensitivityValue sensValue : res.getValues(null)) {
SensitivityFactor factor = factors.get(sensValue.getFactorIndex());
String branchId = factor.getFunctionId();
Branch<?> branch = network.getBranch(branchId);
preContingencyBranchResults.put(branchId, new BranchResult(branchId, sensValue.getFunctionReference(), Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN));
double i1 = currentActivePower(Math.abs(sensValue.getFunctionReference()), branch.getTerminal1().getVoltageLevel().getNominalV(), dcPowerFactor);
double i2 = currentActivePower(Math.abs(sensValue.getFunctionReference()), branch.getTerminal2().getVoltageLevel().getNominalV(), dcPowerFactor);
preContingencyBranchResults.put(branchId, new BranchResult(branchId, sensValue.getFunctionReference(), Double.NaN, i1, -sensValue.getFunctionReference(), Double.NaN, i2, Double.NaN));
detector.checkActivePower(branch, Branch.Side.ONE, Math.abs(sensValue.getFunctionReference()),
violation -> preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation));
detector.checkCurrent(branch, Branch.Side.ONE, i1,
violation -> preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation));
detector.checkCurrent(branch, Branch.Side.TWO, i2,
violation -> preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation));
}

LimitViolationsResult preContingencyResult = new LimitViolationsResult(true,
Expand All @@ -90,14 +101,21 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete
SensitivityFactor factor = factors.get(v.getFactorIndex());
String branchId = factor.getFunctionId();
Branch<?> branch = network.getBranch(branchId);
double i1 = currentActivePower(Math.abs(v.getFunctionReference()), branch.getTerminal1().getVoltageLevel().getNominalV(), dcPowerFactor);
double i2 = currentActivePower(Math.abs(v.getFunctionReference()), branch.getTerminal2().getVoltageLevel().getNominalV(), dcPowerFactor);

if (monitor.getBranchIds().contains(branchId)) {
BranchResult preContingencyBranchResult = preContingencyBranchResults.get(branchId);
double flowTransfer = Double.isNaN(branchInContingencyP1) ? Double.NaN : (v.getFunctionReference() - preContingencyBranchResult.getP1()) / branchInContingencyP1;
postContingencyBranchResults.put(branchId, new BranchResult(branchId, v.getFunctionReference(), Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, flowTransfer));
postContingencyBranchResults.put(branchId, new BranchResult(branchId, v.getFunctionReference(), Double.NaN, i1,
-v.getFunctionReference(), Double.NaN, i2, flowTransfer));
}
detector.checkActivePower(branch, Branch.Side.ONE, Math.abs(v.getFunctionReference()),
violation -> violations.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation));
detector.checkCurrent(branch, Branch.Side.ONE, i1,
violation -> violations.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation));
detector.checkCurrent(branch, Branch.Side.TWO, i2,
violation -> violations.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation));
}
preContingencyLimitViolationsMap.forEach((subjectSideId, preContingencyViolation) -> {
LimitViolation postContingencyViolation = violations.get(subjectSideId);
Expand All @@ -110,4 +128,8 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete

return new SecurityAnalysisReport(new SecurityAnalysisResult(preContingencyResult, postContingencyResults, new ArrayList<>(preContingencyBranchResults.values()), Collections.emptyList(), Collections.emptyList()));
}

public static double currentActivePower(double activePower, double voltage, double cosPhi) {
return 1000 * activePower / (Math.sqrt(3) * cosPhi * voltage);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ void testDefaultOpenLoadflowConfig() {
assertEquals(OpenLoadFlowParameters.THROWS_EXCEPTION_IN_CASE_OF_SLACK_DISTRIBUTION_FAILURE_DEFAULT_VALUE, olfParameters.isThrowsExceptionInCaseOfSlackDistributionFailure());
assertEquals(OpenLoadFlowParameters.SLACK_BUS_P_MAX_MISMATCH_DEFAULT_VALUE, olfParameters.getSlackBusPMaxMismatch(), 0.0);
assertEquals(OpenLoadFlowParameters.REACTIVE_POWER_REMOTE_CONTROL_DEFAULT_VALUE, olfParameters.hasReactivePowerRemoteControl());
assertEquals(OpenLoadFlowParameters.DC_POWER_FACTOR_DEFAULT_VALUE, olfParameters.getDcPowerFactor());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ void testGetExtendedVoltageInitializer() {
@Test
void specificParametersTest() {
OpenLoadFlowProvider provider = new OpenLoadFlowProvider();
assertEquals(15, provider.getSpecificParametersNames().size());
assertEquals(16, provider.getSpecificParametersNames().size());
LoadFlowParameters parameters = new LoadFlowParameters();

provider.loadSpecificParameters(Collections.emptyMap())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1521,4 +1521,94 @@ void testSwitchLoopIssue() {
assertEquals(-599.882, postContingencyResult.getBranchResult("L2").getP1(), LoadFlowAssert.DELTA_POWER);
assertEquals(608.214, postContingencyResult.getBranchResult("L2").getP2(), LoadFlowAssert.DELTA_POWER);
}

@Test
void testDcPermanentCurrentLimitViolations() {
Network network = FourBusNetworkFactory.create();
SecurityAnalysisParameters securityAnalysisParameters = new SecurityAnalysisParameters();
LoadFlowParameters lfParameters = new LoadFlowParameters()
.setDc(true);
setSlackBusId(lfParameters, "b1_vl_0");
securityAnalysisParameters.setLoadFlowParameters(lfParameters);

List<Contingency> contingencies = allBranches(network);

network.getLine("l14").newCurrentLimits1().setPermanentLimit(60.0).add();
network.getLine("l12").newCurrentLimits1().setPermanentLimit(120.0).add();
network.getLine("l23").newCurrentLimits2().setPermanentLimit(150.0).add();
network.getLine("l34").newCurrentLimits1().setPermanentLimit(90.0).add();
network.getLine("l13").newCurrentLimits2().setPermanentLimit(60.0).add();

List<StateMonitor> monitors = List.of(new StateMonitor(ContingencyContext.all(), Set.of("l14", "l12", "l23", "l34", "l13"), Collections.emptySet(), Collections.emptySet()));

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

assertTrue(result.getPreContingencyResult().getLimitViolationsResult().isComputationOk());
assertEquals(5, result.getPreContingencyResult().getLimitViolationsResult().getLimitViolations().size());
assertEquals(5, result.getPostContingencyResults().size());
assertEquals(2, getPostContingencyResult(result, "l14").getLimitViolationsResult().getLimitViolations().size());
assertEquals(192.450, getPostContingencyResult(result, "l14").getBranchResult("l12").getI1(), LoadFlowAssert.DELTA_I);
assertEquals(962.250, getPostContingencyResult(result, "l14").getBranchResult("l13").getI1(), LoadFlowAssert.DELTA_I);
assertEquals(2, getPostContingencyResult(result, "l12").getLimitViolationsResult().getLimitViolations().size());
assertEquals(192.450, getPostContingencyResult(result, "l12").getBranchResult("l14").getI1(), LoadFlowAssert.DELTA_I);
assertEquals(962.250, getPostContingencyResult(result, "l12").getBranchResult("l13").getI1(), LoadFlowAssert.DELTA_I);
assertEquals(4, getPostContingencyResult(result, "l13").getLimitViolationsResult().getLimitViolations().size());
assertEquals(577.350, getPostContingencyResult(result, "l13").getBranchResult("l12").getI1(), LoadFlowAssert.DELTA_I);
assertEquals(577.350, getPostContingencyResult(result, "l13").getBranchResult("l14").getI1(), LoadFlowAssert.DELTA_I);
assertEquals(1154.700, getPostContingencyResult(result, "l13").getBranchResult("l23").getI1(), LoadFlowAssert.DELTA_I);
assertEquals(1154.700, getPostContingencyResult(result, "l13").getBranchResult("l34").getI1(), LoadFlowAssert.DELTA_I);
assertEquals(4, getPostContingencyResult(result, "l23").getLimitViolationsResult().getLimitViolations().size());
assertEquals(577.350, getPostContingencyResult(result, "l23").getBranchResult("l12").getI1(), LoadFlowAssert.DELTA_I);
assertEquals(384.900, getPostContingencyResult(result, "l23").getBranchResult("l14").getI1(), LoadFlowAssert.DELTA_I);
assertEquals(1347.150, getPostContingencyResult(result, "l23").getBranchResult("l13").getI1(), LoadFlowAssert.DELTA_I);
assertEquals(962.250, getPostContingencyResult(result, "l23").getBranchResult("l34").getI1(), LoadFlowAssert.DELTA_I);
assertEquals(4, getPostContingencyResult(result, "l34").getLimitViolationsResult().getLimitViolations().size());
assertEquals(384.900, getPostContingencyResult(result, "l34").getBranchResult("l12").getI1(), LoadFlowAssert.DELTA_I);
assertEquals(577.350, getPostContingencyResult(result, "l34").getBranchResult("l14").getI1(), LoadFlowAssert.DELTA_I);
assertEquals(1347.150, getPostContingencyResult(result, "l34").getBranchResult("l13").getI1(), LoadFlowAssert.DELTA_I);
assertEquals(962.250, getPostContingencyResult(result, "l34").getBranchResult("l23").getI1(), LoadFlowAssert.DELTA_I);
}

@Test
void testDcTemporaryCurrentLimitViolations() {
Network network = FourBusNetworkFactory.create();
SecurityAnalysisParameters securityAnalysisParameters = new SecurityAnalysisParameters();
LoadFlowParameters lfParameters = new LoadFlowParameters()
.setDc(true);
OpenLoadFlowParameters lfParametersExt = new OpenLoadFlowParameters().setDcPowerFactor(Math.tan(0.4));
lfParameters.addExtension(OpenLoadFlowParameters.class, lfParametersExt);
setSlackBusId(lfParameters, "b1_vl_0");
securityAnalysisParameters.setLoadFlowParameters(lfParameters);

List<Contingency> contingencies = allBranches(network);

network.getLine("l14").newCurrentLimits1().setPermanentLimit(60.0)
.beginTemporaryLimit().setName("60").setAcceptableDuration(Integer.MAX_VALUE).setValue(200.0).endTemporaryLimit()
.beginTemporaryLimit().setName("0").setAcceptableDuration(60).setValue(Double.MAX_VALUE).endTemporaryLimit().add();
network.getLine("l12").newCurrentLimits1().setPermanentLimit(120.0)
.beginTemporaryLimit().setName("60").setAcceptableDuration(Integer.MAX_VALUE).setValue(300.0).endTemporaryLimit()
.beginTemporaryLimit().setName("0").setAcceptableDuration(60).setValue(Double.MAX_VALUE).endTemporaryLimit().add();
network.getLine("l23").newCurrentLimits2().setPermanentLimit(150.0)
.beginTemporaryLimit().setName("60").setAcceptableDuration(Integer.MAX_VALUE).setValue(500.0).endTemporaryLimit()
.beginTemporaryLimit().setName("0").setAcceptableDuration(60).setValue(Double.MAX_VALUE).endTemporaryLimit().add();
network.getLine("l34").newCurrentLimits1().setPermanentLimit(90.0)
.beginTemporaryLimit().setName("60").setAcceptableDuration(Integer.MAX_VALUE).setValue(300.0).endTemporaryLimit()
.beginTemporaryLimit().setName("0").setAcceptableDuration(60).setValue(Double.MAX_VALUE).endTemporaryLimit().add();
network.getLine("l13").newCurrentLimits2().setPermanentLimit(60.0)
.beginTemporaryLimit().setName("60").setAcceptableDuration(Integer.MAX_VALUE).setValue(300.0).endTemporaryLimit()
.beginTemporaryLimit().setName("0").setAcceptableDuration(60).setValue(Double.MAX_VALUE).endTemporaryLimit().add();

List<StateMonitor> monitors = List.of(new StateMonitor(ContingencyContext.all(), Set.of("l14", "l12", "l23", "l34", "l13"), Collections.emptySet(), Collections.emptySet()));

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

assertTrue(result.getPreContingencyResult().getLimitViolationsResult().isComputationOk());
assertEquals(5, result.getPreContingencyResult().getLimitViolationsResult().getLimitViolations().size());
assertEquals(5, result.getPostContingencyResults().size());
assertEquals(2, result.getPostContingencyResults().get(0).getLimitViolationsResult().getLimitViolations().size());
assertEquals(2, result.getPostContingencyResults().get(1).getLimitViolationsResult().getLimitViolations().size());
assertEquals(4, result.getPostContingencyResults().get(2).getLimitViolationsResult().getLimitViolations().size());
assertEquals(4, result.getPostContingencyResults().get(3).getLimitViolationsResult().getLimitViolations().size());
assertEquals(4, result.getPostContingencyResults().get(4).getLimitViolationsResult().getLimitViolations().size());
}
}
3 changes: 2 additions & 1 deletion src/test/resources/debug-parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
"maxIteration" : 30,
"newtonRaphsonConvEpsPerEq" : 1.0E-4,
"voltageInitModeOverride" : "NONE",
"transformerVoltageControlMode" : "WITH_GENERATOR_VOLTAGE_CONTROL"
"transformerVoltageControlMode" : "WITH_GENERATOR_VOLTAGE_CONTROL",
"dcPowerFactor" : 1.0
}
}
},
Expand Down

0 comments on commit 881b629

Please sign in to comment.