Skip to content

Commit

Permalink
fix dispatchQ method
Browse files Browse the repository at this point in the history
Signed-off-by: Etienne LESOT <etienne.lesot@rte-france.com>
  • Loading branch information
EtienneLt committed May 4, 2022
1 parent 9215b2c commit 7fcc012
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -415,22 +415,26 @@ public void addHvdc(LfHvdc hvdc) {
hvdcs.add(Objects.requireNonNull(hvdc));
}

private static double dispatchQ(List<LfGenerator> generatorsThatControlVoltage, boolean reactiveLimits, double qToDispatch) {
protected static double dispatchQ(List<LfGenerator> generatorsThatControlVoltage, boolean reactiveLimits, double qToDispatch) {
double residueQ = 0;
double calculatedQ = qToDispatch / generatorsThatControlVoltage.size();
if (generatorsThatControlVoltage.isEmpty()) {
throw new IllegalArgumentException("the generator list to dispatch Q can not be empty");
}
double qToBeDispatchedByGenerator = qToDispatch / generatorsThatControlVoltage.size();
Iterator<LfGenerator> itG = generatorsThatControlVoltage.iterator();
while (itG.hasNext()) {
LfGenerator generator = itG.next();
if (reactiveLimits && calculatedQ < generator.getMinQ()) {
generator.setCalculatedQ(generator.getCalculatedQ() + generator.getMinQ());
residueQ += calculatedQ - generator.getMinQ();
double generatorAlreadyCalculatedQ = generator.getCalculatedQ();
if (reactiveLimits && qToBeDispatchedByGenerator + generatorAlreadyCalculatedQ < generator.getMinQ()) {
residueQ += qToBeDispatchedByGenerator + generatorAlreadyCalculatedQ - generator.getMinQ();
generator.setCalculatedQ(generator.getMinQ());
itG.remove();
} else if (reactiveLimits && calculatedQ > generator.getMaxQ()) {
generator.setCalculatedQ(generator.getCalculatedQ() + generator.getMaxQ());
residueQ += calculatedQ - generator.getMaxQ();
} else if (reactiveLimits && qToBeDispatchedByGenerator + generatorAlreadyCalculatedQ > generator.getMaxQ()) {
residueQ += qToBeDispatchedByGenerator + generatorAlreadyCalculatedQ - generator.getMaxQ();
generator.setCalculatedQ(generator.getMaxQ());
itG.remove();
} else {
generator.setCalculatedQ(generator.getCalculatedQ() + calculatedQ);
generator.setCalculatedQ(generatorAlreadyCalculatedQ + qToBeDispatchedByGenerator);
}
}
return residueQ;
Expand Down Expand Up @@ -458,7 +462,7 @@ void updateGeneratorsState(double generationQ, boolean reactiveLimits) {
@Override
public void updateState(boolean reactiveLimits, boolean writeSlackBus, boolean distributedOnConformLoad, boolean loadPowerFactorConstant) {
// update generator reactive power
updateGeneratorsState(voltageControlEnabled ? q.eval() * PerUnit.SB + loadTargetQ : generationTargetQ, reactiveLimits);
updateGeneratorsState(voltageControlEnabled ? q.eval() * PerUnit.SB + loadTargetQ : generationTargetQ, reactiveLimits);

// update load power
lfLoads.updateState(getLoadTargetP() - getInitialLoadTargetP(), loadPowerFactorConstant);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,4 +409,26 @@ void testWithDisconnectedGenerator() {
assertActivePowerEquals(Double.NaN, gen.getTerminal());
assertReactivePowerEquals(Double.NaN, gen.getTerminal());
}

@Test
void testGeneratorReactiveLimits() {
Network network = EurostagTutorialExample1Factory.create();
network.getGenerator("GEN").newMinMaxReactiveLimits().setMinQ(0).setMaxQ(120).add();
network.getVoltageLevel("VLGEN").newGenerator().setId("GEN1")
.setBus("NGEN").setConnectableBus("NGEN")
.setMinP(-9999.99D).setMaxP(9999.99D)
.setVoltageRegulatorOn(true).setTargetV(24.5D)
.setTargetP(607.0D).setTargetQ(301.0D).add();
network.getGenerator("GEN1").newMinMaxReactiveLimits().setMinQ(0).setMaxQ(220).add();
LoadFlowParameters parameters = new LoadFlowParameters().setNoGeneratorReactiveLimits(false)
.setDistributedSlack(false)
.setVoltageInitMode(LoadFlowParameters.VoltageInitMode.DC_VALUES);
loadFlowRunner.run(network, parameters);
network.getGenerators().forEach(gen -> {
if (gen.getReactiveLimits() instanceof MinMaxReactiveLimits) {
assertTrue(-gen.getTerminal().getQ() <= ((MinMaxReactiveLimits) gen.getReactiveLimits()).getMaxQ());
assertTrue(-gen.getTerminal().getQ() >= ((MinMaxReactiveLimits) gen.getReactiveLimits()).getMinQ());
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.VoltagePerReactivePowerControlAdder;
import com.powsybl.iidm.network.test.EurostagTutorialExample1Factory;
import com.powsybl.iidm.network.test.FourSubstationsNodeBreakerFactory;
import com.powsybl.openloadflow.network.LfGenerator;
import com.powsybl.openloadflow.network.LfNetwork;
import com.powsybl.openloadflow.network.MostMeshedSlackBusSelector;
Expand All @@ -17,6 +18,8 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static com.powsybl.openloadflow.util.LoadFlowAssert.DELTA_POWER;
Expand Down Expand Up @@ -142,4 +145,76 @@ void updateGeneratorsStateTest() {
}
Assertions.assertEquals(generationQ, sumQ, DELTA_POWER, "sum of generators calculatedQ should be equals to qToDispatch");
}

private List<LfGenerator> createLfGeneratorsWithInitQ(List<Double> initQs) {
Network network = FourSubstationsNodeBreakerFactory.create();
LfNetworkLoadingReport lfNetworkLoadingReport = new LfNetworkLoadingReport();
LfGenerator lfGenerator1 = LfGeneratorImpl.create(network.getGenerator("GH1"),
false, 100, true, lfNetworkLoadingReport);
lfGenerator1.setCalculatedQ(initQs.get(0));
LfGenerator lfGenerator2 = LfGeneratorImpl.create(network.getGenerator("GH2"),
false, 200, true, lfNetworkLoadingReport);
lfGenerator2.setCalculatedQ(initQs.get(1));
LfGenerator lfGenerator3 = LfGeneratorImpl.create(network.getGenerator("GH3"),
false, 200, true, lfNetworkLoadingReport);
lfGenerator3.setCalculatedQ(initQs.get(2));
List<LfGenerator> generators = new ArrayList<>();
generators.add(lfGenerator1);
generators.add(lfGenerator2);
generators.add(lfGenerator3);
return generators;
}

@Test
void dispatchQForMaxTest() {
List<LfGenerator> generators = createLfGeneratorsWithInitQ(Arrays.asList(0d, 0d, 0d));
LfGenerator generatorToRemove = generators.get(1);
double qToDispatch = 21;
double residueQ = AbstractLfBus.dispatchQ(generators, true, qToDispatch);
double totalCalculatedQ = generators.get(0).getCalculatedQ() + generators.get(1).getCalculatedQ() + generatorToRemove.getCalculatedQ();
Assertions.assertEquals(7.0, generators.get(0).getCalculatedQ());
Assertions.assertEquals(7.0, generators.get(1).getCalculatedQ());
Assertions.assertEquals(2, generators.size());
Assertions.assertEquals(qToDispatch - totalCalculatedQ, residueQ, 0.00001);
Assertions.assertEquals(generatorToRemove.getMaxQ(), generatorToRemove.getCalculatedQ());
}

@Test
void dispatchQTestWithInitialQForMax() {
List<LfGenerator> generators = createLfGeneratorsWithInitQ(Arrays.asList(1.5d, 1d, 3d));
double qInitial = generators.get(0).getCalculatedQ() + generators.get(1).getCalculatedQ() + generators.get(2).getCalculatedQ();
LfGenerator generatorToRemove1 = generators.get(1);
LfGenerator generatorToRemove2 = generators.get(2);
double qToDispatch = 20;
double residueQ = AbstractLfBus.dispatchQ(generators, true, qToDispatch);
double totalCalculatedQ = generators.get(0).getCalculatedQ() + generatorToRemove1.getCalculatedQ() + generatorToRemove2.getCalculatedQ();
Assertions.assertEquals(1, generators.size());
Assertions.assertEquals(qToDispatch + qInitial - totalCalculatedQ, residueQ, 0.0001);
Assertions.assertEquals(8.17, generators.get(0).getCalculatedQ(), 0.01);
Assertions.assertEquals(generatorToRemove1.getMaxQ(), generatorToRemove1.getCalculatedQ(), 0.01);
Assertions.assertEquals(generatorToRemove2.getMaxQ(), generatorToRemove2.getCalculatedQ(), 0.01);
}

@Test
void dispatchQForMinTest() {
List<LfGenerator> generators = createLfGeneratorsWithInitQ(Arrays.asList(0d, 0d, 0d));
LfGenerator generatorToRemove2 = generators.get(1);
LfGenerator generatorToRemove3 = generators.get(2);
double qToDispatch = -21;
double residueQ = AbstractLfBus.dispatchQ(generators, true, qToDispatch);
double totalCalculatedQ = generators.get(0).getCalculatedQ() + generatorToRemove2.getCalculatedQ() + generatorToRemove3.getCalculatedQ();
Assertions.assertEquals(-7.0, generators.get(0).getCalculatedQ());
Assertions.assertEquals(1, generators.size());
Assertions.assertEquals(qToDispatch - totalCalculatedQ, residueQ, 0.00001);
Assertions.assertEquals(generatorToRemove2.getMinQ(), generatorToRemove2.getCalculatedQ());
Assertions.assertEquals(generatorToRemove3.getMinQ(), generatorToRemove3.getCalculatedQ());
}

@Test
void dispatchQEmptyListTest() {
List<LfGenerator> generators = new ArrayList<>();
double qToDispatch = -21;
Assertions.assertThrows(IllegalArgumentException.class, () -> AbstractLfBus.dispatchQ(generators, true, qToDispatch),
"the generator list to dispatch Q can not be empty");
}
}

0 comments on commit 7fcc012

Please sign in to comment.