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

Fix proportional scalable infinite loop #3188

Merged
merged 7 commits into from
Oct 24, 2024
Merged

Conversation

jeandemanged
Copy link
Member

@jeandemanged jeandemanged commented Oct 22, 2024

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?

No

What kind of change does this PR introduce?

Bug fix

What is the current behavior?

Infinite loop in proportional scalable under the following condition:

  • asking a little bit more power than the full available power range over all scalables
  • scalable percentages are low enough so that the difference of asked power minus done power on one scalable falls below the 0.01 MW epsilon

In this case the iteration percentage of the scalable is never set to zero, there is remaining asked power, and the scaling is stuck in an infinite loop.

May sound like a marginal case, but was observed on real data. On large networks a given load may have a small percentage.

What is the new behavior (if this is a feature change)?
We set iteration percentage to zero when a scalable is saturated, in addition to the existing condition checking that not all asked power has been done.

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

  • No

Other information:

Signed-off-by: Damien Jeandemange <damien.jeandemange@artelys.com>
Signed-off-by: Damien Jeandemange <damien.jeandemange@artelys.com>
@jeandemanged jeandemanged changed the title [WIP] Fix proportional scalable infinite loop Fix proportional scalable infinite loop Oct 23, 2024
…es (even after the fix)

Signed-off-by: Philippe Edwards <philippe.edwards@rte-france.com>
@phiedw
Copy link
Contributor

phiedw commented Oct 23, 2024

Well spotted for the issue!
However I don't think the fix is the correct one.
As you can see with the example I added, there can be other similar cases which cause infinite looping (which are not fixed by this pull request)

phiedw and others added 3 commits October 23, 2024 14:28
Signed-off-by: Philippe Edwards <philippe.edwards@rte-france.com>
Signed-off-by: Damien Jeandemange <damien.jeandemange@artelys.com>
Signed-off-by: Damien Jeandemange <damien.jeandemange@artelys.com>
@phiedw
Copy link
Contributor

phiedw commented Oct 23, 2024

What should the behaviour be in the following case? (maybe too much of a marginal case for us to worry about)

Initially load1 is at 0MW, load2 and load3 are at 100MW, and the coefficients on the different loads are ~100, 1e-5 and 1e-5.

If we ask for a 100MW reduction, with the new code, we will scale by 2e-3MW at the first iteration and will exit the loop.
Before, we would have scaled by 2e-3MW at the first iteration, renormalized the coefficients (since load1 is saturated), and then at the second iteration, scaled by 50MW on both loads 2 and 3.

Signed-off-by: Damien Jeandemange <damien.jeandemange@artelys.com>
Copy link

Copy link
Contributor

@phiedw phiedw left a comment

Choose a reason for hiding this comment

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

Thank you very much for this pull request

@jeandemanged
Copy link
Member Author

What should the behaviour be in the following case? (maybe too much of a marginal case for us to worry about)

Initially load1 is at 0MW, load2 and load3 are at 100MW, and the coefficients on the different loads are ~100, 1e-5 and 1e-5.

If we ask for a 100MW reduction, with the new code, we will scale by 2e-3MW at the first iteration and will exit the loop. Before, we would have scaled by 2e-3MW at the first iteration, renormalized the coefficients (since load1 is saturated), and then at the second iteration, scaled by 50MW on both loads 2 and 3.

indeed reverted the change causing this, was a bad idea, but maybe could be made different, e.g. if difference asked-done doesn't 'move' anymore by more than EPSILON between two iterations, then break the loop.

I am a bit worried of remaining very small values summed, summing many small floats can be surprising sometimes.

You opinion @phiedw ?

@jeandemanged jeandemanged requested a review from phiedw October 23, 2024 14:36
@phiedw
Copy link
Contributor

phiedw commented Oct 23, 2024

I think this fix seems to be a decent way to fix the issue. I can't think of any cases where the behaviour would not be the expected one.
I was wondering if it could be possible to add to the scalable interface a method that checks some conditions to know if the scalable is saturated/disabled/disconnected etc to know if we should set its percentage to 0, but I'm not sure it would be cleaner.

@jeandemanged
Copy link
Member Author

I think this fix seems to be a decent way to fix the issue. I can't think of any cases where the behaviour would not be the expected one. I was wondering if it could be possible to add to the scalable interface a method that checks some conditions to know if the scalable is saturated/disabled/disconnected etc to know if we should set its percentage to 0, but I'm not sure it would be cleaner.

yes I am not sure as well refactoring would make things easier

I was also wondering if to be on the safe side we should do as below, but cannot build a unit test for that.

saving it here so it doesn't get lost:

    private double iterativeScale(Network n, double asked, ScalingParameters parameters) {
        double done = 0;
        boolean first = false;
        while (Math.abs(asked - done) > EPSILON && notSaturated()) {
            checkIterationPercentages();
            double previousAskedMinusDone = asked - done;
            done += scaleIteration(n, asked - done, parameters);
            double newAskedMinusDone = asked - done;
            if (Math.abs(previousAskedMinusDone - newAskedMinusDone) < EPSILON) {
                if (!first) {
                    first = true;
                } else {
                    LOGGER.warn("Proportional iterative scale did not distribute more than {} MW between 2 consecutive iterations, " +
                            "stopping iterative scale. asked={} MW, done={} MW", EPSILON, asked, done);
                    break;
                }
            } else {
                first = false;
            }
            updateIterationPercentages();
        }
        return done;
    }

@olperr1 olperr1 merged commit 2b9eadc into main Oct 24, 2024
7 checks passed
@olperr1 olperr1 deleted the fix-prop-scalable-infinite-loop branch October 24, 2024 05:43
olperr1 pushed a commit that referenced this pull request Oct 24, 2024
* Fix proportional scalable infinite loop

Signed-off-by: Damien Jeandemange <damien.jeandemange@artelys.com>
(cherry picked from commit 2b9eadc)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants