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

Improve performance of incremental outer loops #895

Merged
merged 22 commits into from
Nov 24, 2023

Conversation

caioluke
Copy link
Member

@caioluke caioluke commented Nov 8, 2023

Please check if the PR fulfills these requirements

  • 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?

What kind of change does this PR introduce?

Performance enhancement

What is the current behavior?

We currently calculate sensitivity for all controllers of the network, even though we won't need them all.

What is the new behavior (if this is a feature change)?
Sensitivities are only calculated for the necessary controllers (outside target/deadband).

Does this PR introduce a breaking change or deprecate an API?

No

Other information:

Signed-off-by: Caio Luke <caioluke97@gmail.com>
Signed-off-by: Caio Luke <caioluke97@gmail.com>
@caioluke caioluke added the enhancement New feature or request label Nov 8, 2023
@caioluke caioluke requested a review from jeandemanged November 8, 2023 17:09
@caioluke caioluke self-assigned this Nov 8, 2023
@caioluke caioluke changed the title [WIP] Improve performance of outerloops with sensitivity (Transformers and Shunt) Improve performance of outerloops with sensitivity (Transformers and Shunt) Nov 8, 2023
Signed-off-by: Caio Luke <caioluke97@gmail.com>
@caioluke caioluke requested a review from geofjamg November 9, 2023 09:32
@geofjamg
Copy link
Member

geofjamg commented Nov 9, 2023

@caioluke is this optimization based on some performance profiles? Do you have observed in a real case a significant performance improvement?

@jeandemanged
Copy link
Member

@geofjamg yes we observed the issue on large networks.
Didn't check code yet but just tested it today.
Performance improvement is quite significative.

Flamegraph before (outerloop is taking more time than the NR ...):
image

Flamegraph after:
image

solution "path" unchanged but much faster (left is before fix, right after fix):
image

@geofjamg
Copy link
Member

geofjamg commented Nov 9, 2023

Indeed.
Do you have the "solve2" individual execution time (before) and how much time it is called?
Also are you able with your profiler to get JNI native function profiling (IntelliJ profiler can do it by changing the option 'Collect native calls") ?

@geofjamg
Copy link
Member

I summarize the discussion I had with @caioluke:

  • it is indeed a good idea to pre-filter controllers that are outside of the dead band
    • it really accelerates the performance, because the more the incremental outerloops are running less there is controller outside of dead band. So firsts outer loops are slow and last are very fast.
    • Even if faster, we still see the sensi calculation of incremental outer loops in profiling so there is room to more optimization.
  • The REAL PROBLEM which is the one to solve is that we are solving a very very sparse second member. Second member is made with a matrix that has only one non zero value per column (and the number of row is the size of the system). KLU library only supports dense second member (this is the normal use so it makes sense). So in our very special way to use KLU for sensi analysis, the KLU_solve and KLU_tsolve functions are very inefficients. Thanks @caioluke @jeandemanged for pointing this I was not aware of it.
  • A solution would be to re-implement our own KLU_solve and KLU_tsolve function. Looking at https://github.com/DrTimothyAldenDavis/SuiteSparse/blob/dev/KLU/Source/klu_sort.c for instance, the code is quite simple and short and could maybe be copy/pasted to work on a sparse second member (instead of a B[], a pair B_values[] and B_Index[]). Performance would be much faster, only processing non zero values.

@jeandemanged @Hadrien-Godard what do you think?

caioluke and others added 5 commits November 20, 2023 12:23
# Conflicts:
#	src/main/java/com/powsybl/openloadflow/ac/outerloop/IncrementalShuntVoltageControlOuterLoop.java
#	src/main/java/com/powsybl/openloadflow/ac/outerloop/IncrementalTransformerVoltageControlOuterLoop.java
Signed-off-by: Caio Luke <caioluke97@gmail.com>
Signed-off-by: Caio Luke <caioluke97@gmail.com>
Signed-off-by: Caio Luke <caioluke97@gmail.com>
double diffV = controlledBus.getHighestPriorityMainVoltageControl().orElseThrow().getTargetValue() - voltageControl.getControlledBus().getV();
double halfTargetDeadband = getHalfTargetDeadband(voltageControl);
if (Math.abs(diffV) > halfTargetDeadband) {
List<LfShunt> controllers = voltageControl.getMergedControllerElements().stream()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a difference here in the way we get controllers from a controlled. In previous code, we use IncrementalContextData.getControllerElements which has a filter on voltage control type. Is it equivalent?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is equivalent. I directly call the method for the specific type of voltage control: getShuntVoltageControl or getTransformerVoltageControl. And I also filter out the disabled controllers.

caioluke and others added 10 commits November 23, 2023 15:37
Signed-off-by: Anne Tilloy <anne.tilloy@rte-france.com>
@@ -191,11 +201,26 @@ private boolean adjustWithSeveralControllers(List<LfBranch> controllerBranches,
}

private static double getDiffV(TransformerVoltageControl voltageControl) {
double targetV = voltageControl.getTargetValue();
double targetV = voltageControl.getControlledBus().getHighestPriorityMainVoltageControl().orElseThrow().getTargetValue();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jeandemanged and @geofjamg bug fix here. We have to check the voltage difference against the voltage control of highest priority, most of the time those of the generator and not those of the transformer.

@annetill
Copy link
Member

Maybe a final performance test is needed before merging and a unit test that shows the bug.

Signed-off-by: Caio Luke <caioluke97@gmail.com>
.setRegulating(true)
.setTapPosition(0)
.setRegulationTerminal(line34.getTerminal2())
.setTargetV(33.0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change this targetV to 30.0 to show the benefit of the bug fix.

Signed-off-by: Anne Tilloy <anne.tilloy@rte-france.com>
@annetill annetill changed the title Improve performance of outerloops with sensitivity (Transformers and Shunt) Improve performance of incremental outer loops Nov 24, 2023
Copy link

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

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

96.3% 96.3% Coverage
0.0% 0.0% Duplication

Copy link
Member

@jeandemanged jeandemanged left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all good, thanks

other improvements (see here) would be in other PRs

@jeandemanged jeandemanged merged commit 3321a02 into main Nov 24, 2023
6 checks passed
@jeandemanged jeandemanged deleted the improve_sentivity_outerloops branch November 24, 2023 17:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants