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

Cgmes active reactive regulating control #2995

Merged
merged 23 commits into from
Jul 25, 2024

Conversation

nemanja-st
Copy link
Contributor

@nemanja-st nemanja-st commented Apr 30, 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?
Fixes #2920 '

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

  • Yes
  • No

Other information:
ACTIVE_POWER and CURRENT_LIMITER are already implemented for PSTs.

@nemanja-st nemanja-st changed the title Cgmes active reactive regulating control WIP Cgmes active reactive regulating control Apr 30, 2024
@nemanja-st nemanja-st force-pushed the cgmes_active_reactive_regulating_control branch from 70799b8 to 7912758 Compare May 9, 2024 14:33
@nemanja-st nemanja-st changed the title WIP Cgmes active reactive regulating control Cgmes active reactive regulating control May 10, 2024
@nemanja-st
Copy link
Contributor Author

nemanja-st commented May 10, 2024

Issues observed for this PR:

  1. StaticVarCompensator:
    • When StaticVarCompensatorRegulationMode is OFF and regulatingTerminal is remote, RegulatingControl is always exported with enabled set to false.
    • When StaticVarCompensatorRegulationMode is OFF and regulatingTerminal is local, RegulatingControl is never exported.
  2. ShuntCompensator:
    • When voltageRegulatorOn is false and regulatingTerminal is remote, RegulatingControl is always exported with enabled set to false.
    • When voltageRegulatorOn is false and regulatingTerminal is local, RegulatingControl is never exported.
  3. Implementation in commit d75dacb will need to be propagated to TC export in SV, if user exports only SV cimxml file.

@nemanja-st nemanja-st force-pushed the cgmes_active_reactive_regulating_control branch 2 times, most recently from 9ec5142 to 611d144 Compare May 10, 2024 09:31
Copy link

sonarcloud bot commented May 10, 2024

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
Copy link
Member

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);
Copy link
Contributor

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()))) {

Copy link
Contributor Author

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.

Copy link
Contributor

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);
Copy link
Contributor

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()))) {

Copy link
Contributor Author

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).

Copy link
Contributor

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.

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 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) {
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor

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 {
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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);
Copy link
Contributor

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()) {
Copy link
Contributor

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.

Copy link
Contributor Author

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();
}

Copy link
Contributor

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;
}

Copy link
Contributor

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);
}

Copy link
Contributor

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();
Copy link
Contributor

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,
Copy link
Contributor

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

@nemanja-st nemanja-st force-pushed the cgmes_active_reactive_regulating_control branch from bc1218f to 3b825b0 Compare June 10, 2024 14:08
@nemanja-st
Copy link
Contributor Author

nemanja-st commented Jun 10, 2024

Hello @marqueslanauja @annetill
I implemented the suggestions, refactored the code and fixed some tests 1035fca and 3b825b0.

The behavior on control export currently:

  • Generator:
    • Imported control is always exported.
    • No control when no reactive capability (Qmin=Qmax)
    • Reactive control when reactive is enabled and voltage disabled
    • Voltage in all other cases
  • Shunt:
    • No control when control is not remote and no voltage setpoint
    • Voltage exported in all other cases
  • SVC:
    • No control when control is local, OFF and there are no valid Q or V targets
    • Reactive control when control is REACTIVE or control is OFF and reactive power target is valid and voltage target is invalid
    • Voltage control in all other cases
  • RTC:
    • Control is not exported when it's not defined (RatioRegulationMode not defined), regardless if it has remote terminal or not.
    • Otherwise, control exported based on RatioRegulationMode

Copy link

sonarcloud bot commented Jun 10, 2024

@annetill
Copy link
Member

Hi @nemanja-st, documentation is missing

stojkovicn added 4 commits July 23, 2024 18:40
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>
stojkovicn added 14 commits July 23, 2024 18:40
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>
@nemanja-st nemanja-st force-pushed the cgmes_active_reactive_regulating_control branch from 3b825b0 to 553d59f Compare July 23, 2024 16:42
nemanja-st and others added 3 commits July 24, 2024 17:07
Signed-off-by: Anne Tilloy <anne.tilloy@rte-france.com>
Signed-off-by: Anne Tilloy <anne.tilloy@rte-france.com>
zamarrenolm and others added 2 commits July 25, 2024 11:26
Signed-off-by: Luma <zamarrenolm@aia.es>
Signed-off-by: Anne Tilloy <anne.tilloy@rte-france.com>
Copy link

sonarcloud bot commented Jul 25, 2024

@annetill annetill merged commit a240c8f into main Jul 25, 2024
7 checks passed
@annetill annetill deleted the cgmes_active_reactive_regulating_control branch July 25, 2024 10:12
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.

CGMES export regulating controls for active and reactive power
4 participants