diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesReports.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesReports.java index 0622215fc54..045f852c87b 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesReports.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesReports.java @@ -293,4 +293,12 @@ public static void invalidPccTerminalReport(ReportNode reportNode, String conver .withSeverity(TypedValue.ERROR_SEVERITY) .add(); } + + public static void phaseTapChangerCurrentLimiterModeNotSupportedReport(ReportNode reportNode, String phaseTapChangerId) { + reportNode.newReportNode() + .withMessageTemplate("core.cgmes.conversion.phaseTapChangerCurrentLimiterModeNotSupported") + .withUntypedValue("phaseTapChangerId", phaseTapChangerId) + .withSeverity(TypedValue.WARN_SEVERITY) + .add(); + } } diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportUtil.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportUtil.java index a928308d6f5..2558e64f386 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportUtil.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportUtil.java @@ -576,13 +576,6 @@ public static String getTcMode(RatioTapChanger rtc) { }; } - 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; - }; - } - public static boolean isMinusOrMaxValue(double value) { return value == -Double.MAX_VALUE || value == Double.MAX_VALUE; } diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/EquipmentExport.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/EquipmentExport.java index bfcf2f89ef0..1483ed1afee 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/EquipmentExport.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/EquipmentExport.java @@ -8,6 +8,7 @@ package com.powsybl.cgmes.conversion.export; import com.powsybl.cgmes.conversion.CgmesExport; +import com.powsybl.cgmes.conversion.CgmesReports; import com.powsybl.cgmes.conversion.Conversion; import com.powsybl.cgmes.conversion.elements.dc.DCEquipment; import com.powsybl.cgmes.conversion.naming.NamingStrategy; @@ -673,7 +674,7 @@ private static void writeTwoWindingsTransformers(Network network, Map> void writePhaseTapChanger(C eq, PhaseTapChanger ptc, String twtName, int endNumber, String endId, double neutralU, Set regulatingControlsWritten, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { + private static > void writePhaseTapChanger(C eq, PhaseTapChanger ptc, String twtName, int endNumber, String endId, double neutralU, Set regulatingControlsWritten, String cimNamespace, String euNamespace, Set exportedLimitTypes, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { if (ptc != null) { String aliasType = Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + CgmesNames.PHASE_TAP_CHANGER + endNumber; String tapChangerId = eq.getAliasFromType(aliasType).orElseThrow(); @@ -861,11 +862,30 @@ private static > void writePhaseTapChanger(C eq, PhaseT Optional regulatingControlId = getTapChangerControlId(eq, tapChangerId); String cgmesRegulatingControlId = null; if (regulatingControlId.isPresent() && CgmesExportUtil.regulatingControlIsDefined(ptc)) { - String mode = CgmesExportUtil.getPhaseTapChangerRegulationMode(ptc); - String controlName = twtName + "_PTC_RC"; - String terminalId = CgmesExportUtil.getTerminalId(ptc.getRegulationTerminal(), context); cgmesRegulatingControlId = context.getNamingStrategy().getCgmesId(regulatingControlId.get()); if (!regulatingControlsWritten.contains(cgmesRegulatingControlId)) { + String mode = RegulatingControlEq.REGULATING_CONTROL_ACTIVE_POWER; + String controlName = twtName + "_PTC_RC"; + String terminalId = CgmesExportUtil.getTerminalId(ptc.getRegulationTerminal(), context); + if (ptc.getRegulationMode() == PhaseTapChanger.RegulationMode.CURRENT_LIMITER) { + // Log not supported regulation mode + CgmesReports.phaseTapChangerCurrentLimiterModeNotSupportedReport(context.getReportNode(), cgmesTapChangerId); + + // Add a CurrentLimit with the PhaseTapChanger current limiter regulation value to the regulated terminal. + String operationalLimitSetId = context.getNamingStrategy().getCgmesId(ref(terminalId), ref(PhaseTapChanger.RegulationMode.CURRENT_LIMITER.name()), OPERATIONAL_LIMIT_SET); + String operationalLimitSetName = twtName + "_PTC_" + PhaseTapChanger.RegulationMode.CURRENT_LIMITER; + OperationalLimitSetEq.write(operationalLimitSetId, operationalLimitSetName, terminalId, cimNamespace, writer, context); + + String className = "CurrentLimit"; + String operationalLimitId = context.getNamingStrategy().getCgmesId(ref(operationalLimitSetId), ref(className), PATL, OPERATIONAL_LIMIT_VALUE); + String operationalLimitTypeId = context.getNamingStrategy().getCgmesId(PATL, OPERATIONAL_LIMIT_TYPE); + LoadingLimitEq.write(operationalLimitId, className, "PATL", ptc.getRegulationValue(), operationalLimitTypeId, operationalLimitSetId, cimNamespace, writer, context); + + if (!exportedLimitTypes.contains(operationalLimitTypeId)) { + OperationalLimitTypeEq.writePatl(operationalLimitTypeId, cimNamespace, euNamespace, writer, context); + exportedLimitTypes.add(operationalLimitTypeId); + } + } TapChangerEq.writeControl(cgmesRegulatingControlId, controlName, mode, terminalId, cimNamespace, writer, context); regulatingControlsWritten.add(cgmesRegulatingControlId); } @@ -1238,7 +1258,7 @@ private static void writeLoadingLimits(LoadingLimits limits, String cimNamespace // Write the permanent limit String className = loadingLimitClassName(limits); String operationalLimitId = context.getNamingStrategy().getCgmesId(ref(operationalLimitSetId), ref(className), PATL, OPERATIONAL_LIMIT_VALUE); - LoadingLimitEq.write(operationalLimitId, limits, "PATL", limits.getPermanentLimit(), operationalLimitTypeId, operationalLimitSetId, cimNamespace, writer, context); + LoadingLimitEq.write(operationalLimitId, className, "PATL", limits.getPermanentLimit(), operationalLimitTypeId, operationalLimitSetId, cimNamespace, writer, context); if (!limits.getTemporaryLimits().isEmpty()) { for (LoadingLimits.TemporaryLimit temporaryLimit : limits.getTemporaryLimits()) { @@ -1254,7 +1274,7 @@ private static void writeLoadingLimits(LoadingLimits limits, String cimNamespace // Write the temporary limit operationalLimitId = context.getNamingStrategy().getCgmesId(ref(operationalLimitSetId), ref(className), TATL, ref(acceptableDuration), OPERATIONAL_LIMIT_VALUE); String temporaryLimitName = temporaryLimit.getName().isEmpty() ? "TATL " + temporaryLimit.getAcceptableDuration() : temporaryLimit.getName(); // If the temporary limit name is empty, write TATL and the acceptable duration - LoadingLimitEq.write(operationalLimitId, limits, temporaryLimitName, temporaryLimit.getValue(), operationalLimitTypeId, operationalLimitSetId, cimNamespace, writer, context); + LoadingLimitEq.write(operationalLimitId, className, temporaryLimitName, temporaryLimit.getValue(), operationalLimitTypeId, operationalLimitSetId, cimNamespace, writer, context); } } } diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/SteadyStateHypothesisExport.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/SteadyStateHypothesisExport.java index 4a292c936fe..91c387e19f6 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/SteadyStateHypothesisExport.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/SteadyStateHypothesisExport.java @@ -488,13 +488,13 @@ private static void addRegulatingControlView(TapChanger tc, CgmesTap } else if (tc instanceof PhaseTapChanger phaseTapChanger && CgmesExportUtil.regulatingControlIsDefined(phaseTapChanger)) { boolean valid; - String unitMultiplier = switch (CgmesExportUtil.getPhaseTapChangerRegulationMode(phaseTapChanger)) { - case RegulatingControlEq.REGULATING_CONTROL_CURRENT_FLOW -> { + String unitMultiplier = switch (phaseTapChanger.getRegulationMode()) { + case PhaseTapChanger.RegulationMode.CURRENT_LIMITER -> { // Unit multiplier is none (multiply by 1), regulation value is a current in Amperes valid = true; yield "none"; } - case RegulatingControlEq.REGULATING_CONTROL_ACTIVE_POWER -> { + case PhaseTapChanger.RegulationMode.ACTIVE_POWER_CONTROL -> { // Unit multiplier is M, regulation value is an active power flow in MW valid = true; yield "M"; @@ -505,12 +505,13 @@ private static void addRegulatingControlView(TapChanger tc, CgmesTap } }; if (valid) { + boolean isActivePowerControlMode = phaseTapChanger.getRegulationMode() == PhaseTapChanger.RegulationMode.ACTIVE_POWER_CONTROL; rcv = new RegulatingControlView(controlId, RegulatingControlType.TAP_CHANGER_CONTROL, true, - phaseTapChanger.isRegulating(), - phaseTapChanger.getTargetDeadband(), - phaseTapChanger.getRegulationValue(), + isActivePowerControlMode && phaseTapChanger.isRegulating(), + isActivePowerControlMode ? phaseTapChanger.getTargetDeadband() : 0.0, + isActivePowerControlMode ? phaseTapChanger.getRegulationValue() : 0.0, unitMultiplier); } } diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/LoadingLimitEq.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/LoadingLimitEq.java index 9a9086ef5e1..631cfe1d8cb 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/LoadingLimitEq.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/LoadingLimitEq.java @@ -23,11 +23,10 @@ */ public final class LoadingLimitEq { - public static void write(String id, LoadingLimits loadingLimits, String name, double value, + public static void write(String id, String className, String name, double value, String operationalLimitTypeId, String operationalLimitSetId, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { - String cgmesClass = loadingLimitClassName(loadingLimits); - CgmesExportUtil.writeStartIdName(cgmesClass, id, name, cimNamespace, writer, context); - writer.writeStartElement(cimNamespace, cgmesClass + "." + getLimitValueAttributeName(context)); + CgmesExportUtil.writeStartIdName(className, id, name, cimNamespace, writer, context); + writer.writeStartElement(cimNamespace, className + "." + getLimitValueAttributeName(context)); writer.writeCharacters(CgmesExportUtil.format(value)); writer.writeEndElement(); CgmesExportUtil.writeReference("OperationalLimit.OperationalLimitSet", operationalLimitSetId, cimNamespace, writer, context); diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/RegulatingControlEq.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/RegulatingControlEq.java index 83e478b97a8..4fd4f09da92 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/RegulatingControlEq.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/RegulatingControlEq.java @@ -27,7 +27,6 @@ public final class RegulatingControlEq { public static final String REGULATING_CONTROL_VOLTAGE = "RegulatingControlModeKind.voltage"; public static final String REGULATING_CONTROL_REACTIVE_POWER = "RegulatingControlModeKind.reactivePower"; public static final String REGULATING_CONTROL_ACTIVE_POWER = "RegulatingControlModeKind.activePower"; - public static final String REGULATING_CONTROL_CURRENT_FLOW = "RegulatingControlModeKind.currentFlow"; public static String writeRegulatingControlEq(Connectable c, String terminalId, Set regulatingControlsWritten, String mode, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { String regulatingControlId = context.getNamingStrategy().getCgmesIdFromProperty(c, Conversion.PROPERTY_REGULATING_CONTROL); diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/TapChangerConversionTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/TapChangerConversionTest.java index d4963249275..473ddfaf7c7 100644 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/TapChangerConversionTest.java +++ b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/TapChangerConversionTest.java @@ -13,6 +13,7 @@ import com.powsybl.commons.test.AbstractSerDeTest; import com.powsybl.commons.test.PowsyblTestReportResourceBundle; import com.powsybl.iidm.network.*; +import com.powsybl.iidm.network.test.PhaseShifterTestCaseFactory; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -64,4 +65,39 @@ void invalidLtcFlagTest() throws IOException { assertTrue(logs.contains("TapChanger PTC has regulation enabled but has no load tap changing capability. Fixed ltcFlag to true.")); } + @Test + void currentLimiterExportTest() throws IOException { + // IIDM network: + // A PhaseShifter with current limiter regulation mode. + // CGMES network: + // A PhaseShifter with active power regulation mode, off regulation and the current limit saved as an operational limit. + Network network = PhaseShifterTestCaseFactory.createRegulatingWithoutMode(); + + // PhaseShifter PS1 has a PhaseTapChanger in current limiter regulation mode, + // with a current limit value of 200A at PS1 secondary terminal. + PhaseTapChanger ptc = network.getTwoWindingsTransformer("PS1").getPhaseTapChanger(); + assertEquals(PhaseTapChanger.RegulationMode.CURRENT_LIMITER, ptc.getRegulationMode()); + assertEquals(200, ptc.getRegulationValue()); + assertTrue(ptc.isRegulating()); + assertEquals("PS1", ptc.getRegulationTerminal().getConnectable().getId()); + assertEquals(2, ptc.getRegulationTerminal().getSide().getNum()); + assertTrue(network.getTwoWindingsTransformer("PS1").getOperationalLimitsGroups2().isEmpty()); + + // PhaseTapChanger is in active power regulation mode and the regulation is disabled. + // A CurentLimit with the value 200A has been created. + String eqFile = writeCgmesProfile(network, "EQ", tmpDir); + String tapChangerControl = getElement(eqFile, "TapChangerControl", "PS1_PTC_RC"); + assertEquals("http://iec.ch/TC57/2013/CIM-schema-cim16#RegulatingControlModeKind.activePower", getResource(tapChangerControl, "RegulatingControl.mode")); + String limitSet = getElement(eqFile, "OperationalLimitSet", "PS1_PT_T_2_CURRENT_LIMITER_OLS"); + assertEquals("PS1_PT_T_2", getResource(limitSet, "OperationalLimitSet.Terminal")); + String currentLimit = getElement(eqFile, "CurrentLimit", "PS1_PT_T_2_CURRENT_LIMITER_OLS_CurrentLimit_PATL_OLV"); + assertEquals("200", getAttribute(currentLimit, "CurrentLimit.value")); + + String sshFile = writeCgmesProfile(network, "SSH", tmpDir); + tapChangerControl = getElement(sshFile, "TapChangerControl", "PS1_PTC_RC"); + assertEquals("false", getAttribute(tapChangerControl, "RegulatingControl.enabled")); + assertEquals("0", getAttribute(tapChangerControl, "RegulatingControl.targetDeadband")); + assertEquals("0", getAttribute(tapChangerControl, "RegulatingControl.targetValue")); + } + } diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/EquipmentExportTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/EquipmentExportTest.java index 31e92cad1a3..3aabcdba3f4 100644 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/EquipmentExportTest.java +++ b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/EquipmentExportTest.java @@ -1021,14 +1021,14 @@ void phaseTapChangerTapChangerControlEQTest() throws IOException { Properties exportParams = new Properties(); exportParams.put(CgmesExport.PROFILES, "EQ"); - // PST with no regulation mode but regulating true => set to CURRENT_LIMITER mode + // PST with no regulation mode but regulating true => set to ACTIVE_POWER_CONTROL mode network = PhaseShifterTestCaseFactory.createRegulatingWithoutMode(); assertTrue(network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().isRegulating()); eq = getEQ(network, baseName, tmpDir, exportParams); - testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_PS1_PT_T_2", "currentFlow"); + testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_PS1_PT_T_2", "activePower"); network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().setRegulating(false); eq = getEQ(network, baseName, tmpDir, exportParams); - testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_PS1_PT_T_2", "currentFlow"); + testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_PS1_PT_T_2", "activePower"); // PST local with ACTIVE_POWER_CONTROL network = PhaseShifterTestCaseFactory.createLocalActivePowerWithTargetDeadband(); @@ -1039,24 +1039,6 @@ void phaseTapChangerTapChangerControlEQTest() throws IOException { eq = getEQ(network, baseName, tmpDir, exportParams); testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_PS1_PT_T_2", "activePower"); - // PST local with CURRENT_LIMITER - network = PhaseShifterTestCaseFactory.createLocalCurrentLimiterWithTargetDeadband(); - assertFalse(network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().isRegulating()); - eq = getEQ(network, baseName, tmpDir, exportParams); - testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_PS1_PT_T_2", "currentFlow"); - network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().setRegulating(true); - eq = getEQ(network, baseName, tmpDir, exportParams); - testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_PS1_PT_T_2", "currentFlow"); - - // PST remote with CURRENT_LIMITER - network = PhaseShifterTestCaseFactory.createRemoteCurrentLimiterWithTargetDeadband(); - assertFalse(network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().isRegulating()); - eq = getEQ(network, baseName, tmpDir, exportParams); - testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_LD2_EC_T_1", "currentFlow"); - network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().setRegulating(true); - eq = getEQ(network, baseName, tmpDir, exportParams); - testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_LD2_EC_T_1", "currentFlow"); - // PST remote with ACTIVE_POWER_CONTROL network = PhaseShifterTestCaseFactory.createRemoteActivePowerWithTargetDeadband(); assertFalse(network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().isRegulating()); diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/SteadyStateHypothesisExportTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/SteadyStateHypothesisExportTest.java index 07081e75af9..fd44cbb5e3a 100644 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/SteadyStateHypothesisExportTest.java +++ b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/SteadyStateHypothesisExportTest.java @@ -401,10 +401,10 @@ void phaseTapChangerTapChangerControlSSHTest() throws IOException { // PST with no regulation mode but regulating true => set to CURRENT_LIMITER mode network = PhaseShifterTestCaseFactory.createWithTargetDeadband(); ssh = getSSH(network, baseName, tmpDir, exportParams); - testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "true", "10", "200", "none"); + testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "true", "0", "0", "none"); network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().setRegulating(false); ssh = getSSH(network, baseName, tmpDir, exportParams); - testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "false", "10", "200", "none"); + testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "false", "0", "0", "none"); // PST local with ACTIVE_POWER_CONTROL network = PhaseShifterTestCaseFactory.createLocalActivePowerWithTargetDeadband(); @@ -417,18 +417,18 @@ void phaseTapChangerTapChangerControlSSHTest() throws IOException { // PST local with CURRENT_LIMITER network = PhaseShifterTestCaseFactory.createLocalCurrentLimiterWithTargetDeadband(); ssh = getSSH(network, baseName, tmpDir, exportParams); - testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "true", "10", "200", "none"); + testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "true", "0", "0", "none"); network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().setRegulating(false); ssh = getSSH(network, baseName, tmpDir, exportParams); - testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "false", "10", "200", "none"); + testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "false", "0", "0", "none"); // PST remote with CURRENT_LIMITER network = PhaseShifterTestCaseFactory.createRemoteCurrentLimiterWithTargetDeadband(); ssh = getSSH(network, baseName, tmpDir, exportParams); - testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "true", "10", "200", "none"); + testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "true", "0", "0", "none"); network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().setRegulating(false); ssh = getSSH(network, baseName, tmpDir, exportParams); - testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "false", "10", "200", "none"); + testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "false", "0", "0", "none"); // PST remote with ACTIVE_POWER_CONTROL network = PhaseShifterTestCaseFactory.createRemoteActivePowerWithTargetDeadband(); diff --git a/commons/src/main/resources/com/powsybl/commons/reports.properties b/commons/src/main/resources/com/powsybl/commons/reports.properties index 1a6fb3f3674..c93a7d42ec9 100644 --- a/commons/src/main/resources/com/powsybl/commons/reports.properties +++ b/commons/src/main/resources/com/powsybl/commons/reports.properties @@ -22,6 +22,7 @@ core.cgmes.conversion.missingMandatoryAttribute = Couldn't retrieve mandatory at core.cgmes.conversion.multipleUnpairedDanglingLinesAtSameBoundary = Multiple unpaired DanglingLines were connected at the same boundary side. Adjusted original injection from (${p0}, ${q0}) to (${p0Adjusted}, ${q0Adjusted}) for dangling line ${danglingLineId}. core.cgmes.conversion.nominalVoltageIsZero = Ignoring VoltageLevel: ${voltageLevelId} for its nominal voltage is equal to 0. core.cgmes.conversion.notVisitedDcEquipment = DCEquipment ${dcEquipmentId} is discarded as it couldn't be attached to any DCIsland. +core.cgmes.conversion.phaseTapChangerCurrentLimiterModeNotSupported = PhaseTapChanger ${phaseTapChangerId}: current limiter regulation mode isn't supported in CGMES. PhaseTapChanger regulation disabled and mode changed to active power flow. core.cgmes.conversion.removingUnattachedHvdcConverterStation = HVDC Converter Station ${converterId} will be removed since it has no attached HVDC line. core.cgmes.conversion.settingVoltagesAndAngles = Setting voltages and angles. core.cgmes.conversion.substationMapping = Original ${substationMappingSize} Substation container(s) connected by transformers have been merged in IIDM. Map of original Substation to IIDM: ${mapAsString}. diff --git a/commons/src/main/resources/com/powsybl/commons/reports_fr.properties b/commons/src/main/resources/com/powsybl/commons/reports_fr.properties index d2001983449..cc8e3da2ebb 100644 --- a/commons/src/main/resources/com/powsybl/commons/reports_fr.properties +++ b/commons/src/main/resources/com/powsybl/commons/reports_fr.properties @@ -22,6 +22,7 @@ core.cgmes.conversion.missingMandatoryAttribute = Impossible de r core.cgmes.conversion.multipleUnpairedDanglingLinesAtSameBoundary = Plusieurs lignes frontières non appairées ont été connectées du même côté de la frontière. Ajustement de l'injection originale de (${p0}, ${q0}) à (${p0Adjusted}, ${q0Adjusted}) pour la ligne frontière ${danglingLineId}. core.cgmes.conversion.nominalVoltageIsZero = Poste ignoré : ${voltageLevelId} car sa tension nominale est égale à 0. core.cgmes.conversion.notVisitedDcEquipment = DCEquipment ${dcEquipmentId} est enlevé car il ne peut être rattaché à aucun DCIsland. +core.cgmes.conversion.phaseTapChangerCurrentLimiterModeNotSupported = Déphaseur ${phaseTapChangerId}: le mode de régulation en limitation de courant n'est pas supporté en CGMES. Déphaseur passé hors-régulation avec un mode de régulation en transit de puissance active. core.cgmes.conversion.removingUnattachedHvdcConverterStation = La station de conversion HVDC ${converterId} est supprimée car elle n'a pas de ligne HVDC de rattachement. core.cgmes.conversion.settingVoltagesAndAngles = Configuration des tensions et des angles. core.cgmes.conversion.substationMapping = ${substationMappingSize} sites connectés par des transformateurs ont été fusionnés dans l'IIDM. Map du site d'origine en IIDM : ${mapAsString}. diff --git a/docs/grid_exchange_formats/cgmes/export.md b/docs/grid_exchange_formats/cgmes/export.md index 01702d5a5b8..7315a31a584 100644 --- a/docs/grid_exchange_formats/cgmes/export.md +++ b/docs/grid_exchange_formats/cgmes/export.md @@ -410,16 +410,16 @@ If the transformer has a `TapChanger`, the CGMES SSH `step` is written from the If the network comes from a CIM-CGMES model and the tap changer has initially a `TapChangerControl`, it always has at export too. Otherwise, a `TapChangerControl` is exported for the tap changer if it is considered as defined. A `RatioTapChanger` is considered as defined if it has a valid regulation value, a valid target deadband and a non-null regulating terminal. -A `PhaseTapChanger` is considered as defined if it has a valid regulation value, -a valid target deadband, and a non-null regulating terminal. By default its regulation mode is set to `CURRENT_LIMITER`. +A `PhaseTapChanger` is considered as defined if it has a valid regulation value, a valid target deadband, and a non-null regulating terminal. In a `RatioTapChanger`, the `TapChangerControl` is exported with `RegulatingControl.mode` set to `RegulatingControlModeKind.reactivePower` when `RatioTapChanger` `regulationMode` is set to `REACTIVE_POWER`, and with `RegulatingControl.mode` set to `RegulatingControlModeKind.voltage` when `RatioTapChanger` `regulationMode` is set to `VOLTAGE`. -In a `PhaseTapChanger`, the `TapChangerControl` is exported with `RegulatingControl.mode` set to `RegulatingControlModeKind.activePower` when -`PhaseTapChanger` `regulationMode` is set to `ACTIVE_POWER_CONTROL`, and with `RegulatingControl.mode` set to `RegulatingControlModeKind.currentFlow` -when `PhaseTapChanger` `regulationMode` is set to `CURRENT_LIMITER`. +In a `PhaseTapChanger`, the `TapChangerControl` is always exported with `RegulatingControl.mode` set to `RegulatingControlModeKind.activePower`. +If the original `PhaseTapChanger` `regulationMode` is `CURRENT_LIMITER`, the `TapChangerControl` regulation is disabled, +the regulation target value and deadband are set to 0, and an `OperationalLimitSet` with a `CurrentLimit` is created +at the regulated terminal with the regulation value. (cgmes-two-winding-transformer-export)= ### TwoWindingsTransformer