-
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
Introduce voltage sensitivity #253
Conversation
Signed-off-by: Gael Macherel <[email protected]>
We will need to update the core version once the sensitivity is released on core's side |
@@ -55,6 +54,27 @@ protected AbstractSensitivityAnalysis(MatrixFactory matrixFactory) { | |||
this.matrixFactory = Objects.requireNonNull(matrixFactory); | |||
} | |||
|
|||
protected static Terminal getEquipmentRegulatingTerminal(Network network, String equipmentId) { |
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 Here I am trying to get the terminal that corresponds to the equipmentId, but I am not sure of the way to do it
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 have pushed a commit to help you (but the code could be improved if you want). Indeed it was what I have tried to avoid with another design of the factor, without any success from my colleagues :-)
functionLfBranch = null; | ||
Bus bus = ((BusVoltagePerTargetV) factor).getFunction().getBusRef().resolve(network).orElseThrow(); | ||
functionLfBus = lfNetwork.getBusById(bus.getId()); | ||
equationTerm = equationSystem.getEquationTerm(ElementType.BUS, functionLfBus.getNum(), EquationTerm.VariableEquationTerm.class); |
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.
@geofjamg @annetill I would like to do the same thing as the branches (like using functionLfBus.getV() to get an Evaluable), but I am not sure if the Evaluable should be the bus_V equation, or the bus_V equation term ? Moreover, currently, getV() returns v / nominalV, so I am not sure whether the nominal V should be included in the Evaluable 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.
You can use the BUS_V equation term.
No the / nominalV should not be included and just be careful to add it when updating the IIDM network (LfBusImpl.updateState method)
functionLfBranch = null; | ||
Bus bus = ((BusVoltagePerTargetV) factor).getFunction().getBusRef().resolve(network).orElseThrow(); | ||
functionLfBus = lfNetwork.getBusById(bus.getId()); | ||
equationTerm = equationSystem.getEquationTerm(ElementType.BUS, functionLfBus.getNum(), EquationTerm.VariableEquationTerm.class); |
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.
You can use the BUS_V equation term.
No the / nominalV should not be included and just be careful to add it when updating the IIDM network (LfBusImpl.updateState method)
@@ -111,7 +146,9 @@ protected JacobianMatrix createJacobianMatrix(EquationSystem equationSystem, Vol | |||
// Wrap factors in specific class to have instant access to their branch, and their equation term | |||
private final SensitivityFactor factor; | |||
|
|||
private final LfBranch functionLfBranch; | |||
private final LfBranch functionLfBranch; // todo: create two classes: branch function and bus function ? |
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.
Ideally yes, if possible we should have another class with commons abstract for branch or bus monitored factor.
|
||
LfBusVoltagePerTargetV(SensitivityFactor factor, Network network, LfNetwork lfNetwork, EquationSystem equationSystem) { | ||
super(factor, network, lfNetwork, equationSystem); | ||
String targetVTerminalId = ((TargetV) factor.getVariable()).getEquipmentId(); |
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.
This is not a terminal id, but an element id
LfBusVoltagePerTargetV(SensitivityFactor factor, Network network, LfNetwork lfNetwork, EquationSystem equationSystem) { | ||
super(factor, network, lfNetwork, equationSystem); | ||
String targetVTerminalId = ((TargetV) factor.getVariable()).getEquipmentId(); | ||
Terminal regulatingTerminal = getEquipmentRegulatingTerminal(network, targetVTerminalId); |
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.
The factor/bus ref is crappy, this why you are doing all this ugly code. Here factor should provide you a TerminaRef directly.
Signed-off-by: Gael Macherel <[email protected]>
Signed-off-by: Gael Macherel <[email protected]>
Signed-off-by: Gael Macherel <[email protected]>
Signed-off-by: Gael Macherel <[email protected]>
Signed-off-by: Gael Macherel <[email protected]>
@Djazouli Now that we have a sensi internal API, I propose that for this PR, you don't care about powsybl sensi API and just make voltage sensi available from internal API. In Gridpy I made an evolution to directly connect to sensi internal API, so even without new powsybl API addition I will be able to use it. |
The idea would be to merge this, before switching to next powsybl release. Adaptation to new factor from powsybl api would be done in another PR. |
Sweet idea, I'll do it |
Signed-off-by: Gael Macherel <[email protected]>
Signed-off-by: Gael Macherel <[email protected]>
Signed-off-by: Gael Macherel <[email protected]>
Signed-off-by: Gael Macherel <[email protected]>
Signed-off-by: Gael Macherel <[email protected]>
Signed-off-by: Gael Macherel <[email protected]>
Signed-off-by: Gael Macherel <[email protected]>
Signed-off-by: Gael Macherel <[email protected]>
Signed-off-by: Gael Macherel <[email protected]>
private final String variableId; | ||
|
||
protected final LfBranch functionLfBranch; | ||
ILfSensitivityFunction function; |
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.
LfBranch and LfBus has a common base class LfElement. Would it be possible to use it here in order to avoid adding ILfSensitivityFunction?
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 we could try in this PR to adapt LfFactor to internal API. To avoid LfFactor subclassing hell (with all function/variable combinations), we could try to only have one LfFactor class and one LfFactorGroup. So having LfElement type for variable and function.
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.
So, we would to store a LfElement + a SensitivityFunctionType instead of having a class wrapping the element for each Function type ? And then, to get the equation term from that, we write a big switch statement, instead of overriding methods ? (and do the same thing for the variables)
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 can try to see what it would look like.
Signed-off-by: Gael Macherel <[email protected]>
Signed-off-by: Gael Macherel <[email protected]>
Signed-off-by: Gael Macherel <[email protected]>
protected JacobianMatrix createJacobianMatrix(EquationSystem equationSystem, VoltageInitializer voltageInitializer) { | ||
double[] x = equationSystem.createStateVector(voltageInitializer); | ||
equationSystem.updateEquations(x); | ||
return new JacobianMatrix(equationSystem, matrixFactory); | ||
} | ||
|
||
static class LfSensitivityFactor { | ||
abstract static class AbstractLfSensitivityFactor { |
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.
Thanks, for this great refactoring! Maybe we can keep a LfSensitivityFactor interface in addition to the AbstractLfSensitivityFactor to avoid using AbstractLfSensitivityFactor everywhere in the code (Abstract class are not supposed to be used as an API)?
Signed-off-by: Gael Macherel <[email protected]>
public EquationTerm getEquationTerm() { | ||
throw new NotImplementedException("getEquationTerm should have an override"); | ||
switch (functionType) { | ||
case BRANCH_ACTIVE_POWER: |
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.
Just a small remark here: maybe it could be better to use the terminology we already introduced: BRANCH_P
, BRANCH_I
(I have it on a working branch for transformer in current limiter mode) and BUS_V
?
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 would keep it like this as it is supposed one day to move to core as API V2 and as an official API is it more meaningful to keep BRANCH_ACTIVE_POWER
if (staticVarCompensator != null) { | ||
return staticVarCompensator.getRegulatingTerminal(); | ||
} | ||
TwoWindingsTransformer t2wt = network.getTwoWindingsTransformer(equipmentId); |
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.
This PR is indeed not working with transformers as we don't have any PV bus linked to the transformer regulation. In your test, the PV bus is linked to the generator. For phase tap changers, we have activated the phase variable. Here, we have to active the rho variable and the linked bus_v equation I think.
Signed-off-by: Gael Macherel <[email protected]>
Signed-off-by: Gael Macherel <[email protected]>
@@ -263,7 +263,7 @@ private static void createBranchActivePowerTargetEquation(LfBranch branch, Discr | |||
|
|||
private static void createDiscreteVoltageControlEquation(LfBus bus, VariableSet variableSet, EquationSystem equationSystem) { | |||
if (bus.isDiscreteVoltageControlled()) { | |||
EquationTerm vTerm = EquationTerm.createVariableTerm(bus, VariableType.BUS_V, variableSet, bus.getV().eval()); | |||
EquationTerm vTerm = EquationTerm.createVariableTerm(bus, VariableType.BUS_V, variableSet, bus.getDiscreteVoltageControl().getTargetValue()); |
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.
@geofjamg I think it is bus.getV().eval()
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.
Using a numeric value of a state variable in the equation system is not correct.
bus.getDiscreteVoltageControl().getTargetValue() is better, but not correct too. It should be redesign to move it in the RHS.
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.
After thinking again, I am not sure to understand why do we need to set an initial value for equation term at this place. Normally equation initial value should be computed from initial state vector. To investigate before merging this PR.
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.
Yes indeed I understand now the purpose of this new term and we have to investigate why we need it now.
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.
The initial value is only used if the voltage initializer type is set to PREVIOUS_VALUES
. (because it causes a call to lfBus.getV().eval() ). Otherwise it is indeed replaced immediately by the value from the state vector.
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.
But with PREVIOUS_VALUES the bus voltage is initialized from IIDM values (if defined). Why do you need to override this value?
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.
The PREVIOUS_VALUES was initialized with LfBus.getV() (now lfBus.getV().eval()). The issue is that after the creation of the system, lfBus.getV() returns the EquationTerm representing V in the system, and not the value found in the IIDM, so we need to pass the value from the IIDM to the EquationTerm so it does not get lost. (or we could also try to call the voltage initialization before the creation of the equation system)
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.
Ok I understand, so @annetill is right in her comment, it should be bus.getV().eval() in that case to really init from IIDM network state as it was before.
Signed-off-by: Gael Macherel <[email protected]>
@Override | ||
public void write(Writer writer) throws IOException { | ||
variables.get(0).write(writer); | ||
} | ||
} | ||
|
||
static VariableEquationTerm createVariableTerm(LfElement element, VariableType variableType, VariableSet variableSet) { | ||
return createVariableTerm(element, variableType, variableSet, 0d); |
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 it will be better to put Double.NaN
here.
Signed-off-by: Gael Macherel <[email protected]>
…ite the equation term Signed-off-by: Gael Macherel <[email protected]>
Signed-off-by: Gael Macherel <[email protected]>
Kudos, SonarCloud Quality Gate passed! |
Signed-off-by: Gael Macherel [email protected]
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 restWhat kind of change does this PR introduce? (Bug fix, feature, docs update, ...)
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)?
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)