Skip to content

Commit

Permalink
CGMES export of regulating controls (#2995)
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
3 people authored Jul 25, 2024
1 parent 49bcb76 commit a240c8f
Show file tree
Hide file tree
Showing 14 changed files with 1,477 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ private void addIidmMappingsGenerators(Network network) {
}

private static boolean hasVoltageControlCapability(Generator generator) {
if (Double.isNaN(generator.getTargetV()) || generator.getReactiveLimits() == null) {
if (generator.getReactiveLimits() == null) {
return false;
}

Expand Down Expand Up @@ -432,7 +432,8 @@ 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 && (CgmesExportUtil.isValidVoltageSetpoint(shuntCompensator.getTargetV())
|| !Objects.equals(shuntCompensator, shuntCompensator.getRegulatingTerminal().getConnectable()))) {
regulatingControlId = namingStrategy.getCgmesId(ref(shuntCompensator), Part.REGULATING_CONTROL);
shuntCompensator.setProperty(Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + REGULATING_CONTROL, regulatingControlId);
}
Expand All @@ -442,7 +443,11 @@ private void addIidmMappingsShuntCompensators(Network network) {
private void addIidmMappingsStaticVarCompensators(Network network) {
for (StaticVarCompensator svc : network.getStaticVarCompensators()) {
String regulatingControlId = svc.getProperty(Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + REGULATING_CONTROL);
if (regulatingControlId == null && (StaticVarCompensator.RegulationMode.VOLTAGE.equals(svc.getRegulationMode()) || !Objects.equals(svc, svc.getRegulatingTerminal().getConnectable()))) {
boolean validVoltageSetpoint = CgmesExportUtil.isValidVoltageSetpoint(svc.getVoltageSetpoint());
boolean validReactiveSetpoint = CgmesExportUtil.isValidReactivePowerSetpoint(svc.getReactivePowerSetpoint());
if (regulatingControlId == null && (validReactiveSetpoint
|| validVoltageSetpoint
|| !Objects.equals(svc, svc.getRegulatingTerminal().getConnectable()))) {
regulatingControlId = namingStrategy.getCgmesId(ref(svc), Part.REGULATING_CONTROL);
svc.setProperty(Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + REGULATING_CONTROL, regulatingControlId);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package com.powsybl.cgmes.conversion.export;

import com.powsybl.cgmes.conversion.Conversion;
import com.powsybl.cgmes.conversion.export.elements.RegulatingControlEq;
import com.powsybl.cgmes.conversion.naming.CgmesObjectReference;
import com.powsybl.cgmes.conversion.naming.CgmesObjectReference.Part;
import com.powsybl.cgmes.extensions.CgmesTapChanger;
Expand All @@ -21,6 +22,7 @@
import com.powsybl.commons.report.TypedValue;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.LoadDetail;
import com.powsybl.iidm.network.extensions.RemoteReactivePowerControl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -404,7 +406,7 @@ private static <C extends Connectable<C>> String getTapChangerId(C twt, String c
}

static boolean regulatingControlIsDefined(RatioTapChanger rtc) {
return !Double.isNaN(rtc.getTargetV())
return !Double.isNaN(rtc.getRegulationValue())
&& !Double.isNaN(rtc.getTargetDeadband())
&& rtc.getRegulationTerminal() != null;
}
Expand Down Expand Up @@ -513,6 +515,68 @@ static String obtainCalculatedSynchronousMachineKind(double minP, double maxP, R
return kind;
}

public static boolean isValidVoltageSetpoint(double v) {
return Double.isFinite(v) && v > 0;
}

public static boolean isValidReactivePowerSetpoint(double q) {
return Double.isFinite(q);
}

public 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 = isValidVoltageSetpoint(generator.getTargetV());
boolean validReactiveSetpoint = isValidReactivePowerSetpoint(rrpc.getTargetQ());
if (validReactiveSetpoint && !validVoltageSetpoint) {
return RegulatingControlEq.REGULATING_CONTROL_REACTIVE_POWER;
}
return RegulatingControlEq.REGULATING_CONTROL_VOLTAGE;
}
}

public 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 {
boolean validVoltageSetpoint = isValidVoltageSetpoint(svc.getVoltageSetpoint());
boolean validReactiveSetpoint = isValidReactivePowerSetpoint(svc.getReactivePowerSetpoint());
if (validReactiveSetpoint && !validVoltageSetpoint) {
return RegulatingControlEq.REGULATING_CONTROL_REACTIVE_POWER;
}
return RegulatingControlEq.REGULATING_CONTROL_VOLTAGE;
}
}

public static String getTcMode(RatioTapChanger rtc) {
if (rtc.getRegulationMode() == null) {
throw new PowsyblException("Regulation mode not defined for RTC.");
}
return switch (rtc.getRegulationMode()) {
case VOLTAGE -> RegulatingControlEq.REGULATING_CONTROL_VOLTAGE;
case REACTIVE_POWER -> RegulatingControlEq.REGULATING_CONTROL_REACTIVE_POWER;
};
}

public static String getPhaseTapChangerRegulationMode(PhaseTapChanger ptc) {
return switch (ptc.getRegulationMode()) {
case CURRENT_LIMITER -> RegulatingControlEq.REGULATING_CONTROL_CURRENT_FLOW;
case ACTIVE_POWER_CONTROL -> RegulatingControlEq.REGULATING_CONTROL_ACTIVE_POWER;
default -> throw new PowsyblException("Unexpected regulation mode: " + ptc.getRegulationMode());
};
}

public static boolean isMinusOrMaxValue(double value) {
return value == -Double.MAX_VALUE || value == Double.MAX_VALUE;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.powsybl.commons.exceptions.UncheckedXmlStreamException;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.Identifiable;
import com.powsybl.iidm.network.extensions.RemoteReactivePowerControl;
import com.powsybl.iidm.network.extensions.VoltagePerReactivePowerControl;

import org.apache.commons.lang3.tuple.Pair;
Expand All @@ -45,9 +46,6 @@
public final class EquipmentExport {

private static final String AC_DC_CONVERTER_DC_TERMINAL = "ACDCConverterDCTerminal";
private static final String PHASE_TAP_CHANGER_REGULATION_MODE_ACTIVE_POWER = "activePower";
private static final String PHASE_TAP_CHANGER_REGULATION_MODE_CURRENT_FLOW = "currentFlow";
private static final String RATIO_TAP_CHANGER_REGULATION_MODE_VOLTAGE = "voltage";
private static final String TERMINAL_BOUNDARY = "Terminal_Boundary";
private static final Logger LOG = LoggerFactory.getLogger(EquipmentExport.class);

Expand Down Expand Up @@ -382,7 +380,9 @@ private static void writeGenerators(Network network, Map<Terminal, String> mapTe
Set<String> generatingUnitsWritten = new HashSet<>();
for (Generator generator : network.getGenerators()) {
String cgmesOriginalClass = generator.getProperty(Conversion.PROPERTY_CGMES_ORIGINAL_CLASS, CgmesNames.SYNCHRONOUS_MACHINE);

RemoteReactivePowerControl rrpc = generator.getExtension(RemoteReactivePowerControl.class);
String mode = CgmesExportUtil.getGeneratorRegulatingControlMode(generator, rrpc);
Terminal regulatingTerminal = mode.equals(RegulatingControlEq.REGULATING_CONTROL_VOLTAGE) ? generator.getRegulatingTerminal() : rrpc.getRegulatingTerminal();
switch (cgmesOriginalClass) {
case CgmesNames.EQUIVALENT_INJECTION:
String reactiveCapabilityCurveId = writeReactiveCapabilityCurve(generator, cimNamespace, writer, context);
Expand All @@ -393,14 +393,14 @@ private static void writeGenerators(Network network, Map<Terminal, String> mapTe
cimNamespace, writer, context);
break;
case CgmesNames.EXTERNAL_NETWORK_INJECTION:
String regulatingControlId = RegulatingControlEq.writeKindVoltage(generator, exportedTerminalId(mapTerminal2Id, generator.getRegulatingTerminal()), regulatingControlsWritten, cimNamespace, writer, context);
String regulatingControlId = RegulatingControlEq.writeRegulatingControlEq(generator, exportedTerminalId(mapTerminal2Id, regulatingTerminal), regulatingControlsWritten, mode, cimNamespace, writer, context);
ExternalNetworkInjectionEq.write(context.getNamingStrategy().getCgmesId(generator), generator.getNameOrId(),
context.getNamingStrategy().getCgmesId(generator.getTerminal().getVoltageLevel()),
obtainGeneratorGovernorScd(generator), generator.getMaxP(), obtainMaxQ(generator), generator.getMinP(), obtainMinQ(generator),
regulatingControlId, cimNamespace, writer, context);
break;
case CgmesNames.SYNCHRONOUS_MACHINE:
regulatingControlId = RegulatingControlEq.writeKindVoltage(generator, exportedTerminalId(mapTerminal2Id, generator.getRegulatingTerminal()), regulatingControlsWritten, cimNamespace, writer, context);
regulatingControlId = RegulatingControlEq.writeRegulatingControlEq(generator, exportedTerminalId(mapTerminal2Id, regulatingTerminal), regulatingControlsWritten, mode, cimNamespace, writer, context);
writeSynchronousMachine(generator, cimNamespace, writeInitialP,
generator.getMinP(), generator.getMaxP(), generator.getTargetP(), generator.getRatedS(), generator.getEnergySource(),
regulatingControlId, writer, context, generatingUnitsWritten);
Expand Down Expand Up @@ -574,13 +574,15 @@ private static void writeShuntCompensators(Network network, Map<Terminal, String
context.getNamingStrategy().getCgmesId(s.getTerminal().getVoltageLevel()),
cimNamespace, writer, context);
} else {
// Shunt can only regulate voltage
String mode = RegulatingControlEq.REGULATING_CONTROL_VOLTAGE;
double bPerSection = 0.0;
double gPerSection = Double.NaN;
if (s.getModelType().equals(ShuntCompensatorModelType.LINEAR)) {
bPerSection = ((ShuntCompensatorLinearModel) s.getModel()).getBPerSection();
gPerSection = ((ShuntCompensatorLinearModel) s.getModel()).getGPerSection();
}
String regulatingControlId = RegulatingControlEq.writeKindVoltage(s, exportedTerminalId(mapTerminal2Id, s.getRegulatingTerminal()), regulatingControlsWritten, cimNamespace, writer, context);
String regulatingControlId = RegulatingControlEq.writeRegulatingControlEq(s, exportedTerminalId(mapTerminal2Id, s.getRegulatingTerminal()), regulatingControlsWritten, mode, cimNamespace, writer, context);
ShuntCompensatorEq.write(context.getNamingStrategy().getCgmesId(s), s.getNameOrId(), s.getSectionCount(), s.getMaximumSectionCount(), s.getTerminal().getVoltageLevel().getNominalV(), s.getModelType(), bPerSection, gPerSection, regulatingControlId,
context.getNamingStrategy().getCgmesId(s.getTerminal().getVoltageLevel()), cimNamespace, writer, context);
if (s.getModelType().equals(ShuntCompensatorModelType.NON_LINEAR)) {
Expand All @@ -600,7 +602,8 @@ private static void writeShuntCompensators(Network network, Map<Terminal, String
private static void writeStaticVarCompensators(Network network, Map<Terminal, String> mapTerminal2Id, Set<String> regulatingControlsWritten, String cimNamespace,
XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException {
for (StaticVarCompensator svc : network.getStaticVarCompensators()) {
String regulatingControlId = RegulatingControlEq.writeKindVoltage(svc, exportedTerminalId(mapTerminal2Id, svc.getRegulatingTerminal()), regulatingControlsWritten, cimNamespace, writer, context);
String mode = CgmesExportUtil.getSvcMode(svc);
String regulatingControlId = RegulatingControlEq.writeRegulatingControlEq(svc, exportedTerminalId(mapTerminal2Id, svc.getRegulatingTerminal()), regulatingControlsWritten, mode, cimNamespace, writer, context);
double inductiveRating = svc.getBmin() != 0 ? 1 / svc.getBmin() : 0;
double capacitiveRating = svc.getBmax() != 0 ? 1 / svc.getBmax() : 0;
StaticVarCompensatorEq.write(context.getNamingStrategy().getCgmesId(svc), svc.getNameOrId(), context.getNamingStrategy().getCgmesId(svc.getTerminal().getVoltageLevel()), regulatingControlId, inductiveRating, capacitiveRating, svc.getExtension(VoltagePerReactivePowerControl.class), svc.getRegulationMode(), svc.getVoltageSetpoint(), cimNamespace, writer, context);
Expand Down Expand Up @@ -838,7 +841,7 @@ private static <C extends Connectable<C>> void writePhaseTapChanger(C eq, PhaseT
Optional<String> regulatingControlId = getTapChangerControlId(eq, tapChangerId);
String cgmesRegulatingControlId = null;
if (regulatingControlId.isPresent() && CgmesExportUtil.regulatingControlIsDefined(ptc)) {
String mode = getPhaseTapChangerRegulationMode(ptc);
String mode = CgmesExportUtil.getPhaseTapChangerRegulationMode(ptc);
String controlName = twtName + "_PTC_RC";
String terminalId = CgmesExportUtil.getTerminalId(ptc.getRegulationTerminal(), context);
cgmesRegulatingControlId = context.getNamingStrategy().getCgmesId(regulatingControlId.get());
Expand Down Expand Up @@ -879,14 +882,6 @@ private static <C extends Connectable<C>> Optional<String> getTapChangerControlI
return Optional.empty();
}

private static String getPhaseTapChangerRegulationMode(PhaseTapChanger ptc) {
return switch (ptc.getRegulationMode()) {
case CURRENT_LIMITER -> PHASE_TAP_CHANGER_REGULATION_MODE_CURRENT_FLOW;
case ACTIVE_POWER_CONTROL -> PHASE_TAP_CHANGER_REGULATION_MODE_ACTIVE_POWER;
default -> throw new PowsyblException("Unexpected regulation mode: " + ptc.getRegulationMode());
};
}

private static int getPhaseTapChangerNeutralStep(PhaseTapChanger ptc) {
int neutralStep = ptc.getLowTapPosition();
double minAlpha = Math.abs(ptc.getStep(neutralStep).getAlpha());
Expand Down Expand Up @@ -922,8 +917,11 @@ private static <C extends Connectable<C>> void writeRatioTapChanger(C eq, RatioT
String terminalId = CgmesExportUtil.getTerminalId(rtc.getRegulationTerminal(), context);
cgmesRegulatingControlId = context.getNamingStrategy().getCgmesId(regulatingControlId.get());
if (!regulatingControlsWritten.contains(cgmesRegulatingControlId)) {
// Regulating control mode is always "voltage"
TapChangerEq.writeControl(cgmesRegulatingControlId, controlName, RATIO_TAP_CHANGER_REGULATION_MODE_VOLTAGE, terminalId, cimNamespace, writer, context);
String tccMode = CgmesExportUtil.getTcMode(rtc);
if (tccMode.equals(RegulatingControlEq.REGULATING_CONTROL_REACTIVE_POWER)) {
controlMode = "reactive";
}
TapChangerEq.writeControl(cgmesRegulatingControlId, controlName, tccMode, terminalId, cimNamespace, writer, context);
regulatingControlsWritten.add(cgmesRegulatingControlId);
}
}
Expand Down
Loading

0 comments on commit a240c8f

Please sign in to comment.