-
Notifications
You must be signed in to change notification settings - Fork 8
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
Maintain power factor constant on loads during slack distribution #170
Changes from 2 commits
f6b82b5
757364e
1b500df
06b19e9
97e52bb
c862ba3
f36e241
b9cd0bc
9abfe0c
ce468d1
2b890d6
5f6d9a4
e9cf603
64fbdd1
d0708d5
9dd5da3
88371cd
5bebe97
c95d352
e9aedff
671e350
8b25121
8f16cc5
a24750b
ff60ee3
d07e80b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,10 +24,12 @@ public class DistributedSlackOnLoadOuterLoop extends AbstractDistributedSlackOut | |
private static final Logger LOGGER = LoggerFactory.getLogger(DistributedSlackOnLoadOuterLoop.class); | ||
|
||
private boolean distributedSlackOnConformLoad = false; | ||
private boolean powerFactorConstant = false; | ||
|
||
public DistributedSlackOnLoadOuterLoop(boolean throwsExceptionInCaseOfFailure, boolean distributedSlackOnConformLoad) { | ||
public DistributedSlackOnLoadOuterLoop(boolean throwsExceptionInCaseOfFailure, boolean distributedSlackOnConformLoad, boolean powerFactorConstant) { | ||
super(throwsExceptionInCaseOfFailure); | ||
this.distributedSlackOnConformLoad = distributedSlackOnConformLoad; | ||
this.powerFactorConstant = powerFactorConstant; | ||
} | ||
|
||
@Override | ||
|
@@ -63,24 +65,30 @@ public double run(List<ParticipatingElement<LfBus>> participatingElements, int i | |
LfBus bus = participatingBus.element; | ||
double factor = participatingBus.factor; | ||
|
||
double targetP = bus.getLoadTargetP(); | ||
double newTargetP = targetP - remainingMismatch * factor; | ||
double loadTargetP = bus.getLoadTargetP(); | ||
double newLoadTargetP = loadTargetP - remainingMismatch * factor; | ||
|
||
// We stop when the load produces power. | ||
if (newTargetP <= 0) { | ||
newTargetP = 0; | ||
if (newLoadTargetP <= 0) { | ||
newLoadTargetP = 0; | ||
loadsAtMin++; | ||
it.remove(); | ||
} | ||
|
||
if (newTargetP != targetP) { | ||
if (LOGGER.isTraceEnabled()) { | ||
LOGGER.trace("Rescale '{}' active power target: {} -> {}", | ||
bus.getId(), targetP * PerUnit.SB, newTargetP * PerUnit.SB); | ||
if (newLoadTargetP != loadTargetP) { | ||
LOGGER.trace("Rescale '{}' active power target: {} -> {}", | ||
bus.getId(), loadTargetP * PerUnit.SB, newLoadTargetP * PerUnit.SB); | ||
if (powerFactorConstant) { // https://github.com/powsybl/powsybl-open-loadflow/issues/110 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think a sentence to explain the purpose of this block of code would be more useful and convenient than a link to the issue lists. |
||
double loadTargetQ = bus.getLoadTargetQ(); | ||
// keep power factor constant by using rule of three | ||
double newLoadTargetQ = loadTargetQ * newLoadTargetP / loadTargetP; | ||
LOGGER.trace("Rescale '{}' reactive power target on load: {} -> {}", | ||
bus.getId(), loadTargetQ * PerUnit.SB, newLoadTargetQ * PerUnit.SB); | ||
bus.setLoadTargetQ(newLoadTargetQ); | ||
} | ||
|
||
bus.setLoadTargetP(newTargetP); | ||
done += targetP - newTargetP; | ||
bus.setLoadTargetP(newLoadTargetP); | ||
done += loadTargetP - newLoadTargetP; | ||
modifiedBuses++; | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,6 +53,8 @@ public abstract class AbstractLfBus implements LfBus { | |
|
||
protected int positiveLoadCount = 0; | ||
|
||
protected double initialLoadTargetQ = 0; | ||
|
||
protected double loadTargetQ = 0; | ||
|
||
protected double generationTargetQ = 0; | ||
|
@@ -216,6 +218,7 @@ private List<String> getGeneratorIds() { | |
void addLoad(Load load) { | ||
loads.add(load); | ||
initialLoadTargetP += load.getP0(); | ||
initialLoadTargetQ += load.getQ0(); | ||
loadTargetP += load.getP0(); | ||
LoadDetail loadDetail = load.getExtension(LoadDetail.class); | ||
if (loadDetail != null) { | ||
|
@@ -230,6 +233,7 @@ void addLoad(Load load) { | |
void addBattery(Battery battery) { | ||
batteries.add(battery); | ||
initialLoadTargetP += battery.getP0(); | ||
initialLoadTargetQ += battery.getQ0(); | ||
loadTargetP += battery.getP0(); | ||
loadTargetQ += battery.getQ0(); | ||
} | ||
|
@@ -341,6 +345,11 @@ public double getLoadTargetQ() { | |
return loadTargetQ / PerUnit.SB; | ||
} | ||
|
||
@Override | ||
public void setLoadTargetQ(double loadTargetQ) { | ||
this.loadTargetQ = loadTargetQ * PerUnit.SB; | ||
} | ||
|
||
private double getLimitQ(ToDoubleFunction<LfGenerator> limitQ) { | ||
return generators.stream() | ||
.mapToDouble(generator -> generator.hasVoltageControl() ? limitQ.applyAsDouble(generator) | ||
|
@@ -459,11 +468,12 @@ public void updateState(boolean reactiveLimits, boolean writeSlackBus) { | |
updateGeneratorsState(voltageControl ? calculatedQ + loadTargetQ : generationTargetQ, reactiveLimits); | ||
|
||
// update load power | ||
double factor = initialLoadTargetP != 0 ? loadTargetP / initialLoadTargetP : 1; | ||
double factorP = initialLoadTargetP != 0 ? loadTargetP / initialLoadTargetP : 1; | ||
double factorQ = initialLoadTargetQ != 0 ? loadTargetQ / initialLoadTargetQ : 1; | ||
for (Load load : loads) { | ||
load.getTerminal() | ||
.setP(load.getP0() >= 0 ? factor * load.getP0() : load.getP0()) | ||
.setQ(load.getQ0()); | ||
.setP(load.getP0() >= 0 ? factorP * load.getP0() : load.getP0()) | ||
.setQ(load.getQ0() >= 0 ? factorQ * load.getQ0() : load.getQ0()); | ||
Comment on lines
+485
to
+486
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @annetill: why do we distinguish positive and negative loads? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think these tests are not useful, I have to check. |
||
} | ||
|
||
// update battery power (which are not part of slack distribution) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,9 @@ public final class ParameterConstants { | |
public static final String LOW_IMPEDANCE_BRANCH_MODE_PARAM_NAME = "lowImpedanceBranchMode"; | ||
public static final LowImpedanceBranchMode LOW_IMPEDANCE_BRANCH_MODE_DEFAULT_VALUE = LowImpedanceBranchMode.REPLACE_BY_ZERO_IMPEDANCE_LINE; | ||
|
||
public static final String POWER_FACTOR_CONSTANT_PARAM_NAME = "powerFactorConstant"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not forget to increase documentation. Our web site is here: https://github.com/powsybl/powsybl.github.io There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you find the related page? it's that one: pages/documentation/simulation/powerflow/openlf.md |
||
public static final boolean POWER_FACTOR_CONSTANT_DEFAULT_VALUE = false; | ||
|
||
private ParameterConstants() { | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,10 +7,14 @@ | |
package com.powsybl.openloadflow.util; | ||
|
||
import com.powsybl.iidm.network.Bus; | ||
import com.powsybl.iidm.network.Load; | ||
import com.powsybl.iidm.network.Network; | ||
import com.powsybl.iidm.network.Terminal; | ||
import com.powsybl.loadflow.LoadFlowResult; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
import java.util.Iterator; | ||
|
||
import static org.junit.jupiter.api.Assertions.*; | ||
|
||
/** | ||
* @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com> | ||
|
@@ -47,4 +51,56 @@ public static void assertUndefinedActivePower(Terminal terminal) { | |
public static void assertUndefinedReactivePower(Terminal terminal) { | ||
assertTrue(Double.isNaN(terminal.getQ())); | ||
} | ||
|
||
private static void assertPowerFactor(Network network, boolean isPowerFactorConstant) { | ||
Iterator<Load> loads = network.getLoads().iterator(); | ||
while (loads.hasNext()) { | ||
Load load = loads.next(); | ||
load.getTerminal().getQ(); | ||
if (isPowerFactorConstant) { | ||
assertEquals(Math.round(1000000 * load.getP0() / load.getQ0()), | ||
Math.round(1000000 * load.getTerminal().getP() / load.getTerminal().getQ()), | ||
"power factor should be a constant value"); | ||
} else { | ||
assertNotEquals(Math.round(1000000 * load.getP0() / load.getQ0()), | ||
Math.round(1000000 * load.getTerminal().getP() / load.getTerminal().getQ()), | ||
"power factor should not be a constant value"); | ||
} | ||
} | ||
|
||
} | ||
|
||
public static void assertPowerFactorNotConstant(Network network) { | ||
assertPowerFactor(network, false); | ||
} | ||
|
||
public static void assertPowerFactorConstant(Network network) { | ||
assertPowerFactor(network, true); | ||
} | ||
|
||
public static void assertBetterLoadFlowResults(LoadFlowResult loadFlowResult, LoadFlowResult loadFlowResultBetter) { | ||
assertTrue(loadFlowResult.isOk(), "results should be ok"); | ||
assertTrue(loadFlowResultBetter.isOk(), "results should be ok"); | ||
assertEquals(loadFlowResult.getComponentResults().size(), | ||
loadFlowResultBetter.getComponentResults().size(), | ||
"results should have same subnetwork count"); | ||
Iterator<LoadFlowResult.ComponentResult> componentResultIterator = loadFlowResult.getComponentResults().iterator(); | ||
Iterator<LoadFlowResult.ComponentResult> componentResultIteratorBetter = loadFlowResultBetter.getComponentResults().iterator(); | ||
// loop over sub networks | ||
while (componentResultIterator.hasNext()) { | ||
LoadFlowResult.ComponentResult componentResult = componentResultIterator.next(); | ||
LoadFlowResult.ComponentResult componentResultBetter = componentResultIteratorBetter.next(); | ||
assertEquals(componentResult.getComponentNum(), | ||
componentResultBetter.getComponentNum(), | ||
"this assert has a bug, please fix it"); | ||
assertEquals(componentResult.getSlackBusId(), | ||
componentResultBetter.getSlackBusId(), | ||
"this assert has a bug, please fix it"); | ||
assertEquals(componentResult.getStatus(), | ||
componentResultBetter.getStatus(), | ||
"status results should be the same"); | ||
assertTrue(componentResult.getIterationCount() >= componentResultBetter.getIterationCount(), "iteration count should be the same or lower for improved result"); | ||
assertTrue(Math.abs(componentResult.getSlackBusActivePowerMismatch()) >= Math.abs(componentResultBetter.getSlackBusActivePowerMismatch()), "mismatch should be the same or lower for improved result"); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As @annetill said, I'm not sure to understand this assessment. From my point of view, you should assert that the results are the expected one, not that the results are closed to the other one |
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two fields should be final?