-
Notifications
You must be signed in to change notification settings - Fork 43
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
Cgmes active reactive regulating control #2995
Conversation
70799b8
to
7912758
Compare
Issues observed for this PR:
|
9ec5142
to
611d144
Compare
Quality Gate passedIssues Measures |
private static String getSvcMode(StaticVarCompensator svc) { | ||
String mode = RegulatingControlEq.REGULATING_CONTROL_VOLTAGE; | ||
StaticVarCompensator.RegulationMode regulationMode = svc.getRegulationMode(); | ||
// FIXME: remove RegulationMode.OFF when #2790 is done |
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.
#2790 will not be available soon because it leads to an increase of iidm version. Maybe in June, but no sure at all. Do you have a unit test with a OFF mode but valid values for both voltage and reactive power control values? What is exported then?
@@ -523,7 +523,7 @@ private void addIidmMappingsShuntCompensators(Network network) { | |||
continue; | |||
} | |||
String regulatingControlId = shuntCompensator.getProperty(Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + REGULATING_CONTROL); | |||
if (regulatingControlId == null && (shuntCompensator.isVoltageRegulatorOn() || !Objects.equals(shuntCompensator, shuntCompensator.getRegulatingTerminal().getConnectable()))) { | |||
if (regulatingControlId == null && SteadyStateHypothesisExport.isValidVoltageSetpoint(shuntCompensator.getTargetV())) { | |||
regulatingControlId = namingStrategy.getCgmesId(ref(shuntCompensator), Part.REGULATING_CONTROL); |
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 create also the control when the regulating control is remote. If cgmes EQ
file is imported (no SSH
file), then only the regulating terminal is defined, given that the setpoint is in the SSH
file. Better do not lose the regulating control in this case if the iidm model is exported. In iidm regulating terminal null is the same as local control, then only if the regulating control is remote we have to export it.
if (regulatingControlId == null
&& (SteadyStateHypothesisExport.isValidVoltageSetpoint(shuntCompensator.getTargetV())
|| !Objects.equals(shuntCompensator, shuntCompensator.getRegulatingTerminal().getConnectable()))) {
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 RC creation from scratch (regulatingControlId == null
) so it comes down to deciding if Shunt has voltage regulating capability from IIDM.
If targetV is not set, in case of full CGMES export from IIDM, SSH will have incorrect values for the control.
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.
If the targetV
is not set, the validation level is EQUIPMENT and does not make sense to export the SSH file.
I prefer to export properly the EQ file, including the control, in concordance with the validation level.
if (regulatingControlId == null && ( | ||
svc.getRegulationMode() == StaticVarCompensator.RegulationMode.VOLTAGE || | ||
svc.getRegulationMode() == StaticVarCompensator.RegulationMode.REACTIVE_POWER || | ||
validVoltageSetpoint && !validReactiveSetpoint || !validVoltageSetpoint && validReactiveSetpoint)) { | ||
regulatingControlId = namingStrategy.getCgmesId(ref(svc), Part.REGULATING_CONTROL); |
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.
In concordance with the previous comment, we can export it if:
if (regulatingControlId == null && (validVoltageSetpoint
|| validReactiveSetpoint
|| !Objects.equals(svc, svc.getRegulatingTerminal().getConnectable()))) {
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.
Again, this is related to RC creation from scratch (no CGMES import).
In CGMES, SVC must have a RC in order to function (SVC parameters regarding control should be ignored). This is valid for local and remote controls.
In this implementation, we avoid exporting RC only when regulationMode is not set and we have both voltage and reactive targets (it's not clear which to use).
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 am in favor of exporting the maximum information if the information is valid. In this case, I prefer to export the voltage control as disabled than do not export anything, but of course both options are valid.
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 have a use case where we export only an EQ file, without SSH file.
if (rrpc != null) { | ||
regulatingTerminal = rrpc.getRegulatingTerminal(); | ||
mode = RegulatingControlEq.REGULATING_CONTROL_REACTIVE_POWER; | ||
} | ||
switch (cgmesOriginalClass) { |
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.
My proposal:
RemoteReactivePowerControl rrpc = generator.getExtension(RemoteReactivePowerControl.class);
String mode = getGeneratorRegulatingControlMode(generator, rrpc);
Terminal regulatingTerminal = mode.equals(RegulatingControlEq.REGULATING_CONTROL_VOLTAGE) ? generator.getRegulatingTerminal() : rrpc.getRegulatingTerminal();
private static String getGeneratorRegulatingControlMode(Generator generator, RemoteReactivePowerControl rrpc) {
if (rrpc == null) {
return RegulatingControlEq.REGULATING_CONTROL_VOLTAGE;
}
boolean enabledVoltageControl = generator.isVoltageRegulatorOn();
boolean enabledReactivePowerControl = rrpc.isEnabled();
if (enabledVoltageControl) {
return RegulatingControlEq.REGULATING_CONTROL_VOLTAGE;
} else if (enabledReactivePowerControl) {
return RegulatingControlEq.REGULATING_CONTROL_REACTIVE_POWER;
} else {
boolean validVoltageSetpoint = SteadyStateHypothesisExport.isValidVoltageSetpoint(generator.getTargetV());
if (validVoltageSetpoint) {
return RegulatingControlEq.REGULATING_CONTROL_VOLTAGE;
} else {
return RegulatingControlEq.REGULATING_CONTROL_REACTIVE_POWER;
}
}
}
We can define the getGeneratorRegulatingControlMode
method in the CgmesExportUtil
class and use it during the SSH
export to be coherent with the EQ
export.
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 difficulty here is in priorities: Is the RRPC extension priority or voltage control?
Example: rrpc exists, voltage control is enabled -> We export voltage control, regardless of rrpc status.
Since rrpc has to be created explicitly as an extension, assumption is that it has the priority.
Therefore, if rrpc is there, we ignore voltage control completely and only use rrpc parameters.
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.
If the reactive power control extension is present and enabled, it does not override the voltage control if enabled. Maybe it is a mistake but it is what is developed inside open loadflow.
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 prefer to select the control priority using the electrical information rather than the software information. The final user, in most of the cases, will not know how the model is internally implemented. Then, if both controls have the same valid attributes I prefer to export the voltage control. But as before, both options are valid.
} | ||
return mode; | ||
} | ||
|
||
private static void writeLines(Network network, Map<Terminal, String> mapTerminal2Id, String cimNamespace, String euNamespace, String valueAttributeName, String limitTypeAttributeName, String limitKindClassName, boolean writeInfiniteDuration, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { |
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.
My proposal:
private static String getSvcMode(StaticVarCompensator svc) {
if (svc.getRegulationMode().equals(StaticVarCompensator.RegulationMode.VOLTAGE)) {
return RegulatingControlEq.REGULATING_CONTROL_VOLTAGE;
} else if (svc.getRegulationMode().equals(StaticVarCompensator.RegulationMode.REACTIVE_POWER)) {
return RegulatingControlEq.REGULATING_CONTROL_REACTIVE_POWER;
} else {
if (SteadyStateHypothesisExport.isValidReactivePowerSetpoint(svc.getReactivePowerSetpoint())) {
return RegulatingControlEq.REGULATING_CONTROL_VOLTAGE;
} else {
return RegulatingControlEq.REGULATING_CONTROL_REACTIVE_POWER
}
}
}
We can also define the getSvcMode method in the CgmesExportUtil class and use it during the SSH export to be coherent with the EQ export.
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.
Same comment as above, when SVC control mode is not defined, and we have valid voltage and reactive targets, the control shouldn't be exported.
But I agree it should be a common method in CgmesExportUtil
.
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 am in favor of exporting the maximum information and in this case I prefer to export the voltage control as disabled but both options are valid.
// Regulating control mode is always "voltage" | ||
TapChangerEq.writeControl(cgmesRegulatingControlId, controlName, RATIO_TAP_CHANGER_REGULATION_MODE_VOLTAGE, terminalId, cimNamespace, writer, context); | ||
String tccMode = (rtc.getRegulationMode() == RatioTapChanger.RegulationMode.REACTIVE_POWER) ? RATIO_TAP_CHANGER_REGULATION_MODE_REACTIVE_POWER : RATIO_TAP_CHANGER_REGULATION_MODE_VOLTAGE; | ||
TapChangerEq.writeControl(cgmesRegulatingControlId, controlName, tccMode, terminalId, cimNamespace, writer, context); | ||
regulatingControlsWritten.add(cgmesRegulatingControlId); |
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 use a method to obtain the tccMode and define it in the CgmesExportUtil class and use it during the SSH export to be always coherent with the EQ export.
@@ -184,6 +185,7 @@ private static String cgmesTapChangerId(TwoWindingsTransformer twt, String tapCh | |||
|
|||
private static void writeTapChangers(Network network, String cimNamespace, Map<String, List<RegulatingControlView>> regulatingControlViews, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { | |||
for (TwoWindingsTransformer twt : network.getTwoWindingsTransformers()) { | |||
CgmesExportUtil.addUpdateCgmesTapChangerExtension(twt, context); | |||
if (twt.hasPhaseTapChanger()) { |
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 suppose that you added to be able to export the SSH file without exporting the EQ file.
You also have to add this method some lines below for the threeWindingsTransformers.
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, I'll update that!
targetValueUnitMultiplier = "k"; | ||
enabled = g.isVoltageRegulatorOn(); | ||
} | ||
|
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.
Use the getGeneratorRegulatingControlMode
method to obtain the mode, then depending on the mode set the attributes
regulatingControlViews.computeIfAbsent(rcid, k -> new ArrayList<>()).add(rcv); | ||
} | ||
} | ||
|
||
private static boolean isValidSvcVolatgeSetpoint(double v) { | ||
public static boolean isValidVoltageSetpoint(double v) { | ||
return Double.isFinite(v) && v > 0; | ||
} | ||
|
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 move this method to the CgmesExportUtil class given that is used in several classes
return Double.isFinite(v) && v > 0; | ||
} | ||
|
||
private static boolean isValidSvcReactivePowerSetpoint(double q) { | ||
public static boolean isValidReactivePowerSetpoint(double q) { | ||
return Double.isFinite(q); | ||
} | ||
|
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 move also to the CgmesExportUtil class
targetValue = svc.getVoltageSetpoint(); | ||
multiplier = "k"; | ||
} else if (regulationMode == StaticVarCompensator.RegulationMode.REACTIVE_POWER | ||
|| regulationMode == StaticVarCompensator.RegulationMode.OFF && isValidSvcReactivePowerSetpoint(svc.getReactivePowerSetpoint())) { | ||
|| regulationMode == StaticVarCompensator.RegulationMode.OFF && isValidReactivePowerSetpoint(svc.getReactivePowerSetpoint()) && !isValidVoltageSetpoint(svc.getVoltageSetpoint())) { | ||
targetValue = svc.getReactivePowerSetpoint(); |
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 use the getSvcMode to obtain the mode, then depending on the mode set the attributes
String unitMultiplier = switch (ratioTapChanger.getRegulationMode()) { | ||
case VOLTAGE -> "k"; | ||
case REACTIVE_POWER -> "M"; | ||
}; | ||
rcv = new RegulatingControlView(controlId, |
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 use the method used in the EQ export to obtain the mode and then depending on the mode set the unitMultiplier
bc1218f
to
3b825b0
Compare
Hello @marqueslanauja @annetill The behavior on control export currently:
|
Quality Gate passedIssues Measures |
Hi @nemanja-st, documentation is missing |
Signed-off-by: stojkovicn <nemanja.stojkovic@rte-france.com> Signed-off-by: nemanja-st <nemanja.stojkovic@redstork-solutions.com>
Signed-off-by: stojkovicn <nemanja.stojkovic@rte-france.com> Signed-off-by: nemanja-st <nemanja.stojkovic@redstork-solutions.com>
Signed-off-by: stojkovicn <nemanja.stojkovic@rte-france.com> Signed-off-by: nemanja-st <nemanja.stojkovic@redstork-solutions.com>
Signed-off-by: stojkovicn <nemanja.stojkovic@rte-france.com> Signed-off-by: nemanja-st <nemanja.stojkovic@redstork-solutions.com>
Signed-off-by: stojkovicn <nemanja.stojkovic@rte-france.com> Signed-off-by: nemanja-st <nemanja.stojkovic@redstork-solutions.com>
Signed-off-by: stojkovicn <nemanja.stojkovic@rte-france.com> Signed-off-by: nemanja-st <nemanja.stojkovic@redstork-solutions.com>
Signed-off-by: stojkovicn <nemanja.stojkovic@rte-france.com> Signed-off-by: nemanja-st <nemanja.stojkovic@redstork-solutions.com>
Signed-off-by: stojkovicn <nemanja.stojkovic@rte-france.com> Signed-off-by: nemanja-st <nemanja.stojkovic@redstork-solutions.com>
Signed-off-by: stojkovicn <nemanja.stojkovic@rte-france.com> Signed-off-by: nemanja-st <nemanja.stojkovic@redstork-solutions.com>
Signed-off-by: stojkovicn <nemanja.stojkovic@rte-france.com> Signed-off-by: nemanja-st <nemanja.stojkovic@redstork-solutions.com>
Signed-off-by: stojkovicn <nemanja.stojkovic@rte-france.com> Signed-off-by: nemanja-st <nemanja.stojkovic@redstork-solutions.com>
Signed-off-by: stojkovicn <nemanja.stojkovic@rte-france.com> Signed-off-by: nemanja-st <nemanja.stojkovic@redstork-solutions.com>
Signed-off-by: stojkovicn <nemanja.stojkovic@rte-france.com> Signed-off-by: nemanja-st <nemanja.stojkovic@redstork-solutions.com>
Signed-off-by: stojkovicn <nemanja.stojkovic@rte-france.com> Signed-off-by: nemanja-st <nemanja.stojkovic@redstork-solutions.com>
Signed-off-by: stojkovicn <nemanja.stojkovic@rte-france.com> Signed-off-by: nemanja-st <nemanja.stojkovic@redstork-solutions.com>
Signed-off-by: stojkovicn <nemanja.stojkovic@rte-france.com> Signed-off-by: nemanja-st <nemanja.stojkovic@redstork-solutions.com>
Signed-off-by: nemanja-st <nemanja.stojkovic@redstork-solutions.com>
Signed-off-by: nemanja-st <nemanja.stojkovic@redstork-solutions.com>
3b825b0
to
553d59f
Compare
Signed-off-by: Anne Tilloy <anne.tilloy@rte-france.com>
Signed-off-by: Luma <zamarrenolm@aia.es>
Quality Gate passedIssues Measures |
Signed-off-by: stojkovicn <nemanja.stojkovic@rte-france.com> Co-authored-by: Anne Tilloy <anne.tilloy@rte-france.com> Co-authored-by: Luma <zamarrenolm@aia.es>
Please check if the PR fulfills these requirements
Does this PR already have an issue describing the problem?
Fixes #2920 '
Does this PR introduce a breaking change or deprecate an API?
Other information:
ACTIVE_POWER
andCURRENT_LIMITER
are already implemented for PSTs.