Skip to content

Conversation

@snoopfab
Copy link
Contributor

@snoopfab snoopfab commented Oct 16, 2025

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)
  • A PR or issue has been opened in all impacted repositories (if any)

Does this PR already have an issue describing the problem?

Implement #3511

What kind of change does this PR introduce?

feature : Implement Model a PQU diagram for reactive limits

What is the current behavior?

#3511

What is the new behavior (if this is a feature change)?

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

  • Yes
  • No

If yes, please check if the following requirements are fulfilled

  • The Breaking Change or Deprecated label has been added
  • The migration steps are described in the following section

What changes might users need to make in their application due to this PR? (migration steps)

Other information:

Fabrice Buscaylet and others added 7 commits October 9, 2025 09:49
Signed-off-by: Fabrice Buscaylet <[email protected]>
added unit tests

Signed-off-by: Fabrice Buscaylet <[email protected]>
Signed-off-by: Matthieu SAUR <[email protected]>
Added lower and upper bounds for ReactiveCapabilityShapePolyhedron
Added tests and fixed old ones
Added javadocs

Signed-off-by: Fabrice Buscaylet <[email protected]>
Added lower and upper bounds for ReactiveCapabilityShapePolyhedron
Added tests and fixed old ones
Added javadocs

Signed-off-by: Fabrice Buscaylet <[email protected]>
Signed-off-by: Fabrice Buscaylet <[email protected]>
@snoopfab snoopfab changed the title features/ReactiveCapabilityShape Implement Model a PQU diagram for reactive limits Oct 16, 2025
@snoopfab snoopfab self-assigned this Oct 16, 2025
@snoopfab snoopfab requested a review from jeandemanged October 16, 2025 15:04
Fabrice Buscaylet added 8 commits October 17, 2025 10:58
Signed-off-by: Fabrice Buscaylet <[email protected]>
added unit tests

Signed-off-by: Fabrice Buscaylet <[email protected]>
Added lower and upper bounds for ReactiveCapabilityShapePolyhedron
Added tests and fixed old ones
Added javadocs

Signed-off-by: Fabrice Buscaylet <[email protected]>
Added lower and upper bounds for ReactiveCapabilityShapePolyhedron
Added tests and fixed old ones
Added javadocs

Signed-off-by: Fabrice Buscaylet <[email protected]>
Signed-off-by: Fabrice Buscaylet <[email protected]>
Signed-off-by: Fabrice Buscaylet <[email protected]>
…' into features/ReactiveCapabilityShape

# Conflicts:
#	iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ReactiveCapabilityShapePlane.java
Signed-off-by: Fabrice Buscaylet <[email protected]>
@snoopfab snoopfab linked an issue Oct 20, 2025 that may be closed by this pull request
@snoopfab snoopfab moved this from TODO to Waiting for review in Release 12/2025 Oct 20, 2025
@snoopfab snoopfab moved this from Waiting for review to TODO in Release 12/2025 Oct 20, 2025
@snoopfab snoopfab moved this from TODO to In Progress in Release 12/2025 Oct 20, 2025
@snoopfab snoopfab moved this from In Progress to Waiting for review in Release 12/2025 Oct 23, 2025
# Conflicts:
#	iidm/iidm-serde/src/main/resources/xsd/iidm_V1_15.xsd
#	iidm/iidm-serde/src/main/resources/xsd/iidm_equipment_V1_15.xsd
#	iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/AbstractIidmSerDeTest.java
#	iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/StaticVarCompensatorXmlTest.java
@sonarqubecloud
Copy link

@colineplqt colineplqt self-requested a review November 17, 2025 15:17
@olperr1 olperr1 mentioned this pull request Nov 20, 2025
7 tasks
@olperr1
Copy link
Member

olperr1 commented Nov 20, 2025

#3614 adds the (de)serialization of reactive limits for the detailed DC model. The last one of these 2 PRs (the current one and #3614) to be merged would have to be adapted to reflect the changes of the other.

Comment on lines +1 to +7
/**
* Copyright (c) 2016, All partners of the iTesla project (http://www.itesla-project.eu/consortium)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
Copy link
Member

Choose a reason for hiding this comment

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

The copyright is wrong:

Suggested change
/**
* Copyright (c) 2016, All partners of the iTesla project (http://www.itesla-project.eu/consortium)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
/**
* Copyright (c) 2025, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/

* *---*--+---------------* |
* | / | | | |
* |/ | . (P, Q, U) | |
* +---|--|---------------|--+
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand what these points represent

double getMinQ(double p, double v);

/**
* Get the reactive power maximum value at a given active power and voltage values.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* Get the reactive power maximum value at a given active power and voltage values.
* Get the reactive power maximum value at a given active power and voltage values.

Comment on lines +1 to +7
/**
* Copyright (c) 2016, All partners of the iTesla project (http://www.itesla-project.eu/consortium)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
Copy link
Member

Choose a reason for hiding this comment

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

The copyright is wrong:

Suggested change
/**
* Copyright (c) 2016, All partners of the iTesla project (http://www.itesla-project.eu/consortium)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
/*
* Copyright (c) 2025, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/

* Add a reactive capability shape plane to the reactive capability shape
* @param alpha the alpha coefficient
* @param beta the beta coefficient
* @param gamma the gamme right hand side
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* @param gamma the gamme right hand side
* @param gamma the gamma right hand side

Comment on lines +1 to +7
/**
* Copyright (c) 2016, All partners of the iTesla project (http://www.itesla-project.eu/consortium)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
Copy link
Member

Choose a reason for hiding this comment

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

The copyright is wrong:

Suggested change
/**
* Copyright (c) 2016, All partners of the iTesla project (http://www.itesla-project.eu/consortium)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
/*
* Copyright (c) 2025, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

class ReactiveCapabilityShapeLimitsTest {
Copy link
Member

Choose a reason for hiding this comment

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

author is missing

@@ -0,0 +1,88 @@
package com.powsybl.iidm.network.impl;
Copy link
Member

Choose a reason for hiding this comment

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

copyright is missing

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class ReactiveCapabilityShapePlaneTest {
Copy link
Member

Choose a reason for hiding this comment

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

author is missing

@@ -0,0 +1,121 @@
package com.powsybl.iidm.network.impl;
Copy link
Member

Choose a reason for hiding this comment

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

copyright is missing


import static org.junit.jupiter.api.Assertions.*;

class ReactiveCapabilityShapePolyhedronTest {
Copy link
Member

Choose a reason for hiding this comment

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

author is missing

* - U (kV): Voltage (Vertical Axis)
* </pre>
* The bounding box represents the operational limits—the single convex polyhedron defined by your constraints (the listOfPlanes).
* The point (P, Q, U) represents a specific operating point that the isInside function is checking.
Copy link
Member

Choose a reason for hiding this comment

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

The sentence about the (P, Q, U) point should be in the polyhedron javadoc as it is not directly in the ReactiveCapabilityShape object.

Copy link
Member

Choose a reason for hiding this comment

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

Or the isInside function could be added to this interface.

*
* - P (MW): Active Power (Horizontal Axis)
* - Q (MVaR): Reactive Power (Depth Axis)
* - U (kV): Voltage (Vertical Axis)
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 it is confusing to use U in the javadoc but V in the code. Should it not all be V?

ReactiveCapabilityShape add();

/**
* Add a reactive capability shape plane to the reactive capability shape
Copy link
Member

Choose a reason for hiding this comment

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

Maybe it would be good to reming the place equation here so that the alpha, beta and gamma coefficients are directly understood.

Copy link
Member

Choose a reason for hiding this comment

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

Or in the param you could add what the coefficient refers to.


/**
* Constructor
* @param polyhedron the reactive capacility shape polyhedron
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* @param polyhedron the reactive capacility shape polyhedron
* @param polyhedron the reactive capability shape polyhedron


/**
* Builder
* @param polyhedron the reactive capacility shape polyhedron
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* @param polyhedron the reactive capacility shape polyhedron
* @param polyhedron the reactive capability shape polyhedron

/**
* The inequaility types
*/
InequalityType inequalityType;
Copy link
Member

Choose a reason for hiding this comment

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

Could be private no?

sb.append("Q");

// Append U term (alpha * U)
if (Math.abs(alpha) > EPSILON) { // Check if alpha is non-zero
Copy link
Member

Choose a reason for hiding this comment

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

You could create a new method to extract the common logic

Copy link
Member

Choose a reason for hiding this comment

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

You should either use v or u for variables

* @return true if the point satisfies ALL plane constraints, false otherwise.
*/
public boolean isInside(final double p, final double q, final double u) {
boolean insideBounds = isInsideBounds(p, q, u);
Copy link
Member

Choose a reason for hiding this comment

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

if not insideBounds, return false at the beginning of the method for clarity

Comment on lines +236 to +256
private void addBoundsConstraints(final Collection<LinearConstraint> constraints) {
// Check the bounds activities before adding them to the linear program
if (!Double.isNaN(this.minQ)) {
constraints.add(new LinearConstraint(new double[]{1.0, 0.0, 0.0}, Relationship.GEQ, this.minQ));
}
if (!Double.isNaN(this.maxQ)) {
constraints.add(new LinearConstraint(new double[]{1.0, 0.0, 0.0}, Relationship.LEQ, this.maxQ));
}
if (!Double.isNaN(this.minP)) {
constraints.add(new LinearConstraint(new double[]{0.0, 0.0, 1.0}, Relationship.GEQ, this.minP));
}
if (!Double.isNaN(this.maxP)) {
constraints.add(new LinearConstraint(new double[]{0.0, 0.0, 1.0}, Relationship.LEQ, this.maxP));
}
if (!Double.isNaN(this.minV)) {
constraints.add(new LinearConstraint(new double[]{0.0, 1.0, 0.0}, Relationship.GEQ, this.minV));
}
if (!Double.isNaN(this.maxV)) {
constraints.add(new LinearConstraint(new double[]{0.0, 1.0, 0.0}, Relationship.LEQ, this.maxV));
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
private void addBoundsConstraints(final Collection<LinearConstraint> constraints) {
// Check the bounds activities before adding them to the linear program
if (!Double.isNaN(this.minQ)) {
constraints.add(new LinearConstraint(new double[]{1.0, 0.0, 0.0}, Relationship.GEQ, this.minQ));
}
if (!Double.isNaN(this.maxQ)) {
constraints.add(new LinearConstraint(new double[]{1.0, 0.0, 0.0}, Relationship.LEQ, this.maxQ));
}
if (!Double.isNaN(this.minP)) {
constraints.add(new LinearConstraint(new double[]{0.0, 0.0, 1.0}, Relationship.GEQ, this.minP));
}
if (!Double.isNaN(this.maxP)) {
constraints.add(new LinearConstraint(new double[]{0.0, 0.0, 1.0}, Relationship.LEQ, this.maxP));
}
if (!Double.isNaN(this.minV)) {
constraints.add(new LinearConstraint(new double[]{0.0, 1.0, 0.0}, Relationship.GEQ, this.minV));
}
if (!Double.isNaN(this.maxV)) {
constraints.add(new LinearConstraint(new double[]{0.0, 1.0, 0.0}, Relationship.LEQ, this.maxV));
}
}
private void addBoundsConstraints(final Collection<LinearConstraint> constraints) {
addBoundConstraint(constraints, IDX_Q, this.minQ, Relationship.GEQ);
addBoundConstraint(constraints, IDX_Q, this.maxQ, Relationship.LEQ);
addBoundConstraint(constraints, IDX_P, this.minP, Relationship.GEQ);
addBoundConstraint(constraints, IDX_P, this.maxP, Relationship.LEQ);
addBoundConstraint(constraints, IDX_U, this.minU, Relationship.GEQ);
addBoundConstraint(constraints, IDX_U, this.maxU, Relationship.LEQ);
}
private void addBoundConstraint(Collection<LinearConstraint> constraints, int variableIndex, double boundValue, Relationship relationship) {
if (!Double.isNaN(boundValue)) {
double[] coefficients = new double[3];
coefficients[variableIndex] = 1.0;
constraints.add(new LinearConstraint(coefficients, relationship, boundValue));
}
}

* This method permits to add active power bounds to the reactive limit implementation
* @param holder the reactive limit holder
*/
default void applyOwnerBounds(ReactiveLimitsHolder holder) {
Copy link
Member

Choose a reason for hiding this comment

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

This method should not be part of the API and moved to impl

@@ -0,0 +1,123 @@
/**
Copy link
Member

Choose a reason for hiding this comment

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

Maybe this one should be move to impl package, because I don't think it could be reused in the network store iidm impl.
It make sense to ReactiveCapabilityShapePolyhedron and ReactiveCapabilityShapePlane on API side as it is utility classes reusable in all IIDM implementations but I don't think it is the case for ReactiveCapabilityShapeImpl.


@Override
public void applyOwnerBounds(ReactiveLimitsHolder holder) {
polyhedron.withActivePowerBounds(holder.getMinP(), holder.getMaxP());
Copy link
Member

Choose a reason for hiding this comment

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

The problem with this approach is that if one change the minP and maxP of the generator for instance, the shape is not up-to date anymore. We probably need to store the holder ot an abstraction on it to always get the current value.

@github-project-automation github-project-automation bot moved this from TODO to Waiting for review in Release 03/2026 Nov 27, 2025
@alicecaron alicecaron moved this from Waiting for review to In Progress in Release 03/2026 Nov 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: In Progress
Status: Waiting for review

Development

Successfully merging this pull request may close these issues.

Model a PQU diagram for reactive limits

7 participants