Skip to content
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

Merged
merged 26 commits into from
Dec 1, 2020

Conversation

frigaux
Copy link
Contributor

@frigaux frigaux commented Nov 17, 2020

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)

  • The commit message follows our guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

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:

  • The Breaking Change or Deprecated label has been added
  • The migration guide has been updated in the github wiki (What changes might users need to make in their application due to this PR?)

Other information:

(if any of the questions/checkboxes don't apply, please delete them entirely)

@frigaux frigaux changed the title https://github.com/powsybl/powsybl-open-loadflow/issues/110#issuecomm… Power Factor Constant Nov 17, 2020
@annetill annetill requested review from annetill and flo-dup November 17, 2020 13:27
@Test
void testPowerFactorConstant() {
// given
Network testNetwork = Importers.loadNetwork(Paths.get("src", "test", "resources", "2.xiidm"));
Copy link
Member

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.

Copy link
Contributor

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) {
Copy link
Member

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");
Copy link
Member

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 ?

Copy link
Contributor Author

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.

Copy link
Contributor

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);
Copy link
Member

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";
Copy link
Member

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

Copy link
Contributor

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,
Copy link
Member

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 ?

Copy link
Contributor Author

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 ?

Copy link
Contributor

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.

Copy link
Contributor

@mathbagu mathbagu left a 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) {
Copy link
Contributor

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
Copy link
Contributor

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");
}
}
Copy link
Contributor

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>
@frigaux frigaux force-pushed the power_factor_constant branch from fe68636 to f6b82b5 Compare November 18, 2020 09:06
Copy link
Contributor

@flo-dup flo-dup left a 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;
Copy link
Contributor

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;
Copy link
Contributor

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,
Copy link
Contributor

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()) {
Copy link
Contributor

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";
Copy link
Contributor

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"));
Copy link
Contributor

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>
Comment on lines 26 to 27
private boolean distributedSlackOnConformLoad = false;
private boolean powerFactorConstant = false;
Copy link
Contributor

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
Copy link
Contributor

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.

Comment on lines +475 to +476
.setP(load.getP0() >= 0 ? factorP * load.getP0() : load.getP0())
.setQ(load.getQ0() >= 0 ? factorQ * load.getQ0() : load.getQ0());
Copy link
Contributor

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?

Copy link
Member

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.

frigaux and others added 6 commits November 19, 2020 10:57
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>
@annetill annetill requested a review from flo-dup November 24, 2020 12:06
annetill and others added 2 commits November 24, 2020 14:28
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())
Copy link
Contributor

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.

Copy link
Contributor Author

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 ?

Copy link
Member

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.

Signed-off-by: Anne Tilloy <anne.tilloy@rte-france.com>
@annetill annetill changed the title Power Factor Constant Maintain power factor constant on loads during slack distribution Nov 24, 2020
annetill and others added 5 commits November 24, 2020 17:24
Signed-off-by: Anne Tilloy <anne.tilloy@rte-france.com>
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>
Copy link
Member

@geofjamg geofjamg left a 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)

annetill and others added 8 commits November 27, 2020 18:00
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>
Signed-off-by: Anne Tilloy <anne.tilloy@rte-france.com>
Signed-off-by: Florian Dupuy <florian.dupuy@rte-france.com>
Signed-off-by: Florian Dupuy <florian.dupuy@rte-france.com>
@sonarqubecloud
Copy link

sonarqubecloud bot commented Dec 1, 2020

Kudos, SonarCloud Quality Gate passed!

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

90.0% 90.0% Coverage
0.0% 0.0% Duplication

@annetill annetill merged commit a66ea7d into master Dec 1, 2020
@annetill annetill deleted the power_factor_constant branch December 1, 2020 15:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants