|
7 | 7 | */ |
8 | 8 | package com.powsybl.loadflow.validation; |
9 | 9 |
|
10 | | -import static org.junit.jupiter.api.Assertions.assertFalse; |
11 | | -import static org.junit.jupiter.api.Assertions.assertTrue; |
| 10 | +import static org.junit.jupiter.api.Assertions.*; |
| 11 | +import static org.mockito.Mockito.mock; |
12 | 12 | import static org.mockito.Mockito.when; |
13 | 13 |
|
14 | 14 | import java.io.IOException; |
|
17 | 17 | import org.apache.commons.io.output.NullWriter; |
18 | 18 | import org.junit.jupiter.api.BeforeEach; |
19 | 19 | import org.junit.jupiter.api.Test; |
20 | | -import org.mockito.Mockito; |
21 | 20 |
|
22 | 21 | import com.powsybl.iidm.network.Bus; |
23 | 22 | import com.powsybl.iidm.network.Network; |
@@ -55,32 +54,32 @@ class StaticVarCompensatorsValidationTest extends AbstractValidationTest { |
55 | 54 | void setUp() throws IOException { |
56 | 55 | super.setUp(); |
57 | 56 |
|
58 | | - Bus svcBus = Mockito.mock(Bus.class); |
59 | | - Mockito.when(svcBus.getV()).thenReturn(v); |
60 | | - Mockito.when(svcBus.isInMainConnectedComponent()).thenReturn(mainComponent); |
61 | | - |
62 | | - svcBusView = Mockito.mock(BusView.class); |
63 | | - Mockito.when(svcBusView.getBus()).thenReturn(svcBus); |
64 | | - Mockito.when(svcBusView.getConnectableBus()).thenReturn(svcBus); |
65 | | - |
66 | | - VoltageLevel voltageLevel = Mockito.mock(VoltageLevel.class); |
67 | | - Mockito.when(voltageLevel.getNominalV()).thenReturn(nominalV); |
68 | | - |
69 | | - svcTerminal = Mockito.mock(Terminal.class); |
70 | | - Mockito.when(svcTerminal.getP()).thenReturn(p); |
71 | | - Mockito.when(svcTerminal.getQ()).thenReturn(q); |
72 | | - Mockito.when(svcTerminal.getBusView()).thenReturn(svcBusView); |
73 | | - Mockito.when(svcTerminal.getVoltageLevel()).thenReturn(voltageLevel); |
74 | | - |
75 | | - svc = Mockito.mock(StaticVarCompensator.class); |
76 | | - Mockito.when(svc.getId()).thenReturn("svc"); |
77 | | - Mockito.when(svc.getTerminal()).thenReturn(svcTerminal); |
78 | | - Mockito.when(svc.getReactivePowerSetpoint()).thenReturn(reactivePowerSetpoint); |
79 | | - Mockito.when(svc.getVoltageSetpoint()).thenReturn(voltageSetpoint); |
80 | | - Mockito.when(svc.getRegulationMode()).thenReturn(regulationMode); |
81 | | - Mockito.when(svc.isRegulating()).thenReturn(regulating); |
82 | | - Mockito.when(svc.getBmin()).thenReturn(bMin); |
83 | | - Mockito.when(svc.getBmax()).thenReturn(bMax); |
| 57 | + Bus svcBus = mock(Bus.class); |
| 58 | + when(svcBus.getV()).thenReturn(v); |
| 59 | + when(svcBus.isInMainConnectedComponent()).thenReturn(mainComponent); |
| 60 | + |
| 61 | + svcBusView = mock(BusView.class); |
| 62 | + when(svcBusView.getBus()).thenReturn(svcBus); |
| 63 | + when(svcBusView.getConnectableBus()).thenReturn(svcBus); |
| 64 | + |
| 65 | + VoltageLevel voltageLevel = mock(VoltageLevel.class); |
| 66 | + when(voltageLevel.getNominalV()).thenReturn(nominalV); |
| 67 | + |
| 68 | + svcTerminal = mock(Terminal.class); |
| 69 | + when(svcTerminal.getP()).thenReturn(p); |
| 70 | + when(svcTerminal.getQ()).thenReturn(q); |
| 71 | + when(svcTerminal.getBusView()).thenReturn(svcBusView); |
| 72 | + when(svcTerminal.getVoltageLevel()).thenReturn(voltageLevel); |
| 73 | + |
| 74 | + svc = mock(StaticVarCompensator.class); |
| 75 | + when(svc.getId()).thenReturn("svc"); |
| 76 | + when(svc.getTerminal()).thenReturn(svcTerminal); |
| 77 | + when(svc.getReactivePowerSetpoint()).thenReturn(reactivePowerSetpoint); |
| 78 | + when(svc.getVoltageSetpoint()).thenReturn(voltageSetpoint); |
| 79 | + when(svc.getRegulationMode()).thenReturn(regulationMode); |
| 80 | + when(svc.isRegulating()).thenReturn(regulating); |
| 81 | + when(svc.getBmin()).thenReturn(bMin); |
| 82 | + when(svc.getBmax()).thenReturn(bMax); |
84 | 83 | } |
85 | 84 |
|
86 | 85 | @Test |
@@ -169,19 +168,19 @@ void checkSvcsValues() { |
169 | 168 | void checkSvcs() { |
170 | 169 | // active power should be equal to 0 |
171 | 170 | assertTrue(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE)); |
172 | | - Mockito.when(svcTerminal.getP()).thenReturn(-39.8); |
| 171 | + when(svcTerminal.getP()).thenReturn(-39.8); |
173 | 172 | assertFalse(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE)); |
174 | 173 |
|
175 | 174 | // the unit is disconnected |
176 | | - Mockito.when(svcBusView.getBus()).thenReturn(null); |
| 175 | + when(svcBusView.getBus()).thenReturn(null); |
177 | 176 | assertTrue(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE)); |
178 | 177 | } |
179 | 178 |
|
180 | 179 | @Test |
181 | 180 | void checkNetworkSvcs() throws IOException { |
182 | | - Network network = Mockito.mock(Network.class); |
183 | | - Mockito.when(network.getId()).thenReturn("network"); |
184 | | - Mockito.when(network.getStaticVarCompensatorStream()).thenAnswer(dummy -> Stream.of(svc)); |
| 181 | + Network network = mock(Network.class); |
| 182 | + when(network.getId()).thenReturn("network"); |
| 183 | + when(network.getStaticVarCompensatorStream()).thenAnswer(dummy -> Stream.of(svc)); |
185 | 184 |
|
186 | 185 | assertTrue(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(network, looseConfig, data)); |
187 | 186 |
|
@@ -218,4 +217,156 @@ void checkSVCReactivePowerSetpointWhenPOrQMissing() { |
218 | 217 | assertTrue(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE)); |
219 | 218 | } |
220 | 219 |
|
| 220 | + // Rule 3: regulationMode = REACTIVE_POWER |
| 221 | + // Test condition: required inputs missing => OK only if okMissingValues=true |
| 222 | + @Test |
| 223 | + void checkSVCReactivePowerModeMissingInputs() { |
| 224 | + // Given regulation enabled, and regulationMode is REACTIVE_POWER |
| 225 | + when(svc.getRegulationMode()).thenReturn(RegulationMode.REACTIVE_POWER); |
| 226 | + when(svc.isRegulating()).thenReturn(true); |
| 227 | + // Given Rule1, Rule2 (OK) |
| 228 | + when(svcTerminal.getP()).thenReturn(0.0); |
| 229 | + when(svc.getReactivePowerSetpoint()).thenReturn(Double.NaN); |
| 230 | + // When |
| 231 | + strictConfig.setOkMissingValues(false); |
| 232 | + // Then |
| 233 | + assertFalse(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE)); |
| 234 | + // When |
| 235 | + strictConfig.setOkMissingValues(true); |
| 236 | + // Then |
| 237 | + assertTrue(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE)); |
| 238 | + } |
| 239 | + |
| 240 | + // Rule 3: regulationMode = REACTIVE_POWER |
| 241 | + // Test condition: Q must match reactivePowerSetpoint within threshold |
| 242 | + @Test |
| 243 | + void checkSVCReactivePowerModeQMustMatchSetpoint() { |
| 244 | + // Given regulation enabled, and regulationMode is REACTIVE_POWER |
| 245 | + when(svc.getRegulationMode()).thenReturn(RegulationMode.REACTIVE_POWER); |
| 246 | + when(svc.isRegulating()).thenReturn(true); |
| 247 | + |
| 248 | + when(svcTerminal.getP()).thenReturn(0.0); |
| 249 | + when(svc.getReactivePowerSetpoint()).thenReturn(3.0); |
| 250 | + // When |
| 251 | + when(svcTerminal.getQ()).thenReturn(3.01); |
| 252 | + // Then |
| 253 | + assertTrue(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE)); |
| 254 | + // When |
| 255 | + when(svcTerminal.getQ()).thenReturn(3.5); // diff > (threshold = 0.01) |
| 256 | + // Then |
| 257 | + assertFalse(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE)); |
| 258 | + } |
| 259 | + |
| 260 | + // Rule 4: regulationMode = VOLTAGE |
| 261 | + // Test condition: required inputs missing => OK only if okMissingValues=true |
| 262 | + @Test |
| 263 | + void checkSVCVoltageModeMissingInputs() { |
| 264 | + // Given regulation enabled, and regulationMode is VOLTAGE |
| 265 | + when(svc.getRegulationMode()).thenReturn(RegulationMode.VOLTAGE); |
| 266 | + when(svc.isRegulating()).thenReturn(true); |
| 267 | + // Given Rule1, Rule 2 (OK) |
| 268 | + when(svcTerminal.getQ()).thenReturn(0.0); |
| 269 | + when(svc.getVoltageSetpoint()).thenReturn(Double.NaN); |
| 270 | + // When |
| 271 | + strictConfig.setOkMissingValues(false); |
| 272 | + // Then |
| 273 | + assertFalse(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE)); |
| 274 | + // When |
| 275 | + strictConfig.setOkMissingValues(true); |
| 276 | + // Then |
| 277 | + assertTrue(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE)); |
| 278 | + } |
| 279 | + |
| 280 | + // Rule 4: regulationMode = VOLTAGE |
| 281 | + // Test condition: V controlled < V setPoint, then Q must match maxQ. |
| 282 | + @Test |
| 283 | + void checkSVCVoltageModeVLowerThanSetpoint() { |
| 284 | + // Given regulation enabled, and regulationMode is VOLTAGE |
| 285 | + when(svc.getRegulationMode()).thenReturn(RegulationMode.VOLTAGE); |
| 286 | + when(svc.isRegulating()).thenReturn(true); |
| 287 | + when(svcTerminal.getP()).thenReturn(0.0); |
| 288 | + // Given V controlled < V setpoint |
| 289 | + Terminal regulatingTerminal = regulatingTerminalWithVoltage(360.0); // V controlled = 360.0 |
| 290 | + when(svc.getRegulatingTerminal()).thenReturn(regulatingTerminal); |
| 291 | + when(svc.getVoltageSetpoint()).thenReturn(380.0); // V setpoint 380.0 |
| 292 | + double expectedQmax = -bMin * v * v; |
| 293 | + assertEquals(1444.0, expectedQmax); |
| 294 | + // Given q matching Qmax |
| 295 | + when(svcTerminal.getQ()).thenReturn(expectedQmax); |
| 296 | + assertTrue(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE)); |
| 297 | + // Given q not matching Qmax |
| 298 | + when(svcTerminal.getQ()).thenReturn(1300.0); |
| 299 | + assertFalse(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE)); |
| 300 | + } |
| 301 | + |
| 302 | + |
| 303 | + // Rule 4: regulationMode = VOLTAGE |
| 304 | + // Test condition: V regulation > V setPoint, then Q must match minQ. |
| 305 | + @Test |
| 306 | + void checkSVCVoltageModeVHigherThanSetpoint() { |
| 307 | + // Given regulation enabled, and regulationMode is VOLTAGE |
| 308 | + when(svc.getRegulationMode()).thenReturn(RegulationMode.VOLTAGE); |
| 309 | + when(svc.isRegulating()).thenReturn(true); |
| 310 | + when(svcTerminal.getP()).thenReturn(0.0); |
| 311 | + // Given V controlled > V setpoint |
| 312 | + Terminal regulatingTerminal = regulatingTerminalWithVoltage(400.0); // V controlled = 400.0 |
| 313 | + when(svc.getRegulatingTerminal()).thenReturn(regulatingTerminal); |
| 314 | + when(svc.getVoltageSetpoint()).thenReturn(380.0); // V setpoint 380.0 |
| 315 | + double expectedQmin = -bMax * v * v; |
| 316 | + assertEquals(-14440.0, expectedQmin); |
| 317 | + // Given q matching Qmin |
| 318 | + when(svcTerminal.getQ()).thenReturn(expectedQmin); |
| 319 | + assertTrue(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE)); |
| 320 | + // Given q not matching Qmin |
| 321 | + when(svcTerminal.getQ()).thenReturn(-13000.0); |
| 322 | + assertFalse(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE)); |
| 323 | + } |
| 324 | + |
| 325 | + // Rule 4: regulationMode = VOLTAGE |
| 326 | + // Test condition: V regulation ~ V setPoint, then Q must be within [minQ, maxQ]. |
| 327 | + @Test |
| 328 | + void checkSVCVoltageModeVAtSetpoint() { |
| 329 | + // Given regulation enabled, and regulationMode is VOLTAGE |
| 330 | + when(svc.getRegulationMode()).thenReturn(RegulationMode.VOLTAGE); |
| 331 | + when(svc.isRegulating()).thenReturn(true); |
| 332 | + when(svcTerminal.getP()).thenReturn(0.0); |
| 333 | + // Given V controlled ~ V setpoint |
| 334 | + Terminal regulatingTerminal = regulatingTerminalWithVoltage(380.0); // V controlled = 380.0.0 |
| 335 | + when(svc.getRegulatingTerminal()).thenReturn(regulatingTerminal); |
| 336 | + when(svc.getVoltageSetpoint()).thenReturn(380.0); // V setpoint 380.0 |
| 337 | + double expectedQmax = -bMin * v * v; |
| 338 | + assertEquals(1444.0, expectedQmax); |
| 339 | + double expectedQmin = -bMax * v * v; |
| 340 | + assertEquals(-14440.0, expectedQmin); |
| 341 | + // Given q inside bounds [-14440.0, 1444.0] |
| 342 | + when(svcTerminal.getQ()).thenReturn(0.0); // inside bounds [-14440.0, 1444.0] |
| 343 | + assertTrue(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE)); |
| 344 | + // Given q outside bounds [-14440.0, 1444.0] |
| 345 | + when(svcTerminal.getQ()).thenReturn(2000.0); |
| 346 | + assertFalse(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE)); |
| 347 | + } |
| 348 | + |
| 349 | + // Rule 5: if regulating is false then reactive power (Q) should be equal to 0 (within threshold) |
| 350 | + @Test |
| 351 | + void checkSVCWhenNoRegulatingQShouldBeZero() { |
| 352 | + when(svc.getRegulationMode()).thenReturn(RegulationMode.VOLTAGE); |
| 353 | + when(svc.isRegulating()).thenReturn(false); |
| 354 | + when(svcTerminal.getP()).thenReturn(0.0); |
| 355 | + when(svcTerminal.getQ()).thenReturn(0.009); // ~ threshold => invalid result |
| 356 | + assertTrue(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE)); |
| 357 | + when(svcTerminal.getQ()).thenReturn(0.02); // > threshold => invalid result |
| 358 | + assertFalse(StaticVarCompensatorsValidation.INSTANCE.checkSVCs(svc, strictConfig, NullWriter.INSTANCE)); |
| 359 | + } |
| 360 | + |
| 361 | + private Terminal regulatingTerminalWithVoltage(double vControlled) { |
| 362 | + Bus controlledBus = mock(Bus.class); |
| 363 | + when(controlledBus.getV()).thenReturn(vControlled); |
| 364 | + |
| 365 | + BusView controlledBusView = mock(BusView.class); |
| 366 | + when(controlledBusView.getBus()).thenReturn(controlledBus); |
| 367 | + |
| 368 | + Terminal regulatingTerminal = mock(Terminal.class); |
| 369 | + when(regulatingTerminal.getBusView()).thenReturn(controlledBusView); |
| 370 | + return regulatingTerminal; |
| 371 | + } |
221 | 372 | } |
0 commit comments