-
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
Conversation
@Test | ||
void testPowerFactorConstant() { | ||
// given | ||
Network testNetwork = Importers.loadNetwork(Paths.get("src", "test", "resources", "2.xiidm")); |
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.
Use Network network = EurostagTutorialExample1Factory.create();
instead.
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.
And thus delete the 2.xiidm
file.
@@ -47,4 +50,22 @@ public static void assertUndefinedActivePower(Terminal terminal) { | |||
public static void assertUndefinedReactivePower(Terminal terminal) { | |||
assertTrue(Double.isNaN(terminal.getQ())); | |||
} | |||
|
|||
public static void assertBetterResults(LoadFlowResult loadFlowResult, LoadFlowResult loadFlowResultBetter) { |
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.
Use assertLoadFlowResults
instead of this name choice.
assertEquals(componentResult.getSlackBusId(), componentResultBetter.getSlackBusId(), "this assert has a bug, please fix it"); | ||
assertEquals(componentResult.getStatus(), componentResultBetter.getStatus(), "status results should be the same"); | ||
assertEquals(componentResult.getIterationCount(), componentResultBetter.getIterationCount(), "iteration count results should be the same"); | ||
assertTrue(Math.abs(componentResult.getSlackBusActivePowerMismatch()) > Math.abs(componentResultBetter.getSlackBusActivePowerMismatch()), "it was expected that improved process returns a better result"); |
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.
Why are you not doing here an assertEquals ?
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.
It seems ending mismatch is smaller by making power factor
a constant value.
Is it true ?
That's why my assert was called assertBetterResults.
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.
I'm not sure this is true for all cases, but just a lucky side effect
LoadFlowResult loadFlowResult2 = loadFlowRunner.run(testNetwork, parameters); | ||
|
||
// then | ||
assertBetterResults(loadFlowResult1, loadFlowResult2); |
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.
I am not sure to understand why a result should be better than another one. Here the idea is to assert the reactive power that has changed in the second run. The assert on LoadFlowResults could be interested if you give reference loadflow results to avoid regression.
@@ -28,6 +28,9 @@ | |||
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 comment
The 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 comment
The 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
private LoadFlowParameters loadFlowParameters; | ||
private OpenLoadFlowParameters openLoadFlowParameters; | ||
|
||
public DistributedSlackOnLoadOuterLoop(LoadFlowParameters loadFlowParameters, |
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.
Can you here have as arguments only the parameters you need for this outerloop ?
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.
From my mind, it's better to pass the two parameters objects instead of multiple primitive types ?
Moreover this code is done only in DistributedSlackOnLoadOuterLoop constructor (not in callers) :
this.distributedSlackOnConformLoad = loadFlowParameters.getBalanceType() == LoadFlowParameters.BalanceType.PROPORTIONAL_TO_CONFORM_LOAD;
So keep or not ?
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.
I agree with Anne, here (as very often) it's better to have only the parameters you need in the constructor. That allows to see clearly which parameters affect the outerloop without even looking at the code in the outerloop. At the cost of more parameters for you to type, sure! Moreover, (very) minor thing, here you're testing twice the balance type.
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.
Could you also please fix the DCO. You should configure your IDE to not forget it for your next commits. Please read the contributing guide if not already done.
return powerFactorConstant; | ||
} | ||
|
||
public void setPowerFactorConstant(boolean powerFactorConstant) { |
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.
We use a fluent API here: could you please follow the same way to implement setters?
bus.getId(), targetP * PerUnit.SB, newTargetP * PerUnit.SB); | ||
bus.getId(), loadTargetP * PerUnit.SB, newLoadTargetP * PerUnit.SB); | ||
} | ||
if (this.openLoadFlowParameters.isPowerFactorConstant()) { // https://github.com/powsybl/powsybl-open-loadflow/issues/110 |
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.
There is no need to prefix the openLoadFlowParaterers with this
assertEquals(componentResult.getIterationCount(), componentResultBetter.getIterationCount(), "iteration count results should be the same"); | ||
assertTrue(Math.abs(componentResult.getSlackBusActivePowerMismatch()) > Math.abs(componentResultBetter.getSlackBusActivePowerMismatch()), "it was expected that improved process returns a better result"); | ||
} | ||
} |
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.
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
…ent-726812696 Signed-off-by: Fabien Rigaux <fabien.rigaux@free.fr>
fe68636
to
f6b82b5
Compare
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.
More general comments:
- Please do not force-push after review, it makes it more difficult to see what recent changes you made. Which changes did you make with this morning's force push btw?
- Please follow the guidelines for the commit message - or at least do not tick the box if you don't (I unticked it)!
- In open-loadflow we require 90% coverage to merge a PR (the code coverage is above 92% so far in that repo), so please look at which conditions / lines are not covered with sonar and improve your tests to cover them
public DistributedSlackOnLoadOuterLoop(boolean throwsExceptionInCaseOfFailure, boolean distributedSlackOnConformLoad) { | ||
super(throwsExceptionInCaseOfFailure); | ||
this.distributedSlackOnConformLoad = distributedSlackOnConformLoad; | ||
private LoadFlowParameters loadFlowParameters; |
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.
Field not used, remove it.
super(throwsExceptionInCaseOfFailure); | ||
this.distributedSlackOnConformLoad = distributedSlackOnConformLoad; | ||
private LoadFlowParameters loadFlowParameters; | ||
private OpenLoadFlowParameters openLoadFlowParameters; |
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.
There's no use keeping the whole OpenLoadFlowParameters, remove it. Indeed, you only need to keep the value returned by isPowerFactorConstant().
private LoadFlowParameters loadFlowParameters; | ||
private OpenLoadFlowParameters openLoadFlowParameters; | ||
|
||
public DistributedSlackOnLoadOuterLoop(LoadFlowParameters loadFlowParameters, |
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.
I agree with Anne, here (as very often) it's better to have only the parameters you need in the constructor. That allows to see clearly which parameters affect the outerloop without even looking at the code in the outerloop. At the cost of more parameters for you to type, sure! Moreover, (very) minor thing, here you're testing twice the balance type.
double loadTargetQ = bus.getLoadTargetQ(); | ||
// keep power factor constant by using rule of three | ||
double newLoadTargetQ = loadTargetQ * newLoadTargetP / loadTargetP; | ||
if (LOGGER.isTraceEnabled()) { |
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.
Remove that if (and the existing similar if above), it's weighing down the code to only avoid the 2 multiplications by PerUnit.SB. Remember that the string concatenation is not done anyway if trace is not enabled.
@@ -28,6 +28,9 @@ | |||
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 comment
The 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
@Test | ||
void testPowerFactorConstant() { | ||
// given | ||
Network testNetwork = Importers.loadNetwork(Paths.get("src", "test", "resources", "2.xiidm")); |
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.
And thus delete the 2.xiidm
file.
…dFlowEngine, update Network Loads with new Q value in AbstractLfBus. Signed-off-by: Fabien Rigaux <fabien.rigaux@free.fr>
private boolean distributedSlackOnConformLoad = false; | ||
private boolean powerFactorConstant = false; |
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?
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 comment
The 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.
.setP(load.getP0() >= 0 ? factorP * load.getP0() : load.getP0()) | ||
.setQ(load.getQ0() >= 0 ? factorQ * load.getQ0() : load.getQ0()); |
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.
@annetill: why do we distinguish positive and negative loads?
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.
I think these tests are not useful, I have to check.
Mathieu request changes (PR 170) : Resolved request changes Signed-off-by: Fabien Rigaux <fabien.rigaux@free.fr>
Signed-off-by: Fabien Rigaux <fabien.rigaux@free.fr>
…powerFactorConstant = true» in this case, we have to remain power factor constant on variable power for P and Q Signed-off-by: Fabien Rigaux <fabien.rigaux@free.fr>
… mvn test) : cannot do assertEquals with full precision on slackBusActivePowerMismatch, between Java 8 to Java 11, it seems double primitive type has some differences between Signed-off-by: Fabien Rigaux <fabien.rigaux@free.fr>
use delta from assert instead of Math.round Signed-off-by: Fabien Rigaux <fabien.rigaux@free.fr>
Signed-off-by: Anne Tilloy <anne.tilloy@rte-france.com>
Signed-off-by: Anne Tilloy <anne.tilloy@rte-france.com>
Signed-off-by: Fabien Rigaux <fabien.rigaux@free.fr>
} | ||
|
||
private double getVariableLoadTargetP(LfBus bus) { | ||
return distributedSlackOnConformLoad ? bus.getLoadTargetP() - bus.getFixedLoadTargetP() : bus.getLoadTargetP(); | ||
} | ||
|
||
private double getVariableLoadTargetQAgainstVariableLoadTargetP(LfBus bus) { | ||
return distributedSlackOnConformLoad ? (bus.getLoadTargetQ() - bus.getFixedLoadTargetQ()) / (bus.getLoadTargetP() - bus.getFixedLoadTargetP()) |
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.
Maybe check that bus.getLoadTargetP() != bus.getFixedLoadTargetP() to avoid the division by 0.
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.
Don't know why, but it seems we cannot get division by 0 in reality (tested with recollement-auto-20190124-2110-enrichi.xiidm) ?!?
However we can fix this in getVariableLoadTargetQAgainstVariableLoadTargetP with :
- throwing a ComputationException ?
- or returning 0 ?
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.
Indeed you check before that the variable part is greater than zero to participate.
…wsybl-open-loadflow into power_factor_constant
Signed-off-by: Anne Tilloy <anne.tilloy@rte-france.com>
Signed-off-by: Anne Tilloy <anne.tilloy@rte-france.com>
# Conflicts: # src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java
Signed-off-by: Geoffroy Jamgotchian <geoffroy.jamgotchian@rte-france.com>
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.
As loadTargetQ might be modified, it has to be taken into account in security analysis state restoration (between 2 contingencies)
Signed-off-by: Anne Tilloy <anne.tilloy@rte-france.com>
…ty from 16 to the 15 allowed." Signed-off-by: Fabien Rigaux <fabien.rigaux@free.fr>
Signed-off-by: Anne Tilloy <anne.tilloy@rte-france.com>
…wsybl-open-loadflow into power_factor_constant
Signed-off-by: Florian Dupuy <florian.dupuy@rte-france.com>
Signed-off-by: Florian Dupuy <florian.dupuy@rte-france.com>
Kudos, SonarCloud Quality Gate passed! |
Power Factor Constant
Please check if the PR fulfills these requirements (please use
'[x]'
to check the checkboxes, or submit the PR and then click the checkboxes)Does this PR already have an issue describing the problem ? If so, link to this issue using
'#XXX'
and skip the rest#110 (comment)
What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)
Feature : add "power factor constant" support
What is the current behavior? (You can also link to an open issue here)
What is the new behavior (if this is a feature change)?
Improve equation resolution by Newton-Raphson with "powerFactorConstant: true" in config.yml (open-loadflow-default-parameters)
Does this PR introduce a breaking change or deprecate an API? If yes, check the following:
Other information:
(if any of the questions/checkboxes don't apply, please delete them entirely)