diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportContext.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportContext.java index 2af33a231dc..a40a2338ad1 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportContext.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportContext.java @@ -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; } @@ -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); } @@ -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); } 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 351444b7672..e4f532b3e8c 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 @@ -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; @@ -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; @@ -404,7 +406,7 @@ private static > 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; } @@ -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; } 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 2355ac9b16c..a69c4f5fccc 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 @@ -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; @@ -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); @@ -382,7 +380,9 @@ private static void writeGenerators(Network network, Map mapTe Set 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); @@ -393,14 +393,14 @@ private static void writeGenerators(Network network, Map 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); @@ -574,13 +574,15 @@ private static void writeShuntCompensators(Network network, Map mapTerminal2Id, Set 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); @@ -838,7 +841,7 @@ private static > void writePhaseTapChanger(C eq, PhaseT Optional 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()); @@ -879,14 +882,6 @@ private static > Optional 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()); @@ -922,8 +917,11 @@ private static > 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); } } 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 b91825b82f6..1a47768509a 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 @@ -9,6 +9,7 @@ import com.powsybl.cgmes.conversion.CgmesExport; import com.powsybl.cgmes.conversion.Conversion; +import com.powsybl.cgmes.conversion.export.elements.RegulatingControlEq; import com.powsybl.cgmes.extensions.CgmesControlArea; import com.powsybl.cgmes.extensions.CgmesControlAreas; import com.powsybl.cgmes.extensions.CgmesTapChanger; @@ -21,6 +22,7 @@ import com.powsybl.iidm.network.*; import com.powsybl.iidm.network.extensions.ActivePowerControl; import com.powsybl.iidm.network.extensions.ReferencePriority; +import com.powsybl.iidm.network.extensions.RemoteReactivePowerControl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -192,6 +194,7 @@ private static String cgmesTapChangerId(TwoWindingsTransformer twt, String tapCh private static void writeTapChangers(Network network, String cimNamespace, Map> regulatingControlViews, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { for (TwoWindingsTransformer twt : network.getTwoWindingsTransformers()) { + CgmesExportUtil.addUpdateCgmesTapChangerExtension(twt, context); if (twt.hasPhaseTapChanger()) { String ptcId = cgmesTapChangerId(twt, CgmesNames.PHASE_TAP_CHANGER, context); writeTapChanger(twt, ptcId, twt.getPhaseTapChanger(), CgmesNames.PHASE_TAP_CHANGER_TABULAR, regulatingControlViews, cimNamespace, writer, context); @@ -204,6 +207,7 @@ private static void writeTapChangers(Network network, String cimNamespace, Map new ArrayList<>()).add(rcv); } } - private static boolean isValidSvcVolatgeSetpoint(double v) { - return Double.isFinite(v) && v > 0; - } - - private static boolean isValidSvcReactivePowerSetpoint(double q) { - return Double.isFinite(q); - } - private static void writeStaticVarCompensators(Network network, String cimNamespace, Map> regulatingControlViews, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { for (StaticVarCompensator svc : network.getStaticVarCompensators()) { @@ -409,12 +421,11 @@ private static void writeStaticVarCompensators(Network network, String cimNamesp // Regulating control could be reactive power or voltage double targetValue; String multiplier; - if (regulationMode == StaticVarCompensator.RegulationMode.VOLTAGE - || regulationMode == StaticVarCompensator.RegulationMode.OFF && isValidSvcVolatgeSetpoint(svc.getVoltageSetpoint())) { + String svcMode = CgmesExportUtil.getSvcMode(svc); + if (svcMode.equals(RegulatingControlEq.REGULATING_CONTROL_VOLTAGE)) { targetValue = svc.getVoltageSetpoint(); multiplier = "k"; - } else if (regulationMode == StaticVarCompensator.RegulationMode.REACTIVE_POWER - || regulationMode == StaticVarCompensator.RegulationMode.OFF && isValidSvcReactivePowerSetpoint(svc.getReactivePowerSetpoint())) { + } else if (svcMode.equals(RegulatingControlEq.REGULATING_CONTROL_REACTIVE_POWER)) { targetValue = svc.getReactivePowerSetpoint(); multiplier = "M"; } else { @@ -451,24 +462,29 @@ private static void addRegulatingControlView(TapChanger tc, CgmesTap RegulatingControlView rcv = null; if (tc instanceof RatioTapChanger ratioTapChanger && CgmesExportUtil.regulatingControlIsDefined(ratioTapChanger)) { + String controlMode = CgmesExportUtil.getTcMode(ratioTapChanger); + String unitMultiplier = switch (controlMode) { + case RegulatingControlEq.REGULATING_CONTROL_VOLTAGE -> "k"; + case RegulatingControlEq.REGULATING_CONTROL_REACTIVE_POWER -> "M"; + default -> "none"; + }; rcv = new RegulatingControlView(controlId, RegulatingControlType.TAP_CHANGER_CONTROL, true, ratioTapChanger.isRegulating(), ratioTapChanger.getTargetDeadband(), - ratioTapChanger.getTargetV(), - // Unit multiplier is k for ratio tap changers (regulation value is a voltage in kV) - "k"); + ratioTapChanger.getRegulationValue(), + unitMultiplier); } else if (tc instanceof PhaseTapChanger phaseTapChanger && CgmesExportUtil.regulatingControlIsDefined(phaseTapChanger)) { boolean valid; - String unitMultiplier = switch (phaseTapChanger.getRegulationMode()) { - case CURRENT_LIMITER -> { + String unitMultiplier = switch (CgmesExportUtil.getPhaseTapChangerRegulationMode(phaseTapChanger)) { + case RegulatingControlEq.REGULATING_CONTROL_CURRENT_FLOW -> { // Unit multiplier is none (multiply by 1), regulation value is a current in Amperes valid = true; yield "none"; } - case ACTIVE_POWER_CONTROL -> { + case RegulatingControlEq.REGULATING_CONTROL_ACTIVE_POWER -> { // Unit multiplier is M, regulation value is an active power flow in MW valid = true; yield "M"; 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 eac5db96020..68b03f05e2a 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 @@ -25,25 +25,24 @@ 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 writeKindVoltage(Connectable c, String terminalId, Set regulatingControlsWritten, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { + 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.CGMES_PREFIX_ALIAS_PROPERTIES + "RegulatingControl"); if (regulatingControlId != null && !regulatingControlsWritten.contains(regulatingControlId)) { String regulatingControlName = "RC_" + c.getNameOrId(); - RegulatingControlEq.writeKindVoltage(regulatingControlId, regulatingControlName, terminalId, cimNamespace, writer, context); + CgmesExportUtil.writeStartIdName("RegulatingControl", regulatingControlId, regulatingControlName, cimNamespace, writer, context); + CgmesExportUtil.writeReference("RegulatingControl.Terminal", terminalId, cimNamespace, writer, context); + writer.writeEmptyElement(cimNamespace, "RegulatingControl.mode"); + writer.writeAttribute(RDF_NAMESPACE, CgmesNames.RESOURCE, cimNamespace + mode); + writer.writeEndElement(); regulatingControlsWritten.add(regulatingControlId); } return regulatingControlId; } - private static void writeKindVoltage(String id, String regulatingControlName, String terminalId, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { - CgmesExportUtil.writeStartIdName("RegulatingControl", id, regulatingControlName, cimNamespace, writer, context); - CgmesExportUtil.writeReference("RegulatingControl.Terminal", terminalId, cimNamespace, writer, context); - writer.writeEmptyElement(cimNamespace, "RegulatingControl.mode"); - writer.writeAttribute(RDF_NAMESPACE, CgmesNames.RESOURCE, cimNamespace + REGULATING_CONTROL_VOLTAGE); - writer.writeEndElement(); - } - private RegulatingControlEq() { } } diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/TapChangerEq.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/TapChangerEq.java index 3d0125423dc..a35419d45fb 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/TapChangerEq.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/TapChangerEq.java @@ -99,7 +99,7 @@ public static void writeRatio(String id, String tapChangerName, String transform public static void writeControl(String id, String name, String mode, String terminalId, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { CgmesExportUtil.writeStartIdName("TapChangerControl", id, name, cimNamespace, writer, context); writer.writeEmptyElement(cimNamespace, "RegulatingControl.mode"); - writer.writeAttribute(RDF_NAMESPACE, CgmesNames.RESOURCE, String.format("%s%s.%s", cimNamespace, "RegulatingControlModeKind", mode)); + writer.writeAttribute(RDF_NAMESPACE, CgmesNames.RESOURCE, String.format("%s%s", cimNamespace, mode)); CgmesExportUtil.writeReference("RegulatingControl.Terminal", terminalId, cimNamespace, writer, context); writer.writeEndElement(); } diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/CgmesExportTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/CgmesExportTest.java index e66a700efa0..f5e9f4c5977 100644 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/CgmesExportTest.java +++ b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/CgmesExportTest.java @@ -634,7 +634,7 @@ void testCanGeneratorControl() throws IOException { generatorRcc.removeProperty(Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + "RegulatingControl"); generatorNoRcc.removeProperty(Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + "RegulatingControl"); - // RC shouldn't be exported without targetV + // RC is exported without targetV, if reactive capability is, or it was imported double rccTargetV = generatorRcc.getTargetV(); generatorRcc.setVoltageRegulatorOn(false); generatorRcc.setTargetV(Double.NaN); @@ -642,19 +642,17 @@ void testCanGeneratorControl() throws IOException { double noRccTargetV = generatorNoRcc.getTargetV(); generatorNoRcc.setVoltageRegulatorOn(false); generatorNoRcc.setTargetV(Double.NaN); - - //network.write("CGMES", null, tmpDir.resolve(baseName)); new CgmesExport().export(network, exportParams, new DirectoryDataSource(tmpDir, baseName)); eq = Files.readString(tmpDir.resolve(baseName + "_EQ.xml")); - assertFalse(eq.contains("3a3b27be-b18b-4385-b557-6735d733baf0_RC")); - assertFalse(eq.contains("550ebe0d-f2b2-48c1-991f-cebea43a21aa_RC")); + assertTrue(eq.contains("3a3b27be-b18b-4385-b557-6735d733baf0_RC")); + assertTrue(eq.contains("550ebe0d-f2b2-48c1-991f-cebea43a21aa_RC")); generatorRcc.setTargetV(rccTargetV); generatorRcc.setVoltageRegulatorOn(true); generatorNoRcc.setTargetV(noRccTargetV); generatorNoRcc.setVoltageRegulatorOn(true); - // RC shouldn't be exported when Qmin and Qmax are the same + // RC shouldn't be exported when Qmin and Qmax are the same, but it exists when it was already imported ReactiveCapabilityCurveAdder rccAdder = generatorRcc.newReactiveCapabilityCurve(); ReactiveCapabilityCurve rcc = (ReactiveCapabilityCurve) generatorRcc.getReactiveLimits(); rcc.getPoints().forEach(point -> rccAdder.beginPoint().setP(point.getP()).setMaxQ(point.getMaxQ()).setMinQ(point.getMaxQ()).endPoint()); @@ -667,8 +665,8 @@ void testCanGeneratorControl() throws IOException { new CgmesExport().export(network, exportParams, new DirectoryDataSource(tmpDir, baseName)); eq = Files.readString(tmpDir.resolve(baseName + "_EQ.xml")); - assertFalse(eq.contains("3a3b27be-b18b-4385-b557-6735d733baf0_RC")); - assertFalse(eq.contains("550ebe0d-f2b2-48c1-991f-cebea43a21aa_RC")); + assertTrue(eq.contains("3a3b27be-b18b-4385-b557-6735d733baf0_RC")); + assertTrue(eq.contains("550ebe0d-f2b2-48c1-991f-cebea43a21aa_RC")); } } 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 4281631f520..1c74cb09b75 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 @@ -29,11 +29,11 @@ import com.powsybl.computation.local.LocalComputationManager; import com.powsybl.iidm.network.*; import com.powsybl.iidm.network.ThreeSides; -import com.powsybl.iidm.network.test.ThreeWindingsTransformerNetworkFactory; +import com.powsybl.iidm.network.extensions.RemoteReactivePowerControl; +import com.powsybl.iidm.network.test.*; import com.powsybl.iidm.serde.ExportOptions; import com.powsybl.iidm.serde.NetworkSerDe; import com.powsybl.iidm.serde.XMLImporter; -import com.powsybl.iidm.network.test.FourSubstationsNodeBreakerFactory; import com.powsybl.iidm.network.util.BranchData; import com.powsybl.iidm.network.util.TwtData; @@ -51,9 +51,12 @@ import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.FileSystem; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; import static org.junit.jupiter.api.Assertions.*; @@ -1004,6 +1007,399 @@ void synchronousMachineKindExportAndImportTest() throws IOException { assertEquals(expectedOperatingMode, actualOperatingMode); } + @Test + void phaseTapChangerTapChangerControlEQTest() throws IOException { + String exportFolder = "/test-pst-tcc"; + String baseName = "testPstTcc"; + Network network; + String eq; + try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) { + Path tmpDir = Files.createDirectory(fs.getPath(exportFolder)); + Properties exportParams = new Properties(); + exportParams.put(CgmesExport.PROFILES, "EQ"); + + // PST with FIXED_TAP + network = PhaseShifterTestCaseFactory.createWithTargetDeadband(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithoutAttribute(eq, "_PS1_PTC_RC", "_PS1_PT_T_2", "activePower"); + + // PST local with ACTIVE_POWER_CONTROL + network = PhaseShifterTestCaseFactory.createLocalActivePowerWithTargetDeadband(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_PS1_PT_T_2", "activePower"); + network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().setRegulating(true); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_PS1_PT_T_2", "activePower"); + + // PST local with CURRENT_LIMITER + network = PhaseShifterTestCaseFactory.createLocalCurrentLimiterWithTargetDeadband(); + 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(); + 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(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_LD2_EC_T_1", "activePower"); + network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().setRegulating(true); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_LD2_EC_T_1", "activePower"); + } + } + + @Test + void ratioTapChangerTapChangerControlEQTest() throws IOException { + String exportFolder = "/test-rtc-tcc"; + String baseName = "testRtcTcc"; + Network network; + String eq; + try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) { + Path tmpDir = Files.createDirectory(fs.getPath(exportFolder)); + Properties exportParams = new Properties(); + exportParams.put(CgmesExport.PROFILES, "EQ"); + + // RTC without control + network = EurostagTutorialExample1Factory.createWithoutRtcControl(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithoutAttribute(eq, "_NHV2_NLOAD_RTC_RC", "", "dummy"); + + // RTC local with VOLTAGE + network = EurostagTutorialExample1Factory.create(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(eq, "_NHV2_NLOAD_RTC_RC", "_NHV2_NLOAD_PT_T_2", "voltage"); + network.getTwoWindingsTransformer("NHV2_NLOAD").getRatioTapChanger().setRegulating(false); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(eq, "_NHV2_NLOAD_RTC_RC", "_NHV2_NLOAD_PT_T_2", "voltage"); + + // RTC local with REACTIVE_POWER + network = EurostagTutorialExample1Factory.createWithReactiveTcc(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(eq, "_NHV2_NLOAD_RTC_RC", "_NHV2_NLOAD_PT_T_2", "reactivePower"); + network.getTwoWindingsTransformer("NHV2_NLOAD").getRatioTapChanger().setRegulating(false); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(eq, "_NHV2_NLOAD_RTC_RC", "_NHV2_NLOAD_PT_T_2", "reactivePower"); + + // RTC remote with VOLTAGE + network = EurostagTutorialExample1Factory.createRemoteVoltageTcc(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(eq, "_NHV2_NLOAD_RTC_RC", "_GEN_SM_T_1", "voltage"); + network.getTwoWindingsTransformer("NHV2_NLOAD").getRatioTapChanger().setRegulating(false); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(eq, "_NHV2_NLOAD_RTC_RC", "_GEN_SM_T_1", "voltage"); + + // RTC remote with REACTIVE_POWER + network = EurostagTutorialExample1Factory.createRemoteReactiveTcc(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(eq, "_NHV2_NLOAD_RTC_RC", "_GEN_SM_T_1", "reactivePower"); + network.getTwoWindingsTransformer("NHV2_NLOAD").getRatioTapChanger().setRegulating(false); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(eq, "_NHV2_NLOAD_RTC_RC", "_GEN_SM_T_1", "reactivePower"); + + // 3w without control + network = EurostagTutorialExample1Factory.createWith3wWithoutControl(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithoutAttribute(eq, "_NGEN_V2_NHV1_RTC_RC", "", "dummy"); + + // 3w with local voltage control + network = EurostagTutorialExample1Factory.createWith3wWithVoltageControl(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(eq, "_NGEN_V2_NHV1_RTC_RC", "_NGEN_V2_NHV1_PT_T_1", "voltage"); + + // 3w with local reactive control + network = EurostagTutorialExample1Factory.create3wWithReactiveTcc(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(eq, "_NGEN_V2_NHV1_RTC_RC", "_NGEN_V2_NHV1_PT_T_1", "reactivePower"); + network.getThreeWindingsTransformer("NGEN_V2_NHV1").getLeg1().getRatioTapChanger().setRegulating(false); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(eq, "_NGEN_V2_NHV1_RTC_RC", "_NGEN_V2_NHV1_PT_T_1", "reactivePower"); + + // 3w with remote voltage + network = EurostagTutorialExample1Factory.create3wRemoteVoltageTcc(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(eq, "_NGEN_V2_NHV1_RTC_RC", "_GEN_SM_T_1", "voltage"); + network.getThreeWindingsTransformer("NGEN_V2_NHV1").getLeg1().getRatioTapChanger().setRegulating(false); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(eq, "_NGEN_V2_NHV1_RTC_RC", "_GEN_SM_T_1", "voltage"); + + // 3w with remote reactive + network = EurostagTutorialExample1Factory.create3wRemoteReactiveTcc(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(eq, "_NGEN_V2_NHV1_RTC_RC", "_GEN_SM_T_1", "reactivePower"); + network.getThreeWindingsTransformer("NGEN_V2_NHV1").getLeg1().getRatioTapChanger().setRegulating(false); + eq = getEQ(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(eq, "_NGEN_V2_NHV1_RTC_RC", "_GEN_SM_T_1", "reactivePower"); + } + } + + @Test + void staticVarCompensatorRegulatingControlEQTest() throws IOException { + String exportFolder = "/test-svc-rc"; + String baseName = "testSvcRc"; + Network network; + String eq; + try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) { + Path tmpDir = Files.createDirectory(fs.getPath(exportFolder)); + Properties exportParams = new Properties(); + exportParams.put(CgmesExport.PROFILES, "EQ"); + + // SVC VOLTAGE + // Local + network = SvcTestCaseFactory.createLocalVoltageControl(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SVC2_RC", "_SVC2_SVC_T_1", "voltage"); + + // Remote + network = SvcTestCaseFactory.createRemoteVoltageControl(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SVC2_RC", "_L2_EC_T_1", "voltage"); + + // SVC REACTIVE_POWER + // Local + network = SvcTestCaseFactory.createLocalReactiveControl(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SVC2_RC", "_SVC2_SVC_T_1", "reactivePower"); + + // Remote + network = SvcTestCaseFactory.createRemoteReactiveControl(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SVC2_RC", "_L2_EC_T_1", "reactivePower"); + + // SVC OFF + // Local + network = SvcTestCaseFactory.createLocalOffNoTarget(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRCWithoutAttribute(eq, "_SVC2_RC", "_SVC2_SVC_T_1", "dummy"); + network = SvcTestCaseFactory.createLocalOffReactiveTarget(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SVC2_RC", "_SVC2_SVC_T_1", "reactivePower"); + network = SvcTestCaseFactory.createLocalOffVoltageTarget(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SVC2_RC", "_SVC2_SVC_T_1", "voltage"); + network = SvcTestCaseFactory.createLocalOffBothTarget(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SVC2_RC", "_SVC2_SVC_T_1", "voltage"); + + // Remote + network = SvcTestCaseFactory.createRemoteOffNoTarget(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SVC2_RC", "_L2_EC_T_1", "voltage"); + network = SvcTestCaseFactory.createRemoteOffReactiveTarget(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SVC2_RC", "_L2_EC_T_1", "reactivePower"); + network = SvcTestCaseFactory.createRemoteOffVoltageTarget(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SVC2_RC", "_L2_EC_T_1", "voltage"); + network = SvcTestCaseFactory.createRemoteOffBothTarget(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SVC2_RC", "_L2_EC_T_1", "voltage"); + } + } + + @Test + void shuntCompensatorRegulatingControlEQTest() throws IOException { + String exportFolder = "/test-sc-rc"; + String baseName = "testScRc"; + Network network; + String eq; + try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) { + Path tmpDir = Files.createDirectory(fs.getPath(exportFolder)); + Properties exportParams = new Properties(); + exportParams.put(CgmesExport.PROFILES, "EQ"); + + // SC linear + network = ShuntTestCaseFactory.create(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_LOAD_EC_T_1", "voltage"); + testRcEqRCWithoutAttribute(eq, "", "", "reactivePower"); + + network = ShuntTestCaseFactory.createLocalLinear(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_SHUNT_SC_T_1", "voltage"); + testRcEqRCWithoutAttribute(eq, "", "", "reactivePower"); + + network = ShuntTestCaseFactory.createDisabledRemoteLinear(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_LOAD_EC_T_1", "voltage"); + testRcEqRCWithoutAttribute(eq, "", "", "reactivePower"); + + network = ShuntTestCaseFactory.createDisabledLocalLinear(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_SHUNT_SC_T_1", "voltage"); + testRcEqRCWithoutAttribute(eq, "", "", "reactivePower"); + + network = ShuntTestCaseFactory.createLocalLinearNoTarget(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRCWithoutAttribute(eq, "_SHUNT_RC", "", ""); + + network = ShuntTestCaseFactory.createRemoteLinearNoTarget(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_LOAD_EC_T_1", "voltage"); + testRcEqRCWithoutAttribute(eq, "", "", "reactivePower"); + + // SC nonlinear + network = ShuntTestCaseFactory.createNonLinear(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_LOAD_EC_T_1", "voltage"); + testRcEqRCWithoutAttribute(eq, "", "", "reactivePower"); + + network = ShuntTestCaseFactory.createLocalNonLinear(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_SHUNT_SC_T_1", "voltage"); + testRcEqRCWithoutAttribute(eq, "", "", "reactivePower"); + + network = ShuntTestCaseFactory.createDisabledRemoteNonLinear(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_LOAD_EC_T_1", "voltage"); + testRcEqRCWithoutAttribute(eq, "", "", "reactivePower"); + + network = ShuntTestCaseFactory.createDisabledLocalNonLinear(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_SHUNT_SC_T_1", "voltage"); + + network = ShuntTestCaseFactory.createLocalNonLinearNoTarget(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRCWithoutAttribute(eq, "_SHUNT_RC", "", ""); + + network = ShuntTestCaseFactory.createRemoteNonLinearNoTarget(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_LOAD_EC_T_1", "voltage"); + testRcEqRCWithoutAttribute(eq, "", "", "reactivePower"); + } + } + + @Test + void generatorRegulatingControlEQTest() throws IOException { + String exportFolder = "/test-gen-rc"; + String baseName = "testGenRc"; + Network network; + String eq; + try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) { + Path tmpDir = Files.createDirectory(fs.getPath(exportFolder)); + Properties exportParams = new Properties(); + exportParams.put(CgmesExport.PROFILES, "EQ"); + + // Generator local voltage + network = EurostagTutorialExample1Factory.create(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_GEN_RC", "_GEN_SM_T_1", "voltage"); + network.getGenerator("GEN").setVoltageRegulatorOn(false); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_GEN_RC", "_GEN_SM_T_1", "voltage"); + + // Generator remote voltage + network = EurostagTutorialExample1Factory.createWithRemoteVoltageGenerator(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_GEN_RC", "_NHV2_NLOAD_PT_T_1", "voltage"); + network.getGenerator("GEN").setVoltageRegulatorOn(false); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_GEN_RC", "_NHV2_NLOAD_PT_T_1", "voltage"); + + // Generator with local reactive + network = EurostagTutorialExample1Factory.createWithLocalReactiveGenerator(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_GEN_RC", "_GEN_SM_T_1", "reactivePower"); + network.getGenerator("GEN").getExtension(RemoteReactivePowerControl.class).setEnabled(false); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_GEN_RC", "_GEN_SM_T_1", "reactivePower"); + + // Generator with remote reactive + network = EurostagTutorialExample1Factory.createWithRemoteReactiveGenerator(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_GEN_RC", "_NHV2_NLOAD_PT_T_1", "reactivePower"); + network.getGenerator("GEN").getExtension(RemoteReactivePowerControl.class).setEnabled(false); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_GEN_RC", "_NHV2_NLOAD_PT_T_1", "reactivePower"); + + // Generator with local reactive and voltage + network = EurostagTutorialExample1Factory.createWithLocalReactiveAndVoltageGenerator(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_GEN_RC", "_GEN_SM_T_1", "voltage"); + network.getGenerator("GEN").setVoltageRegulatorOn(false); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_GEN_RC", "_GEN_SM_T_1", "reactivePower"); + network.getGenerator("GEN").getExtension(RemoteReactivePowerControl.class).setEnabled(false); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_GEN_RC", "_GEN_SM_T_1", "voltage"); + network.getGenerator("GEN").setVoltageRegulatorOn(true); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_GEN_RC", "_GEN_SM_T_1", "voltage"); + + // Generator with remote reactive and voltage + network = EurostagTutorialExample1Factory.createWithRemoteReactiveAndVoltageGenerators(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_GEN_RC", "_NHV2_NLOAD_PT_T_1", "voltage"); + network.getGenerator("GEN").setVoltageRegulatorOn(false); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_GEN_RC", "_NHV2_NLOAD_PT_T_1", "reactivePower"); + network.getGenerator("GEN").getExtension(RemoteReactivePowerControl.class).setEnabled(false); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_GEN_RC", "_NHV2_NLOAD_PT_T_1", "voltage"); + network.getGenerator("GEN").setVoltageRegulatorOn(true); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_GEN_RC", "_NHV2_NLOAD_PT_T_1", "voltage"); + + // Generator without control + network = EurostagTutorialExample1Factory.createWithoutControl(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_GEN_RC", "_GEN_SM_T_1", "voltage"); + + // Generator with remote terminal without control + network = EurostagTutorialExample1Factory.createRemoteWithoutControl(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(eq, "_GEN_RC", "_NHV2_NLOAD_PT_T_1", "voltage"); + + // Generator without control capability + network = EurostagTutorialExample1Factory.create(); + network.getGenerator("GEN").newMinMaxReactiveLimits().setMaxQ(0).setMinQ(0).add(); + eq = getEQ(network, baseName, tmpDir, exportParams); + testRcEqRCWithoutAttribute(eq, "_GEN_RC", "", "dummy"); + } + } + + private void testTcTccWithoutAttribute(String eq, String rcID, String terID, String rcMode) { + assertFalse(eq.contains("cim:TapChangerControl rdf:ID=\"" + rcID + "\"")); + assertFalse(eq.contains("cim:TapChanger.TapChangerControl rdf:resource=\"#" + rcID + "\"")); + assertFalse(eq.contains("RegulatingControlModeKind." + rcMode)); + assertFalse(eq.contains("cim:RegulatingControl.Terminal rdf:resource=\"#" + terID + "\"")); + } + + private void testTcTccWithAttribute(String eq, String rcID, String terID, String rcMode) { + assertTrue(eq.contains("cim:TapChangerControl rdf:ID=\"" + rcID + "\"")); + assertTrue(eq.contains("cim:TapChanger.TapChangerControl rdf:resource=\"#" + rcID + "\"")); + assertTrue(eq.contains("RegulatingControlModeKind." + rcMode)); + assertTrue(eq.contains("cim:RegulatingControl.Terminal rdf:resource=\"#" + terID + "\"")); + } + + private void testRcEqRCWithoutAttribute(String eq, String rcID, String terID, String rcMode) { + assertFalse(eq.contains("cim:RegulatingControl rdf:ID=\"" + rcID + "\"")); + assertFalse(eq.contains("cim:RegulatingCondEq.RegulatingControl rdf:resource=\"#" + rcID + "\"")); + // dummy kind is used when false assertion would trigger because other RCs are present from other equipment + assertFalse(eq.contains("RegulatingControlModeKind." + rcMode)); + assertFalse(eq.contains("cim:RegulatingControl.Terminal rdf:resource=\"#" + terID + "\"")); + } + + private void testRcEqRcWithAttribute(String eq, String rcID, String terID, String rcMode) { + assertTrue(eq.contains("cim:RegulatingControl rdf:ID=\"" + rcID + "\"")); + assertTrue(eq.contains("cim:RegulatingCondEq.RegulatingControl rdf:resource=\"#" + rcID + "\"")); + assertTrue(eq.contains("RegulatingControlModeKind." + rcMode)); + assertTrue(eq.contains("cim:RegulatingControl.Terminal rdf:resource=\"#" + terID + "\"")); + } + + private String getEQ(Network network, String baseName, Path tmpDir, Properties exportParams) throws IOException { + new CgmesExport().export(network, exportParams, new DirectoryDataSource(tmpDir, baseName)); + return Files.readString(tmpDir.resolve(baseName + "_EQ.xml")); + } + private Network createOneGeneratorNetwork() { Network network = NetworkFactory.findDefault().createNetwork("network", "test"); Substation substation1 = network.newSubstation() 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 9c69ed7d45f..bf5b4c2c7dd 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 @@ -7,6 +7,8 @@ */ package com.powsybl.cgmes.conversion.test.export; +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; import com.powsybl.cgmes.conformity.*; import com.powsybl.cgmes.conversion.CgmesExport; import com.powsybl.cgmes.conversion.CgmesImport; @@ -23,6 +25,11 @@ import com.powsybl.iidm.network.ImportConfig; import com.powsybl.iidm.network.Network; import com.powsybl.iidm.network.NetworkFactory; +import com.powsybl.iidm.network.extensions.RemoteReactivePowerControl; +import com.powsybl.iidm.network.test.EurostagTutorialExample1Factory; +import com.powsybl.iidm.network.test.PhaseShifterTestCaseFactory; +import com.powsybl.iidm.network.test.ShuntTestCaseFactory; +import com.powsybl.iidm.network.test.SvcTestCaseFactory; import com.powsybl.iidm.serde.NetworkSerDe; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; @@ -33,6 +40,7 @@ import javax.xml.stream.*; import java.io.*; import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystem; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; @@ -382,6 +390,400 @@ void miniGridCgmesExportPreservingOriginalClasses() throws IOException, XMLStrea assertTrue(ExportXmlCompare.compareSSH(expectedSsh, new ByteArrayInputStream(actualSsh.getBytes(StandardCharsets.UTF_8)), knownDiffsSsh)); } + @Test + void phaseTapChangerTapChangerControlSSHTest() throws IOException { + String exportFolder = "/test-pst-tcc"; + String baseName = "testPstTcc"; + Network network; + String ssh; + try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) { + Path tmpDir = Files.createDirectory(fs.getPath(exportFolder)); + Properties exportParams = new Properties(); + exportParams.put(CgmesExport.PROFILES, "SSH"); + + // PST with FIXED_TAP + network = PhaseShifterTestCaseFactory.createWithTargetDeadband(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithoutAttribute(ssh, "_PS1_PTC_RC", "true", "false", "10", "200", "M"); + + // PST local with ACTIVE_POWER_CONTROL + network = PhaseShifterTestCaseFactory.createLocalActivePowerWithTargetDeadband(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "false", "10", "200", "M"); + network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().setRegulating(true); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "true", "10", "200", "M"); + + // PST local with CURRENT_LIMITER + network = PhaseShifterTestCaseFactory.createLocalCurrentLimiterWithTargetDeadband(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "false", "10", "200", "none"); + network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().setRegulating(true); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "true", "10", "200", "none"); + + // PST remote with CURRENT_LIMITER + network = PhaseShifterTestCaseFactory.createRemoteCurrentLimiterWithTargetDeadband(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "false", "10", "200", "none"); + network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().setRegulating(true); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "true", "10", "200", "none"); + + // PST remote with ACTIVE_POWER_CONTROL + network = PhaseShifterTestCaseFactory.createRemoteActivePowerWithTargetDeadband(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "false", "10", "200", "M"); + network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().setRegulating(true); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_PS1_PTC_RC", "true", "true", "10", "200", "M"); + } + } + + @Test + void ratioTapChangerTapChangerControlSSHTest() throws IOException { + String exportFolder = "/test-rtc-tcc"; + String baseName = "testRtcTcc"; + Network network; + String ssh; + try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) { + Path tmpDir = Files.createDirectory(fs.getPath(exportFolder)); + Properties exportParams = new Properties(); + exportParams.put(CgmesExport.PROFILES, "SSH"); + + // RTC without control + network = EurostagTutorialExample1Factory.createWithoutRtcControl(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithoutAttribute(ssh, "_NHV2_NLOAD_RTC_RC", "", "", "", "", ""); + + // RTC local with VOLTAGE + network = EurostagTutorialExample1Factory.create(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_NHV2_NLOAD_RTC_RC", "true", "true", "0", "158", "k"); + network.getTwoWindingsTransformer("NHV2_NLOAD").getRatioTapChanger().setRegulating(false); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_NHV2_NLOAD_RTC_RC", "true", "false", "0", "158", "k"); + + // RTC local with REACTIVE_POWER + network = EurostagTutorialExample1Factory.createWithReactiveTcc(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_NHV2_NLOAD_RTC_RC", "true", "true", "0", "100", "M"); + network.getTwoWindingsTransformer("NHV2_NLOAD").getRatioTapChanger().setRegulating(false); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_NHV2_NLOAD_RTC_RC", "true", "false", "0", "100", "M"); + + // RTC remote with VOLTAGE + network = EurostagTutorialExample1Factory.createRemoteVoltageTcc(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_NHV2_NLOAD_RTC_RC", "true", "true", "0", "158", "k"); + network.getTwoWindingsTransformer("NHV2_NLOAD").getRatioTapChanger().setRegulating(false); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_NHV2_NLOAD_RTC_RC", "true", "false", "0", "158", "k"); + + // RTC remote with REACTIVE_POWER + network = EurostagTutorialExample1Factory.createRemoteReactiveTcc(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_NHV2_NLOAD_RTC_RC", "true", "true", "0", "100", "M"); + network.getTwoWindingsTransformer("NHV2_NLOAD").getRatioTapChanger().setRegulating(false); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_NHV2_NLOAD_RTC_RC", "true", "false", "0", "100", "M"); + + // 3w without control + network = EurostagTutorialExample1Factory.createWith3wWithoutControl(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithoutAttribute(ssh, "_NGEN_V2_NHV1_RTC_RC", "", "", "", "", ""); + + // 3w with local voltage control + network = EurostagTutorialExample1Factory.createWith3wWithVoltageControl(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_NGEN_V2_NHV1_RTC_RC", "true", "true", "0", "158", "k"); + + // 3w with local reactive control + network = EurostagTutorialExample1Factory.create3wWithReactiveTcc(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_NGEN_V2_NHV1_RTC_RC", "true", "true", "0", "100", "M"); + network.getThreeWindingsTransformer("NGEN_V2_NHV1").getLeg1().getRatioTapChanger().setRegulating(false); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_NGEN_V2_NHV1_RTC_RC", "true", "false", "0", "100", "M"); + + // 3w with remote voltage + network = EurostagTutorialExample1Factory.create3wRemoteVoltageTcc(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_NGEN_V2_NHV1_RTC_RC", "true", "true", "0", "158", "k"); + network.getThreeWindingsTransformer("NGEN_V2_NHV1").getLeg1().getRatioTapChanger().setRegulating(false); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_NGEN_V2_NHV1_RTC_RC", "true", "false", "0", "158", "k"); + + // 3w with remote reactive + network = EurostagTutorialExample1Factory.create3wRemoteReactiveTcc(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_NGEN_V2_NHV1_RTC_RC", "true", "true", "0", "100", "M"); + network.getThreeWindingsTransformer("NGEN_V2_NHV1").getLeg1().getRatioTapChanger().setRegulating(false); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithAttribute(ssh, "_NGEN_V2_NHV1_RTC_RC", "true", "false", "0", "100", "M"); + } + } + + @Test + void staticVarCompensatorRegulatingControlSSHTest() throws IOException { + String exportFolder = "/test-svc-rc"; + String baseName = "testSvcRc"; + Network network; + String ssh; + try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) { + Path tmpDir = Files.createDirectory(fs.getPath(exportFolder)); + Properties exportParams = new Properties(); + exportParams.put(CgmesExport.PROFILES, "SSH"); + + // SVC VOLTAGE + // Local + network = SvcTestCaseFactory.createLocalVoltageControl(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SVC2_RC", "false", "true", "0", "390", "k"); + + // Remote + network = SvcTestCaseFactory.createRemoteVoltageControl(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SVC2_RC", "false", "true", "0", "390", "k"); + + // SVC REACTIVE_POWER + // Local + network = SvcTestCaseFactory.createLocalReactiveControl(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SVC2_RC", "false", "true", "0", "350", "M"); + + // Remote + network = SvcTestCaseFactory.createRemoteReactiveControl(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SVC2_RC", "false", "true", "0", "350", "M"); + + // SVC OFF + // Local + network = SvcTestCaseFactory.createLocalOffNoTarget(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRCWithoutAttribute(ssh, "_SVC2_RC"); + network = SvcTestCaseFactory.createLocalOffReactiveTarget(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SVC2_RC", "false", "false", "0", "350", "M"); + network = SvcTestCaseFactory.createLocalOffVoltageTarget(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SVC2_RC", "false", "false", "0", "390", "k"); + network = SvcTestCaseFactory.createLocalOffBothTarget(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SVC2_RC", "false", "false", "0", "390", "k"); + + // Remote + network = SvcTestCaseFactory.createRemoteOffNoTarget(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SVC2_RC", "false", "false", "0", "0", "k"); + network = SvcTestCaseFactory.createRemoteOffReactiveTarget(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SVC2_RC", "false", "false", "0", "350", "M"); + network = SvcTestCaseFactory.createRemoteOffVoltageTarget(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SVC2_RC", "false", "false", "0", "390", "k"); + network = SvcTestCaseFactory.createRemoteOffBothTarget(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SVC2_RC", "false", "false", "0", "390", "k"); + } + } + + @Test + void shuntCompensatorRegulatingControlSSHTest() throws IOException { + String exportFolder = "/test-sc-rc"; + String baseName = "testScRc"; + Network network; + String ssh; + try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) { + Path tmpDir = Files.createDirectory(fs.getPath(exportFolder)); + Properties exportParams = new Properties(); + exportParams.put(CgmesExport.PROFILES, "SSH"); + + // SC linear + network = ShuntTestCaseFactory.create(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SHUNT_RC", "true", "true", "5", "200", "k"); + testTcTccWithoutAttribute(ssh, "", "", "", "", "", "M"); + + network = ShuntTestCaseFactory.createLocalLinear(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SHUNT_RC", "true", "true", "5", "200", "k"); + testTcTccWithoutAttribute(ssh, "", "", "", "", "", "M"); + + network = ShuntTestCaseFactory.createDisabledRemoteLinear(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SHUNT_RC", "true", "false", "5", "200", "k"); + testTcTccWithoutAttribute(ssh, "", "", "", "", "", "M"); + + network = ShuntTestCaseFactory.createDisabledLocalLinear(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SHUNT_RC", "true", "false", "5", "200", "k"); + testTcTccWithoutAttribute(ssh, "", "", "", "", "", "M"); + + network = ShuntTestCaseFactory.createLocalLinearNoTarget(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithoutAttribute(ssh, "_SHUNT_RC", "", "", "", "", ""); + + network = ShuntTestCaseFactory.createRemoteLinearNoTarget(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SHUNT_RC", "true", "false", "5", "0", "k"); + + // SC nonlinear + network = ShuntTestCaseFactory.createNonLinear(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SHUNT_RC", "true", "true", "5", "200", "k"); + testTcTccWithoutAttribute(ssh, "", "", "", "", "", "M"); + + network = ShuntTestCaseFactory.createLocalNonLinear(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SHUNT_RC", "true", "true", "5", "200", "k"); + testTcTccWithoutAttribute(ssh, "", "", "", "", "", "M"); + + network = ShuntTestCaseFactory.createDisabledRemoteNonLinear(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SHUNT_RC", "true", "false", "5", "200", "k"); + testTcTccWithoutAttribute(ssh, "", "", "", "", "", "M"); + + network = ShuntTestCaseFactory.createDisabledLocalNonLinear(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SHUNT_RC", "true", "false", "5", "200", "k"); + testTcTccWithoutAttribute(ssh, "", "", "", "", "", "M"); + + network = ShuntTestCaseFactory.createLocalNonLinearNoTarget(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testTcTccWithoutAttribute(ssh, "_SHUNT_RC", "", "", "", "", ""); + + network = ShuntTestCaseFactory.createRemoteNonLinearNoTarget(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_SHUNT_RC", "true", "false", "5", "0", "k"); + } + } + + @Test + void generatorRegulatingControlSSHTest() throws IOException { + String exportFolder = "/test-gen-rc"; + String baseName = "testGenRc"; + Network network; + String ssh; + try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) { + Path tmpDir = Files.createDirectory(fs.getPath(exportFolder)); + Properties exportParams = new Properties(); + exportParams.put(CgmesExport.PROFILES, "SSH"); + + // Generator local voltage + network = EurostagTutorialExample1Factory.create(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_GEN_RC", "false", "true", "0", "24.5", "k"); + network.getGenerator("GEN").setVoltageRegulatorOn(false); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_GEN_RC", "false", "false", "0", "24.5", "k"); + + // Generator remote voltage + network = EurostagTutorialExample1Factory.createWithRemoteVoltageGenerator(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_GEN_RC", "false", "true", "0", "24.5", "k"); + network.getGenerator("GEN").setVoltageRegulatorOn(false); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_GEN_RC", "false", "false", "0", "24.5", "k"); + + // Generator with local reactive + network = EurostagTutorialExample1Factory.createWithLocalReactiveGenerator(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_GEN_RC", "false", "true", "0", "200", "M"); + network.getGenerator("GEN").getExtension(RemoteReactivePowerControl.class).setEnabled(false); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_GEN_RC", "false", "false", "0", "200", "M"); + + // Generator with remote reactive + network = EurostagTutorialExample1Factory.createWithRemoteReactiveGenerator(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_GEN_RC", "false", "true", "0", "200", "M"); + network.getGenerator("GEN").getExtension(RemoteReactivePowerControl.class).setEnabled(false); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_GEN_RC", "false", "false", "0", "200", "M"); + + // Generator with local reactive and voltage + network = EurostagTutorialExample1Factory.createWithLocalReactiveAndVoltageGenerator(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_GEN_RC", "false", "true", "0", "24.5", "k"); + network.getGenerator("GEN").setVoltageRegulatorOn(false); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_GEN_RC", "false", "true", "0", "200", "M"); + network.getGenerator("GEN").getExtension(RemoteReactivePowerControl.class).setEnabled(false); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_GEN_RC", "false", "false", "0", "24.5", "k"); + network.getGenerator("GEN").setVoltageRegulatorOn(true); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_GEN_RC", "false", "true", "0", "24.5", "k"); + + // Generator with remote reactive and voltage + network = EurostagTutorialExample1Factory.createWithRemoteReactiveAndVoltageGenerators(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_GEN_RC", "false", "true", "0", "24.5", "k"); + network.getGenerator("GEN").setVoltageRegulatorOn(false); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_GEN_RC", "false", "true", "0", "200", "M"); + network.getGenerator("GEN").getExtension(RemoteReactivePowerControl.class).setEnabled(false); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_GEN_RC", "false", "false", "0", "24.5", "k"); + network.getGenerator("GEN").setVoltageRegulatorOn(true); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_GEN_RC", "false", "true", "0", "24.5", "k"); + + // Generator without control + network = EurostagTutorialExample1Factory.createWithoutControl(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_GEN_RC", "false", "false", "0", "0", "k"); + + // Generator with remote terminal without control + network = EurostagTutorialExample1Factory.createRemoteWithoutControl(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRcWithAttribute(ssh, "_GEN_RC", "false", "false", "0", "0", "k"); + + // Generator without control capability + network = EurostagTutorialExample1Factory.create(); + network.getGenerator("GEN").newMinMaxReactiveLimits().setMaxQ(0).setMinQ(0).add(); + ssh = getSSH(network, baseName, tmpDir, exportParams); + testRcEqRCWithoutAttribute(ssh, "_GEN_RC"); + } + } + + private void testTcTccWithoutAttribute(String ssh, String rcID, String discrete, String enabled, String deadband, String target, String multiplier) { + assertFalse(ssh.contains("cim:TapChangerControl rdf:about=\"#" + rcID + "\"")); + assertFalse(ssh.contains("" + discrete + "")); + assertFalse(ssh.contains("" + enabled + "")); + assertFalse(ssh.contains("" + deadband + "")); + assertFalse(ssh.contains("" + target + "")); + assertFalse(ssh.contains("UnitMultiplier." + multiplier + "\"")); + } + + private void testTcTccWithAttribute(String ssh, String rcID, String discrete, String enabled, String deadband, String target, String multiplier) { + assertTrue(ssh.contains("cim:TapChangerControl rdf:about=\"#" + rcID + "\"")); + assertTrue(ssh.contains("" + discrete + "")); + assertTrue(ssh.contains("" + enabled + "")); + assertTrue(ssh.contains("" + deadband + "")); + assertTrue(ssh.contains("" + target + "")); + assertTrue(ssh.contains("UnitMultiplier." + multiplier + "\"")); + } + + private void testRcEqRCWithoutAttribute(String ssh, String rcID) { + assertFalse(ssh.contains("cim:RegulatingControl rdf:about=\"#" + rcID + "\"")); + } + + private void testRcEqRcWithAttribute(String ssh, String rcID, String discrete, String enabled, String deadband, String target, String multiplier) { + assertTrue(ssh.contains("cim:RegulatingControl rdf:about=\"#" + rcID + "\"")); + assertTrue(ssh.contains("" + discrete + "")); + assertTrue(ssh.contains("" + enabled + "")); + assertTrue(ssh.contains("" + deadband + "")); + assertTrue(ssh.contains("" + target + "")); + assertTrue(ssh.contains("UnitMultiplier." + multiplier + "\"")); + } + + private String getSSH(Network network, String baseName, Path tmpDir, Properties exportParams) throws IOException { + new CgmesExport().export(network, exportParams, new DirectoryDataSource(tmpDir, baseName)); + return Files.readString(tmpDir.resolve(baseName + "_SSH.xml")); + } + private static void copyBoundary(Path outputFolder, String baseName, ReadOnlyDataSource originalDataSource) throws IOException { String eqbd = originalDataSource.listNames(".*EQ_BD.*").stream().findFirst().orElse(null); if (eqbd != null) { diff --git a/docs/grid_exchange_formats/cgmes/export.md b/docs/grid_exchange_formats/cgmes/export.md index 908702b272e..a5ca33a8773 100644 --- a/docs/grid_exchange_formats/cgmes/export.md +++ b/docs/grid_exchange_formats/cgmes/export.md @@ -178,7 +178,16 @@ Each dangling line will be exported as one `EquivalentInjection` and one `ACLine PowSyBl [`Generator`](../../grid_model/network_subnetwork.md#generator) is exported as CGMES `SynchronousMachine`. -TODO details +#### Regulating control + +If the network comes from a CIM-CGMES model and a generator has initially a `RegulatingControl`, it always has at export +too. Otherwise, a `RegulatingControl` is always exported for generators, except if it has no regulating capabilities because +$minQ = maxQ$. + +A `RegulatingControl` is exported with `RegulatingControl.mode` set to `RegulatingControlModeKind.reactivePower` when a +generator has the extension [`RemoteReactivePowerControl`](../../grid_model/extensions.md#remote-reactive-power-control) +with the `enabled` activated and the generator attribute `voltageRegulatorOn` set to `false`. In all other cases, a +`RegulatingControl` is exported with `RegulatingControl.mode` set to `RegulatingControlModeKind.voltage`. ### HVDC line and HVDC converter stations @@ -202,13 +211,32 @@ PowSyBl [`Load`](../../grid_model/network_subnetwork.md#load) is exported as `Co PowSyBl [`ShuntCompensator`](../../grid_model/network_subnetwork.md#shunt-compensator) is exported as `LinearShuntCompensator` or `NonlinearShuntCompensator` depending on their models. -TODO details +#### Regulating control + +If the network comes from a CIM-CGMES model and a shunt compensator has initially a `RegulatingControl`, it always +has at export too. + +A shunt compensator with local voltage control (i.e. the regulating terminal is the same of the terminal of connection) +and no valid voltage target will not have any exported regulating control. In all other cases, a `RegulatingControl` +is exported with `RegulatingControl.mode` set to `RegulatingControlModeKind.voltage`. ### StaticVarCompensator PowSyBl [`StaticVarCompensator`](../../grid_model/network_subnetwork.md#static-var-compensator) is exported as `StaticVarCompensator`. -TODO details +#### Regulating control + +If the network comes from a CIM-CGMES model and a static VAR compensator has initially a `RegulatingControl`, it always +has at export too. + +A static VAR compensator which voltage control is local (i.e. the regulating terminal is the same of the terminal of +connection) and no valid voltage or reactive power target will not have any exported regulating control. + +A `RegulatingControl` is exported with `RegulatingControl.mode` set to `RegulatingControlModeKind.reactivePower` when +the static VAR compensator mode is `REACTIVE_POWER`. A `RegulatingControl` is exported with `RegulatingControl.mode` set +to `RegulatingControlModeKind.voltage` when the static VAR compensator mode is `VOLTAGE`. When the static VAR compensator +is `OFF`, the exported regulating control mode will be reactive power only if the voltage target is not valid but the +reactive power target is. Otherwise, the exported mode will be voltage. ### Substation @@ -225,13 +253,28 @@ PowSyBl [`Switch`](../../grid_model/network_subnetwork.md#breakerswitch) is expo ### ThreeWindingsTransformer PowSyBl [`ThreeWindingsTransformer`](../../grid_model/network_subnetwork.md#three-windings-transformer) is exported as `PowerTransformer` with three `PowerTransformerEnds`. -TODO details + +#### Tap changer control + +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 regulation mode different of `FIXED_TAP`, 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`. ### TwoWindingsTransformer PowSyBl [`TwoWindingsTransformer`](../../grid_model/network_subnetwork.md#two-windings-transformer) is exported as `PowerTransformer` with two `PowerTransformerEnds`. -TODO details +Tap changer controls for two windings transformers are exported following the same rules explained in the previous section about three windings transformers. See [tap changer control](#tap-changer-control). ### Voltage level diff --git a/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/EurostagTutorialExample1Factory.java b/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/EurostagTutorialExample1Factory.java index 0bef269be0b..690b27e1a52 100644 --- a/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/EurostagTutorialExample1Factory.java +++ b/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/EurostagTutorialExample1Factory.java @@ -8,6 +8,7 @@ package com.powsybl.iidm.network.test; import com.powsybl.iidm.network.*; +import com.powsybl.iidm.network.extensions.RemoteReactivePowerControlAdder; import java.time.ZonedDateTime; /** @@ -31,6 +32,9 @@ public final class EurostagTutorialExample1Factory { public static final String NGEN_NHV1 = "NGEN_NHV1"; public static final String NHV2_NLOAD = "NHV2_NLOAD"; public static final String XNODE_1 = "XNODE1"; + public static final String NGEN_V2_NHV1 = "NGEN_V2_NHV1"; + public static final String NGEN = "NGEN"; + public static final String NHV1 = "NHV1"; private EurostagTutorialExample1Factory() { } @@ -74,10 +78,10 @@ public static Network create(NetworkFactory networkFactory) { .setTopologyKind(TopologyKind.BUS_BREAKER) .add(); Bus ngen = vlgen.getBusBreakerView().newBus() - .setId("NGEN") + .setId(NGEN) .add(); Bus nhv1 = vlhv1.getBusBreakerView().newBus() - .setId("NHV1") + .setId(NHV1) .add(); Bus nhv2 = vlhv2.getBusBreakerView().newBus() .setId("NHV2") @@ -220,8 +224,8 @@ public static Network createWithTieLines(NetworkFactory networkFactory) { .setX(20.0) .setG(1E-6) .setB(386E-6 / 2) - .setBus("NHV1") .setPairingKey(XNODE_1) + .setBus(NHV1) .add(); DanglingLine xnode1nhv2 = network.getVoltageLevel(VLHV2).newDanglingLine() .setId(DANGLING_LINE_XNODE1_2) @@ -247,7 +251,7 @@ public static Network createWithTieLines(NetworkFactory networkFactory) { .setX(20.0) .setG(1E-6) .setB(386E-6 / 2) - .setBus("NHV1") + .setBus(NHV1) .setPairingKey("XNODE2") .add(); DanglingLine xnode2nhv2 = network.getVoltageLevel(VLHV2).newDanglingLine() @@ -290,10 +294,10 @@ public static Network createWithLFResults(NetworkFactory factory) { Network network = create(factory); network.setCaseDate(ZonedDateTime.parse("2013-01-15T18:45:00.000+01:00")); - network.getBusBreakerView().getBus("NGEN") + network.getBusBreakerView().getBus(NGEN) .setV(24.500000610351563) .setAngle(2.3259763717651367); - network.getBusBreakerView().getBus("NHV1") + network.getBusBreakerView().getBus(NHV1) .setV(402.1428451538086) .setAngle(0.0); network.getBusBreakerView().getBus("NHV2") @@ -345,7 +349,7 @@ public static Network createWithMoreGenerators(NetworkFactory networkFactory) { Network network = create(networkFactory); VoltageLevel vlgen = network.getVoltageLevel(VLGEN); - Bus ngen = vlgen.getBusBreakerView().getBus("NGEN"); + Bus ngen = vlgen.getBusBreakerView().getBus(NGEN); Generator generator2 = vlgen.newGenerator() .setId("GEN2") @@ -429,8 +433,8 @@ public static Network createWithFixedCurrentLimits(NetworkFactory networkFactory network.getVoltageLevel(VLGEN).newGenerator() .setId("GEN2") - .setBus("NGEN") - .setConnectableBus("NGEN") + .setBus(NGEN) + .setConnectableBus(NGEN) .setMinP(-9999.99) .setMaxP(9999.99) .setVoltageRegulatorOn(true) @@ -439,7 +443,7 @@ public static Network createWithFixedCurrentLimits(NetworkFactory networkFactory .setTargetQ(301.0) .add(); - ((Bus) network.getIdentifiable("NHV1")).setV(380).getVoltageLevel().setLowVoltageLimit(400).setHighVoltageLimit(500); + ((Bus) network.getIdentifiable(NHV1)).setV(380).getVoltageLevel().setLowVoltageLimit(400).setHighVoltageLimit(500); ((Bus) network.getIdentifiable("NHV2")).setV(380).getVoltageLevel().setLowVoltageLimit(300).setHighVoltageLimit(500); Line line = network.getLine(NHV1_NHV2_1); @@ -499,8 +503,8 @@ public static Network createWithFixedLimits(NetworkFactory networkFactory) { network.getVoltageLevel(VLGEN).newGenerator() .setId("GEN2") - .setBus("NGEN") - .setConnectableBus("NGEN") + .setBus(NGEN) + .setConnectableBus(NGEN) .setMinP(-9999.99) .setMaxP(9999.99) .setVoltageRegulatorOn(true) @@ -509,7 +513,7 @@ public static Network createWithFixedLimits(NetworkFactory networkFactory) { .setTargetQ(301.0) .add(); - ((Bus) network.getIdentifiable("NHV1")).setV(380).getVoltageLevel().setLowVoltageLimit(400).setHighVoltageLimit(500); + ((Bus) network.getIdentifiable(NHV1)).setV(380).getVoltageLevel().setLowVoltageLimit(400).setHighVoltageLimit(500); ((Bus) network.getIdentifiable("NHV2")).setV(380).getVoltageLevel().setLowVoltageLimit(300).setHighVoltageLimit(500); Line line = network.getLine(NHV1_NHV2_1); @@ -604,8 +608,8 @@ public static Network createWithFixedCurrentLimitsOnDanglingLines(NetworkFactory network.getVoltageLevel(VLGEN).newGenerator() .setId("GEN2") - .setBus("NGEN") - .setConnectableBus("NGEN") + .setBus(NGEN) + .setConnectableBus(NGEN) .setMinP(-9999.99) .setMaxP(9999.99) .setVoltageRegulatorOn(true) @@ -614,7 +618,7 @@ public static Network createWithFixedCurrentLimitsOnDanglingLines(NetworkFactory .setTargetQ(301.0) .add(); - ((Bus) network.getIdentifiable("NHV1")).setV(380).getVoltageLevel().setLowVoltageLimit(400).setHighVoltageLimit(500); + ((Bus) network.getIdentifiable(NHV1)).setV(380).getVoltageLevel().setLowVoltageLimit(400).setHighVoltageLimit(500); ((Bus) network.getIdentifiable("NHV2")).setV(380).getVoltageLevel().setLowVoltageLimit(300).setHighVoltageLimit(500); DanglingLine danglingLine1 = network.getDanglingLine(DANGLING_LINE_XNODE1_1); @@ -676,8 +680,8 @@ public static Network createWithFixedLimitsOnDanglingLines(NetworkFactory networ network.getVoltageLevel(VLGEN).newGenerator() .setId("GEN2") - .setBus("NGEN") - .setConnectableBus("NGEN") + .setBus(NGEN) + .setConnectableBus(NGEN) .setMinP(-9999.99) .setMaxP(9999.99) .setVoltageRegulatorOn(true) @@ -686,7 +690,7 @@ public static Network createWithFixedLimitsOnDanglingLines(NetworkFactory networ .setTargetQ(301.0) .add(); - ((Bus) network.getIdentifiable("NHV1")).setV(380).getVoltageLevel().setLowVoltageLimit(400).setHighVoltageLimit(500); + ((Bus) network.getIdentifiable(NHV1)).setV(380).getVoltageLevel().setLowVoltageLimit(400).setHighVoltageLimit(500); ((Bus) network.getIdentifiable("NHV2")).setV(380).getVoltageLevel().setLowVoltageLimit(300).setHighVoltageLimit(500); DanglingLine danglingLine1 = network.getDanglingLine(DANGLING_LINE_XNODE1_1); @@ -923,7 +927,261 @@ public static Network createWithTieLinesAndAreas(NetworkFactory networkFactory) .addVoltageLevel(network.getVoltageLevel(VLHV2)) .addVoltageLevel(network.getVoltageLevel(VLLOAD)) .add(); + return network; + } + + public static Network createWithReactiveTcc() { + Network network = create(); + network.getTwoWindingsTransformer(NHV2_NLOAD) + .getRatioTapChanger() + .setRegulationMode(RatioTapChanger.RegulationMode.REACTIVE_POWER) + .setRegulationValue(100); + return network; + } + + public static Network createRemoteReactiveTcc() { + return createRemoteTcc(createWithReactiveTcc()); + } + + public static Network createRemoteVoltageTcc() { + return createRemoteTcc(create()); + } + + private static Network createRemoteTcc(Network network) { + network.getTwoWindingsTransformer(NHV2_NLOAD) + .getRatioTapChanger() + .setRegulationTerminal(network.getGenerator("GEN").getTerminal()); + + return network; + } + + public static Network createWithoutRtcControl() { + Network network = create(); + TwoWindingsTransformer nhv2Nload = network.getTwoWindingsTransformer(NHV2_NLOAD); + RatioTapChanger rtc = nhv2Nload.getRatioTapChanger(); + rtc.remove(); + nhv2Nload.newRatioTapChanger() + .beginStep() + .setRho(0.85f) + .setB(0.0) + .endStep() + .beginStep() + .setRho(1) + .setR(0.0) + .setX(0.0) + .setG(0.0) + .setB(0.0) + .endStep() + .beginStep() + .setRho(1.15f) + .setR(0.0) + .setX(0.0) + .setG(0.0) + .setB(0.0) + .endStep() + .setTapPosition(1) + .setLoadTapChangingCapabilities(false) + .add(); + return network; + } + + public static Network createWith3wTransformer() { + Network network = create(); + Substation p1 = network.getSubstation("P1"); + VoltageLevel v2 = p1.newVoltageLevel() + .setId("V2") + .setNominalV(150.0) + .setTopologyKind(TopologyKind.BUS_BREAKER) + .add(); + v2.getBusBreakerView().newBus() + .setId("N2") + .add(); + network.getTwoWindingsTransformer(NHV2_NLOAD).remove(); + ThreeWindingsTransformerAdder threeWindingsTransformerAdder1 = p1.newThreeWindingsTransformer() + .setId(NGEN_V2_NHV1) + .setRatedU0(400); + threeWindingsTransformerAdder1.newLeg1() + .setBus(NHV1) + .setR(0.001) + .setX(0.000001) + .setB(0) + .setG(0) + .setRatedU(400) + .setVoltageLevel(VLHV1) + .add(); + threeWindingsTransformerAdder1.newLeg2() + .setBus("N2") + .setR(0.1) + .setX(0.00001) + .setB(0) + .setG(0) + .setRatedU(150.0) + .setVoltageLevel("V2") + .add(); + threeWindingsTransformerAdder1.newLeg3() + .setBus(NGEN) + .setR(0.01) + .setX(0.0001) + .setB(0) + .setG(0) + .setRatedU(24) + .setVoltageLevel(VLGEN) + .add(); + threeWindingsTransformerAdder1.add(); + return network; + } + + public static Network createWith3wWithVoltageControl() { + Network network = createWith3wTransformer(); + add3wRtcWithVoltageControl(network); + return network; + } + + public static Network createWith3wWithoutControl() { + Network network = createWith3wTransformer(); + add3wRtcWithoutControl(network); + return network; + } + + private static void add3wRtcWithVoltageControl(Network network) { + network.getThreeWindingsTransformer(NGEN_V2_NHV1).getLeg1().newRatioTapChanger() + .beginStep() + .setRho(0.85f) + .setR(0.0) + .setX(0.0) + .setG(0.0) + .setB(0.0) + .endStep() + .beginStep() + .setRho(1.0) + .setR(0.0) + .setX(0.0) + .setG(0.0) + .setB(0.0) + .endStep() + .beginStep() + .setRho(1.15f) + .setR(0.0) + .setX(0.0) + .setG(0.0) + .setB(0.0) + .endStep() + .setTapPosition(1) + .setLoadTapChangingCapabilities(true) + .setRegulating(true) + .setRegulationMode(RatioTapChanger.RegulationMode.VOLTAGE) + .setRegulationValue(158.0) + .setTargetDeadband(0) + .setRegulationTerminal(network.getThreeWindingsTransformer(NGEN_V2_NHV1).getLeg1().getTerminal()) + .add(); + } + + private static void add3wRtcWithoutControl(Network network) { + network.getThreeWindingsTransformer(NGEN_V2_NHV1).getLeg1().newRatioTapChanger() + .beginStep() + .setRho(0.85f) + .setR(0.0) + .setX(0.0) + .setG(0.0) + .setB(0.0) + .endStep() + .beginStep() + .setRho(1.0) + .setR(0.0) + .setX(0.0) + .setG(0.0) + .setB(0.0) + .endStep() + .beginStep() + .setRho(1.15f) + .setR(0.0) + .setX(0.0) + .setG(0.0) + .setB(0.0) + .endStep() + .setTapPosition(1) + .setLoadTapChangingCapabilities(false) + .add(); + } + + public static Network create3wWithReactiveTcc() { + Network network = createWith3wWithVoltageControl(); + network.getThreeWindingsTransformer(NGEN_V2_NHV1).getLeg1() + .getRatioTapChanger() + .setRegulationMode(RatioTapChanger.RegulationMode.REACTIVE_POWER) + .setRegulationValue(100); + return network; + } + + private static Network create3wRemoteTcc(Network network) { + network.getThreeWindingsTransformer(NGEN_V2_NHV1).getLeg1() + .getRatioTapChanger() + .setRegulationTerminal(network.getGenerator("GEN").getTerminal()); + return network; + } + + public static Network create3wRemoteReactiveTcc() { + return create3wRemoteTcc(create3wWithReactiveTcc()); + } + + public static Network create3wRemoteVoltageTcc() { + return create3wRemoteTcc(createWith3wWithVoltageControl()); + } + + public static Network createWithRemoteVoltageGenerator() { + return addRemoteVoltageGenerator(create()); + } + + public static Network createWithRemoteReactiveGenerator() { + return removeVoltageControlForGenerator(addRemoteReactiveGenerator(create())); + } + + public static Network createWithLocalReactiveGenerator() { + return removeVoltageControlForGenerator(addLocalReactiveGenerator(create())); + } + + public static Network createWithRemoteReactiveAndVoltageGenerators() { + return addRemoteVoltageGenerator(addRemoteReactiveGenerator(create())); + } + + public static Network createWithLocalReactiveAndVoltageGenerator() { + return addLocalReactiveGenerator(create()); + } + + public static Network createWithoutControl() { + return removeVoltageControlForGenerator(create()); + } + + public static Network createRemoteWithoutControl() { + return removeVoltageControlForGenerator(createWithRemoteVoltageGenerator()); + } + + private static Network addLocalReactiveGenerator(Network network) { + return addReactiveGenerator(network, network.getGenerator("GEN").getRegulatingTerminal()); + } + + private static Network addRemoteReactiveGenerator(Network network) { + return addReactiveGenerator(network, network.getTwoWindingsTransformer(NHV2_NLOAD).getTerminal1()); + } + + private static Network addReactiveGenerator(Network network, Terminal terminal) { + network.getGenerator("GEN").newExtension(RemoteReactivePowerControlAdder.class) + .withRegulatingTerminal(terminal) + .withTargetQ(200) + .withEnabled(true).add(); + return network; + } + + private static Network addRemoteVoltageGenerator(Network network) { + network.getGenerator("GEN") + .setRegulatingTerminal(network.getTwoWindingsTransformer(NHV2_NLOAD).getTerminal1()); + return network; + } + private static Network removeVoltageControlForGenerator(Network network) { + Generator gen = network.getGenerator("GEN"); + gen.setVoltageRegulatorOn(false); + gen.setTargetV(Double.NaN); return network; } } diff --git a/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/PhaseShifterTestCaseFactory.java b/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/PhaseShifterTestCaseFactory.java index c35769e0752..f51872ef3a7 100644 --- a/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/PhaseShifterTestCaseFactory.java +++ b/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/PhaseShifterTestCaseFactory.java @@ -183,4 +183,35 @@ public static Network createWithTargetDeadband() { .setTargetDeadband(10.0); return network; } + + public static Network createLocalActivePowerWithTargetDeadband() { + Network network = createWithTargetDeadband(); + network.getTwoWindingsTransformer("PS1") + .getPhaseTapChanger() + .setRegulationMode(PhaseTapChanger.RegulationMode.ACTIVE_POWER_CONTROL); + return network; + } + + public static Network createLocalCurrentLimiterWithTargetDeadband() { + Network network = createWithTargetDeadband(); + network.getTwoWindingsTransformer("PS1") + .getPhaseTapChanger() + .setRegulationMode(PhaseTapChanger.RegulationMode.CURRENT_LIMITER); + return network; + } + + public static Network createRemoteActivePowerWithTargetDeadband() { + return createRemote(createLocalActivePowerWithTargetDeadband()); + } + + public static Network createRemoteCurrentLimiterWithTargetDeadband() { + return createRemote(createLocalCurrentLimiterWithTargetDeadband()); + } + + private static Network createRemote(Network network) { + network.getTwoWindingsTransformer("PS1") + .getPhaseTapChanger() + .setRegulationTerminal(network.getLoad("LD2").getTerminal()); + return network; + } } diff --git a/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/ShuntTestCaseFactory.java b/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/ShuntTestCaseFactory.java index dbde19a85f9..5793c6e837d 100644 --- a/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/ShuntTestCaseFactory.java +++ b/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/ShuntTestCaseFactory.java @@ -141,4 +141,63 @@ private static Network createBase(NetworkFactory networkFactory) { .add(); return network; } + + public static Network createLocalLinear() { + return createLocalShunt(create()); + } + + public static Network createLocalShunt(Network network) { + network.getShuntCompensator(SHUNT) + .setRegulatingTerminal(network.getShuntCompensator(SHUNT).getTerminal()); + return network; + } + + public static Network createDisabledRemoteLinear() { + return createDisabledShunt(create()); + } + + public static Network createDisabledLocalLinear() { + return createDisabledShunt(createLocalLinear()); + } + + public static Network createDisabledRemoteNonLinear() { + return createDisabledShunt(createNonLinear()); + } + + public static Network createDisabledLocalNonLinear() { + return createDisabledShunt(createLocalNonLinear()); + } + + public static Network createDisabledShunt(Network network) { + network.getShuntCompensator(SHUNT) + .setVoltageRegulatorOn(false); + return network; + } + + private static Network createShuntWithNoTarget(Network network) { + network.getShuntCompensator(SHUNT) + .setVoltageRegulatorOn(false) + .setTargetV(Double.NaN); + return network; + } + + public static Network createRemoteLinearNoTarget() { + return createShuntWithNoTarget(create()); + } + + public static Network createRemoteNonLinearNoTarget() { + return createShuntWithNoTarget(createNonLinear()); + } + + public static Network createLocalLinearNoTarget() { + return createShuntWithNoTarget(createLocalLinear()); + } + + public static Network createLocalNonLinearNoTarget() { + return createShuntWithNoTarget(createLocalNonLinear()); + } + + public static Network createLocalNonLinear() { + return createLocalShunt(createNonLinear()); + } } diff --git a/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/SvcTestCaseFactory.java b/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/SvcTestCaseFactory.java index 23c29b1d070..7e1edab8857 100644 --- a/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/SvcTestCaseFactory.java +++ b/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/SvcTestCaseFactory.java @@ -140,4 +140,125 @@ public static Network createWithRemoteRegulatingTerminal(NetworkFactory networkF return network; } + + private static Network addReactiveTarget(Network network) { + network.getStaticVarCompensator("SVC2") + .setReactivePowerSetpoint(350); + return network; + } + + private static Network addVoltageTarget(Network network) { + network.getStaticVarCompensator("SVC2") + .setVoltageSetpoint(390); + return network; + } + + private static Network addBothTarget(Network network) { + network.getStaticVarCompensator("SVC2") + .setReactivePowerSetpoint(350) + .setVoltageSetpoint(390); + return network; + } + + private static Network createLocalVoltageControl(Network network) { + return addVoltageControl(network); + } + + public static Network createLocalVoltageControl() { + return createLocalVoltageControl(create()); + } + + public static Network createRemoteVoltageControl() { + return createLocalVoltageControl(createWithRemoteRegulatingTerminal()); + } + + private static Network addVoltageControl(Network network) { + addVoltageTarget(network); + network.getStaticVarCompensator("SVC2") + .setRegulationMode(StaticVarCompensator.RegulationMode.VOLTAGE); + return network; + } + + private static Network createReactiveControl(Network network) { + return addReactiveControl(network); + } + + public static Network createLocalReactiveControl() { + return createReactiveControl(create()); + } + + public static Network createRemoteReactiveControl() { + return createReactiveControl(createWithRemoteRegulatingTerminal()); + } + + private static Network addReactiveControl(Network network) { + addReactiveTarget(network); + network.getStaticVarCompensator("SVC2") + .setRegulationMode(StaticVarCompensator.RegulationMode.REACTIVE_POWER); + return network; + } + + public static Network createLocalOffReactiveTarget() { + return createOffReactiveTarget(create()); + } + + public static Network createRemoteOffReactiveTarget() { + return createOffReactiveTarget(createWithRemoteRegulatingTerminal()); + } + + private static Network createOffReactiveTarget(Network network) { + return addOffReactiveTarget(network); + } + + private static Network addOffReactiveTarget(Network network) { + return addReactiveTarget(addOffNoTarget(network)); + } + + public static Network createLocalOffVoltageTarget() { + return createOffVoltageTarget(create()); + } + + public static Network createRemoteOffVoltageTarget() { + return createOffVoltageTarget(createWithRemoteRegulatingTerminal()); + } + + private static Network createOffVoltageTarget(Network network) { + return addOffVoltageTarget(network); + } + + private static Network addOffVoltageTarget(Network network) { + return addVoltageTarget(addOffNoTarget(network)); + } + + public static Network createLocalOffBothTarget() { + return createOffBothTarget(create()); + } + + public static Network createRemoteOffBothTarget() { + return createOffBothTarget(createWithRemoteRegulatingTerminal()); + } + + private static Network createOffBothTarget(Network network) { + return addOffBothTarget(network); + } + + private static Network addOffBothTarget(Network network) { + return addBothTarget(addOffNoTarget(network)); + } + + public static Network createLocalOffNoTarget() { + return addOffNoTarget(create()); + } + + public static Network createRemoteOffNoTarget() { + return addOffNoTarget(createWithRemoteRegulatingTerminal()); + } + + private static Network addOffNoTarget(Network network) { + network.getStaticVarCompensator("SVC2") + .setRegulationMode(StaticVarCompensator.RegulationMode.OFF) + .setVoltageSetpoint(Double.NaN) + .setReactivePowerSetpoint(Double.NaN); + return network; + } }