Skip to content

Commit e7d56fd

Browse files
committed
improve SVC validation rules wip
Signed-off-by: Samir Romdhani <samir.romdhani_externe@rte-france.com>
1 parent d6dbb8a commit e7d56fd

File tree

3 files changed

+49
-15
lines changed

3 files changed

+49
-15
lines changed

loadflow/loadflow-validation/src/main/java/com/powsybl/loadflow/validation/StaticVarCompensatorsValidation.java

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@
2525
import com.powsybl.iidm.network.StaticVarCompensator.RegulationMode;
2626
import com.powsybl.loadflow.validation.io.ValidationWriter;
2727

28-
import static com.powsybl.loadflow.validation.ValidationUtils.isOutsideTolerance;
29-
import static com.powsybl.loadflow.validation.ValidationUtils.isUndefinedOrZero;
28+
import static com.powsybl.loadflow.validation.ValidationUtils.*;
3029

3130
/**
3231
*
@@ -150,7 +149,7 @@ public boolean checkSVCs(String id, double p, double q, double vControlled, doub
150149

151150
if (connected && ValidationUtils.isMainComponent(config, mainComponent)) {
152151
if (Double.isNaN(p) || Double.isNaN(q)) {
153-
// Rule2 : TODO
152+
// Rule2: **reactivePowerSetpoint** must be 0 if p or q is missing (NaN)
154153
validated = checkSVCsNaNValues(id, p, q, reactivePowerSetpoint);
155154
} else {
156155
// Rule1, Rule3, Rule4, Rule5
@@ -167,7 +166,6 @@ public boolean checkSVCs(String id, double p, double q, double vControlled, doub
167166

168167
private static boolean checkSVCsNaNValues(String id, double p, double q, double reactivePowerSetpoint) {
169168
// a validation error should be detected if there is a setpoint but no p or q
170-
// Rule2: reactivePowerSetpoint must be undefined or equal to 0 when no p or q
171169
if (!isUndefinedOrZero(reactivePowerSetpoint, 0.0)) {
172170
LOGGER.warn("{} {}: {}: P={} Q={} reactivePowerSetpoint={}", ValidationType.SVCS, ValidationUtils.VALIDATION_ERROR, id, p, q, reactivePowerSetpoint);
173171
return false;
@@ -185,11 +183,9 @@ private static boolean checkSVCsValues(String id, double p, double q, double vCo
185183
LOGGER.warn("{} {}: {}: P={}", ValidationType.SVCS, ValidationUtils.VALIDATION_ERROR, id, p);
186184
validated = false;
187185
}
188-
189-
double vAux = vController; // voltage in bus
190-
if (vAux == 0 || Double.isNaN(vAux)) {
191-
vAux = nominalVcontroller; // voltage in VoltageLevel
192-
}
186+
// vController: voltage in bus
187+
// nominalVcontroller: voltage in VoltageLevel
188+
double vAux = voltageFrom(vController, nominalVcontroller);
193189
double qMin = -bMax * vAux * vAux;
194190
double qMax = -bMin * vAux * vAux;
195191

@@ -223,14 +219,13 @@ private static boolean checkSVCsValues(String id, double p, double q, double vCo
223219
private static boolean reactivePowerRegulationModeKo(RegulationMode regulationMode, double q, double qMin,
224220
double qMax, double reactivePowerSetpoint, ValidationConfig config) {
225221
// if regulationMode = REACTIVE_POWER, the reactive power must be equal to setpoint
226-
227222
if (regulationMode != RegulationMode.REACTIVE_POWER) {
228223
return false;
229224
}
230225
if (ValidationUtils.areNaN(config, reactivePowerSetpoint, qMin, qMax)) {
231226
return true;
232227
}
233-
return Math.abs(q - reactivePowerSetpoint) > config.getThreshold();
228+
return isOutsideTolerance(q, reactivePowerSetpoint, config.getThreshold());
234229
}
235230

236231
private static boolean voltageRegulationModeKo(RegulationMode regulationMode, double q, double qMin,
@@ -240,20 +235,21 @@ private static boolean voltageRegulationModeKo(RegulationMode regulationMode, do
240235
// or q is equal to Qmin = -bMax * V * V and V is higher than voltageSetpoint
241236
// or V at the controlled bus is equal to voltageSetpoint and q is bounded
242237
// within [Qmin=-bMax*V*V, Qmax=-bMin*V*V]
243-
238+
double threshold = config.getThreshold();
244239
if (regulationMode != RegulationMode.VOLTAGE) {
245240
return false;
246241
}
247242
if (ValidationUtils.areNaN(config, qMin, qMax, vControlled, voltageSetpoint)) {
248243
return true;
249244
}
250-
if (vControlled < voltageSetpoint - config.getThreshold() && Math.abs(q - qMax) > config.getThreshold()) {
245+
if (vControlled < voltageSetpoint - threshold && isOutsideTolerance(q, qMax, threshold)) {
251246
return true;
252247
}
253-
if (vControlled > voltageSetpoint + config.getThreshold() && Math.abs(q - qMin) > config.getThreshold()) {
248+
if (vControlled > voltageSetpoint + threshold && isOutsideTolerance(q, qMin, threshold)) {
254249
return true;
255250
}
256-
return Math.abs(vControlled - voltageSetpoint) < config.getThreshold() && !ValidationUtils.boundedWithin(qMin, qMax, q, config.getThreshold());
251+
boolean voltageAtSetpoint = Math.abs(vControlled - voltageSetpoint) < threshold;
252+
return voltageAtSetpoint && !boundedWithin(qMin, qMax, q, threshold);
257253
}
258254

259255
private static boolean notRegulatingKo(boolean regulating, double q, ValidationConfig config) {

loadflow/loadflow-validation/src/main/java/com/powsybl/loadflow/validation/ValidationUtils.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,13 @@ public static double computeShuntExpectedQ(double bPerSection, int sectionCount,
122122
return -bPerSection * sectionCount * v * v;
123123
}
124124

125+
public record QBounds(double qMin, double qMax) { }
126+
127+
public static double voltageFrom(double vBus, double nominalV) {
128+
return (Double.isNaN(vBus) || vBus == 0.0) ? nominalV : vBus;
129+
}
130+
131+
public static boolean isWithinInclusive(double value, double min, double max, double epsilon) {
132+
return boundedWithin(min, max, value, epsilon);
133+
}
125134
}

loadflow/loadflow-validation/src/test/java/com/powsybl/loadflow/validation/StaticVarCompensatorsValidationTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import static org.junit.jupiter.api.Assertions.assertFalse;
1111
import static org.junit.jupiter.api.Assertions.assertTrue;
12+
import static org.mockito.Mockito.when;
1213

1314
import java.io.IOException;
1415
import java.util.stream.Stream;
@@ -189,4 +190,32 @@ void checkNetworkSvcs() throws IOException {
189190
ValidationWriter validationWriter = ValidationUtils.createValidationWriter(network.getId(), looseConfig, NullWriter.INSTANCE, ValidationType.SVCS);
190191
assertTrue(ValidationType.SVCS.check(network, looseConfig, validationWriter));
191192
}
193+
194+
// Rule1: active power should be equal to 0
195+
@Test
196+
void checkSVCActivePowerShouldBeZeroWithinThreshold() {
197+
// Given (p = 0)
198+
when(svcTerminal.getP()).thenReturn(0.0);
199+
assertTrue(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE));
200+
// Given (p = 0.01 ~ threshold)
201+
when(svcTerminal.getP()).thenReturn(0.01);
202+
assertTrue(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE));
203+
//Given (p > 0.01)
204+
when(svcTerminal.getP()).thenReturn(0.02);
205+
assertFalse(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE));
206+
}
207+
208+
// Rule2: **reactivePowerSetpoint** must be 0 if p or q is missing (NaN)
209+
@Test
210+
void checkSVCReactivePowerSetpointWhenPOrQMissing() {
211+
// non-zero setpoint with missing p/q => KO
212+
when(svcTerminal.getP()).thenReturn(Double.NaN);
213+
when(svcTerminal.getQ()).thenReturn(Double.NaN);
214+
when(svc.getReactivePowerSetpoint()).thenReturn(5.0);
215+
assertFalse(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE));
216+
// zero setpoint with missing p/q => OK
217+
when(svc.getReactivePowerSetpoint()).thenReturn(0.0);
218+
assertTrue(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE));
219+
}
220+
192221
}

0 commit comments

Comments
 (0)