From c2ece3e5cd16ee782f5bfb1b8e52a2b00558f4f8 Mon Sep 17 00:00:00 2001 From: EtienneLt <32468651+EtienneLt@users.noreply.github.com> Date: Fri, 25 Oct 2024 10:48:09 +0200 Subject: [PATCH] adjusting regulating when modifying phase tap changer (#537) Signed-off-by: Etienne LESOT Co-authored-by: Thang PHAM <117309322+thangqp@users.noreply.github.com> --- .../TwoWindingsTransformerField.java | 5 +- .../modifications/ModificationUtils.java | 16 +- .../TwoWindingsTransformerModification.java | 169 +++++-- ...woWindingsTransformerModificationTest.java | 445 +++++++++++++++++- 4 files changed, 566 insertions(+), 69 deletions(-) diff --git a/src/main/java/org/gridsuite/modification/server/dto/byfilter/equipmentfield/TwoWindingsTransformerField.java b/src/main/java/org/gridsuite/modification/server/dto/byfilter/equipmentfield/TwoWindingsTransformerField.java index 78d35d9bd..3294d4540 100644 --- a/src/main/java/org/gridsuite/modification/server/dto/byfilter/equipmentfield/TwoWindingsTransformerField.java +++ b/src/main/java/org/gridsuite/modification/server/dto/byfilter/equipmentfield/TwoWindingsTransformerField.java @@ -63,7 +63,6 @@ public static void setNewValue(TwoWindingsTransformer transformer, String twoWin TwoWindingsTransformerField field = TwoWindingsTransformerField.valueOf(twoWindingsTransformerField); final PhaseTapChanger phaseTapChanger = transformer.getPhaseTapChanger(); final RatioTapChanger ratioTapChanger = transformer.getRatioTapChanger(); - final PhaseTapChanger.RegulationMode regulationMode = phaseTapChanger != null ? phaseTapChanger.getRegulationMode() : null; final AttributeModification attributeModification = new AttributeModification<>(Double.parseDouble(newValue), OperationType.SET); switch (field) { @@ -81,13 +80,13 @@ public static void setNewValue(TwoWindingsTransformer transformer, String twoWin null, new AttributeModification<>((int) Double.parseDouble(newValue), OperationType.SET), null, null); case RATIO_TARGET_DEADBAND -> modifyTargets(ratioTapChanger, null, true, null, attributeModification, null); case REGULATION_VALUE -> processPhaseTapRegulation( - phaseTapChanger, null, regulationMode, true, attributeModification, null, null); + phaseTapChanger, null, true, null, attributeModification, null, null); case PHASE_LOW_TAP_POSITION -> processTapChangerPositionsAndSteps(phaseTapChanger, null, true, new AttributeModification<>((int) Double.parseDouble(newValue), OperationType.SET), null, null, null); case PHASE_TAP_POSITION -> processTapChangerPositionsAndSteps(phaseTapChanger, null, true, null, new AttributeModification<>((int) Double.parseDouble(newValue), OperationType.SET), null, null); case PHASE_TARGET_DEADBAND -> processPhaseTapRegulation( - phaseTapChanger, null, null, true, null, attributeModification, null + phaseTapChanger, null, true, null, null, attributeModification, null ); } } diff --git a/src/main/java/org/gridsuite/modification/server/modifications/ModificationUtils.java b/src/main/java/org/gridsuite/modification/server/modifications/ModificationUtils.java index 534d31b5b..aba88cb4c 100644 --- a/src/main/java/org/gridsuite/modification/server/modifications/ModificationUtils.java +++ b/src/main/java/org/gridsuite/modification/server/modifications/ModificationUtils.java @@ -1007,17 +1007,11 @@ public void reportElementaryCreation(ReportNode subReportNode, T value, Stri } public String formatRegulationModeReport(PhaseTapChanger.RegulationMode regulationMode) { - switch (regulationMode) { - case FIXED_TAP: - return " Fixed tap"; - case CURRENT_LIMITER : - return " Current limiter"; - case ACTIVE_POWER_CONTROL : - return " Active power control"; - default : - return ""; - - } + return switch (regulationMode) { + case FIXED_TAP -> " Fixed tap"; + case CURRENT_LIMITER -> " Current limiter"; + case ACTIVE_POWER_CONTROL -> " Active power control"; + }; } public void modifyReactiveCapabilityCurvePoints(Collection points, diff --git a/src/main/java/org/gridsuite/modification/server/modifications/TwoWindingsTransformerModification.java b/src/main/java/org/gridsuite/modification/server/modifications/TwoWindingsTransformerModification.java index 5fee968aa..e1ab603d6 100644 --- a/src/main/java/org/gridsuite/modification/server/modifications/TwoWindingsTransformerModification.java +++ b/src/main/java/org/gridsuite/modification/server/modifications/TwoWindingsTransformerModification.java @@ -16,7 +16,7 @@ import java.util.ArrayList; import java.util.List; -import static org.gridsuite.modification.server.NetworkModificationException.Type.TWO_WINDINGS_TRANSFORMER_NOT_FOUND; +import static org.gridsuite.modification.server.NetworkModificationException.Type.*; import static org.gridsuite.modification.server.modifications.ModificationUtils.insertReportNode; /** @@ -198,26 +198,10 @@ private void processPhaseTapChanger(Network network, PhaseTapChangerAdder phaseTapChangerAdder = isModification ? null : twt.newPhaseTapChanger(); PhaseTapChangerModificationInfos phaseTapChangerInfos = twoWindingsTransformerModificationInfos .getPhaseTapChanger(); - - List phaseTapChangerReports = new ArrayList<>(); - ReportNode regulationModeReport = ModificationUtils.getInstance().applyElementaryModificationsAndReturnReport( - isModification ? phaseTapChanger::setRegulationMode : phaseTapChangerAdder::setRegulationMode, - isModification ? phaseTapChanger::getRegulationMode : () -> null, - phaseTapChangerInfos.getRegulationMode(), "Regulation mode", 1); - if (regulationModeReport != null) { - phaseTapChangerReports.add(regulationModeReport); - } - List regulationReports = new ArrayList<>(); - PhaseTapChanger.RegulationMode regulationMode = isModification ? phaseTapChanger.getRegulationMode() : null; - if (phaseTapChangerInfos.getRegulationMode() != null - && phaseTapChangerInfos.getRegulationMode().getValue() != null) { - regulationMode = phaseTapChangerInfos.getRegulationMode().getValue(); - } - if (!PhaseTapChanger.RegulationMode.FIXED_TAP.equals(regulationMode)) { - processPhaseTapRegulation(phaseTapChanger, phaseTapChangerAdder, regulationMode, isModification, phaseTapChangerInfos.getRegulationValue(), phaseTapChangerInfos.getTargetDeadband(), regulationReports - ); - } + + processPhaseTapRegulation(phaseTapChanger, phaseTapChangerAdder, isModification, phaseTapChangerInfos.getRegulationMode(), + phaseTapChangerInfos.getRegulationValue(), phaseTapChangerInfos.getTargetDeadband(), regulationReports); processRegulatingTerminal(phaseTapChangerInfos, phaseTapChanger, phaseTapChangerAdder, regulationReports, network, @@ -230,19 +214,15 @@ private void processPhaseTapChanger(Network network, phaseTapChangerAdder.add(); } - if (!phaseTapChangerReports.isEmpty() || !regulationReports.isEmpty() || !positionsAndStepsReports.isEmpty()) { + if (!regulationReports.isEmpty() || !positionsAndStepsReports.isEmpty()) { ReportNode phaseTapChangerSubreporter = ModificationUtils.getInstance().reportModifications(subReportNode, - phaseTapChangerReports, TapChangerType.PHASE.name(), PHASE_TAP_CHANGER_SUBREPORTER_DEFAULT_MESSAGE + regulationReports, TapChangerType.PHASE.name(), PHASE_TAP_CHANGER_SUBREPORTER_DEFAULT_MESSAGE ); if (phaseTapChangerSubreporter == null) { phaseTapChangerSubreporter = subReportNode.newReportNode() .withMessageTemplate(TapChangerType.PHASE.name(), PHASE_TAP_CHANGER_SUBREPORTER_DEFAULT_MESSAGE) .add(); } - ModificationUtils.getInstance().reportModifications(phaseTapChangerSubreporter, regulationReports, - regulationMode != null ? regulationMode.name() : null, - ModificationUtils.getInstance().formatRegulationModeReport(regulationMode) - ); ModificationUtils.getInstance().reportModifications(phaseTapChangerSubreporter, positionsAndStepsReports, "phaseTapChangerPositionsAndStepsModification", " Tap Changer"); } @@ -250,40 +230,127 @@ private void processPhaseTapChanger(Network network, public static void processPhaseTapRegulation(PhaseTapChanger phaseTapChanger, PhaseTapChangerAdder phaseTapChangerAdder, - PhaseTapChanger.RegulationMode regulationMode, boolean isModification, - AttributeModification modifyRegulationValue, - AttributeModification modifyTargetDeadband, - List regulationReports) { - - if (regulationMode != null) { - String fieldName = (regulationMode.equals(PhaseTapChanger.RegulationMode.CURRENT_LIMITER)) ? "Value" : "Flow set point"; - ReportNode regulationValueReportNode = ModificationUtils.getInstance().applyElementaryModificationsAndReturnReport( - isModification ? phaseTapChanger::setRegulationValue - : phaseTapChangerAdder::setRegulationValue, - isModification ? phaseTapChanger::getRegulationValue : () -> null, - modifyRegulationValue, - fieldName, - 2); - if (regulationReports != null && regulationValueReportNode != null) { - regulationReports.add(regulationValueReportNode); + AttributeModification regulationModeModification, + AttributeModification regulationValueModification, + AttributeModification targetDeadbandModification, + List regulationReports) throws NetworkModificationException { + AttributeModification finalRegulationModeModification = regulationModeModification; + AttributeModification finalTargetDeadbandModification = targetDeadbandModification; + AttributeModification finalRegulatingModification = null; + + // --- Regulation Mode impacts on regulating => pre-processing regulating --- // + if (isModification) { // modifying an existing extension + // modification check + if (regulationModeModification != null) { + PhaseTapChanger.RegulationMode oldRegulationMode = phaseTapChanger.getRegulationMode(); + PhaseTapChanger.RegulationMode newRegulationMode = regulationModeModification.getValue(); + double oldTargetDeadBand = phaseTapChanger.getTargetDeadband(); + + if (oldRegulationMode == PhaseTapChanger.RegulationMode.FIXED_TAP) { + // if new regulation mode is FIXED_TAP set regulating to false + if (newRegulationMode == PhaseTapChanger.RegulationMode.FIXED_TAP) { + finalRegulatingModification = AttributeModification.toAttributeModification(false, OperationType.SET); + } else { // new regulation mode is CURRENT_LIMITER or ACTIVE_POWER_CONTROL + // check required field + if (regulationValueModification == null) { + throw new NetworkModificationException(MODIFY_TWO_WINDINGS_TRANSFORMER_ERROR, "Regulation value is missing, phase tap changer can not regulate"); + } + + // set regulating to true + finalRegulatingModification = AttributeModification.toAttributeModification(true, OperationType.SET); + + // set default value for deadband + if (Double.isNaN(oldTargetDeadBand) && targetDeadbandModification == null) { + finalTargetDeadbandModification = AttributeModification.toAttributeModification(0.0, OperationType.SET); + } + } + } else { // previous regulation mode is CURRENT_LIMITER or ACTIVE_POWER_CONTROL + // if new regulation mode is FIXED_TAP we keep the old regulation mode and set regulating to false + if (newRegulationMode == PhaseTapChanger.RegulationMode.FIXED_TAP) { + finalRegulatingModification = AttributeModification.toAttributeModification(false, OperationType.SET); + finalRegulationModeModification = AttributeModification.toAttributeModification(oldRegulationMode, OperationType.SET); + } else { // new regulation mode is CURRENT_LIMITER or ACTIVE_POWER_CONTROL + // set regulating to true + finalRegulatingModification = AttributeModification.toAttributeModification(true, OperationType.SET); + // set default value for deadband + if (Double.isNaN(oldTargetDeadBand) && targetDeadbandModification == null) { + finalTargetDeadbandModification = AttributeModification.toAttributeModification(0.0, OperationType.SET); + } + } + } + } + } else { + // creation check + if (regulationModeModification == null) { + throw new NetworkModificationException(CREATE_TWO_WINDINGS_TRANSFORMER_ERROR, "Regulation mode is missing when creating tap phase changer"); + } + + PhaseTapChanger.RegulationMode regulationMode = regulationModeModification.getValue(); + if (regulationMode != PhaseTapChanger.RegulationMode.FIXED_TAP) { + finalRegulatingModification = AttributeModification.toAttributeModification(true, OperationType.SET); + if (regulationValueModification == null) { + throw new NetworkModificationException(CREATE_TWO_WINDINGS_TRANSFORMER_ERROR, + "Regulation value is missing when creating tap phase changer with regulation enabled (different from FIXED_TAP)"); + } + if (finalTargetDeadbandModification == null) { + finalTargetDeadbandModification = AttributeModification.toAttributeModification(0.0, OperationType.SET); + } + } else { + finalRegulatingModification = AttributeModification.toAttributeModification(false, OperationType.SET); } } + //c--- apply changes after pre-processing of regulating --- // + setPhaseTapChangerRegulationAttributes(phaseTapChanger, phaseTapChangerAdder, isModification, + finalRegulationModeModification, regulationValueModification, finalTargetDeadbandModification, finalRegulatingModification, regulationReports); + + } + + private static void setPhaseTapChangerRegulationAttributes(PhaseTapChanger phaseTapChanger, + PhaseTapChangerAdder phaseTapChangerAdder, + boolean isModification, + AttributeModification regulationModeModification, + AttributeModification regulationValueModification, + AttributeModification targetDeadbandModification, + AttributeModification regulatingModification, + List regulationReports) { + // the order is important if regulation mode is set and regulation value or target dead band is null it will crash + PhaseTapChanger.RegulationMode regulationMode = regulationModeModification == null ? null : regulationModeModification.getValue(); + String fieldName = (regulationMode == PhaseTapChanger.RegulationMode.CURRENT_LIMITER) ? "Value" : "Flow set point"; + // Regulation value + ReportNode regulationValueReportNode = ModificationUtils.getInstance().applyElementaryModificationsAndReturnReport( + isModification ? phaseTapChanger::setRegulationValue : phaseTapChangerAdder::setRegulationValue, + isModification ? phaseTapChanger::getRegulationValue : () -> null, + regulationValueModification, fieldName, 1); + if (regulationReports != null && regulationValueReportNode != null) { + regulationReports.add(regulationValueReportNode); + } + // targetDeadBand ReportNode targetDeadbandReportNode = ModificationUtils.getInstance().applyElementaryModificationsAndReturnReport( - isModification ? phaseTapChanger::setTargetDeadband - : phaseTapChangerAdder::setTargetDeadband, - isModification ? phaseTapChanger::getTargetDeadband : () -> null, - modifyTargetDeadband, "Target deadband", 2); - + isModification ? phaseTapChanger::setTargetDeadband : phaseTapChangerAdder::setTargetDeadband, + isModification ? phaseTapChanger::getTargetDeadband : () -> null, + targetDeadbandModification, "Target deadband", 1); if (regulationReports != null && targetDeadbandReportNode != null) { regulationReports.add(targetDeadbandReportNode); } - if (isModification) { - phaseTapChanger.setRegulating(true); - } else { - phaseTapChangerAdder.setRegulating(true); + // RegulationMode + ReportNode regulationReportNode = ModificationUtils.getInstance().applyElementaryModificationsAndReturnReport( + isModification ? phaseTapChanger::setRegulationMode : phaseTapChangerAdder::setRegulationMode, + isModification ? phaseTapChanger::getRegulationMode : () -> null, + regulationModeModification, "Regulation mode", 1); + if (regulationReports != null && regulationReportNode != null) { + regulationReports.add(regulationReportNode); + } + + // Regulating + ReportNode regulatingReportNode = ModificationUtils.getInstance().applyElementaryModificationsAndReturnReport( + isModification ? phaseTapChanger::setRegulating : phaseTapChangerAdder::setRegulating, + isModification ? phaseTapChanger::isRegulating : () -> null, + regulatingModification, "Phase tap regulating", 1); + if (regulationReports != null && regulatingReportNode != null) { + regulationReports.add(regulatingReportNode); } } diff --git a/src/test/java/org/gridsuite/modification/server/modifications/TwoWindingsTransformerModificationTest.java b/src/test/java/org/gridsuite/modification/server/modifications/TwoWindingsTransformerModificationTest.java index a4e5ff367..d11ce3fc8 100644 --- a/src/test/java/org/gridsuite/modification/server/modifications/TwoWindingsTransformerModificationTest.java +++ b/src/test/java/org/gridsuite/modification/server/modifications/TwoWindingsTransformerModificationTest.java @@ -8,6 +8,14 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.powsybl.iidm.network.*; +import com.powsybl.iidm.network.LoadingLimits; +import com.powsybl.iidm.network.Network; +import com.powsybl.iidm.network.PhaseTapChanger; +import com.powsybl.iidm.network.Terminal; +import com.powsybl.iidm.network.TwoSides; +import com.powsybl.iidm.network.TwoWindingsTransformer; + +import com.powsybl.commons.report.ReportNode; import com.powsybl.iidm.network.extensions.ConnectablePosition; import org.gridsuite.modification.server.NetworkModificationException; import org.gridsuite.modification.server.dto.*; @@ -19,7 +27,10 @@ import java.util.*; +import static org.gridsuite.modification.server.NetworkModificationException.Type.MODIFY_TWO_WINDINGS_TRANSFORMER_ERROR; import static org.gridsuite.modification.server.NetworkModificationException.Type.TWO_WINDINGS_TRANSFORMER_NOT_FOUND; +import static org.gridsuite.modification.server.modifications.TwoWindingsTransformerModification.processPhaseTapRegulation; +import static org.gridsuite.modification.server.utils.NetworkUtil.createTwoWindingsTransformer; import static org.gridsuite.modification.server.utils.TestUtils.assertLogMessage; import static org.gridsuite.modification.server.utils.assertions.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; @@ -426,10 +437,10 @@ void testPhaseTapChangerModification() throws Exception { .ratioTapChanger(RatioTapChangerModificationInfos.builder() .build()) .phaseTapChanger(PhaseTapChangerModificationInfos.builder() - .enabled(new AttributeModification(true, OperationType.SET)) - .regulationMode(new AttributeModification(PhaseTapChanger.RegulationMode.CURRENT_LIMITER, OperationType.SET)) - .regulationValue(new AttributeModification(100.0, OperationType.SET)) - .targetDeadband(new AttributeModification(10.0, OperationType.SET)) + .enabled(new AttributeModification<>(true, OperationType.SET)) + .regulationMode(new AttributeModification<>(PhaseTapChanger.RegulationMode.CURRENT_LIMITER, OperationType.SET)) + .regulationValue(new AttributeModification<>(100.0, OperationType.SET)) + .targetDeadband(new AttributeModification<>(10.0, OperationType.SET)) .build()) .build(); @@ -564,6 +575,215 @@ void testPhaseTapChangerModification() throws Exception { } + private TwoWindingsTransformer createPhaseTapChanger() { + return createPhaseTapChanger(PhaseTapChanger.RegulationMode.FIXED_TAP); + } + + private TwoWindingsTransformer createPhaseTapChanger(PhaseTapChanger.RegulationMode regulationMode) { + TwoWindingsTransformer twt3 = createTwoWindingsTransformer(getNetwork().getSubstation("s1"), "trf3", "trf3", 2.0, 14.745, 0.0, 3.2E-5, 400.0, 225.0, + 41, 151, getNetwork().getVoltageLevel("v1").getId(), getNetwork().getVoltageLevel("v2").getId(), + "trf3", 1, ConnectablePosition.Direction.TOP, + "trf3", 2, ConnectablePosition.Direction.TOP); + Terminal phaseTapChangerTerminal = ModificationUtils.getInstance().getTerminalFromIdentifiable(getNetwork(), + "v3load", + "LOAD", + "V3"); + twt3.newPhaseTapChanger() + .setLowTapPosition(0) + .setTapPosition(1) + .setRegulationTerminal(phaseTapChangerTerminal) + .setRegulationMode(regulationMode) + .beginStep() + .setR(39.78473) + .setX(39.784725) + .setG(0.0) + .setB(0.0) + .setRho(1.0) + .setAlpha(1.) + .endStep() + .beginStep() + .setR(39.78475) + .setX(39.784727) + .setG(0.0) + .setB(0.0) + .setRho(1.0) + .setAlpha(1.1) + .endStep() + .add(); + return twt3; + } + + @Test + void testPhaseTapChangerRegulationModification() throws Exception { + TwoWindingsTransformer twt3 = createPhaseTapChanger(); + String twtId = "trf3"; + // modification 1 : FIXED_TAP -> CURRENT_LIMITER + TwoWindingsTransformerModificationInfos phaseTapChangerCreation = TwoWindingsTransformerModificationInfos.builder() + .stashed(false) + .equipmentId(twtId) + .ratioTapChanger(RatioTapChangerModificationInfos.builder() + .build()) + .phaseTapChanger(PhaseTapChangerModificationInfos.builder() + .enabled(new AttributeModification<>(true, OperationType.SET)) + .regulationMode(new AttributeModification<>(PhaseTapChanger.RegulationMode.CURRENT_LIMITER, OperationType.SET)) + .regulationValue(new AttributeModification<>(10.0, OperationType.SET)) + .build()) + .build(); + + String modificationToModifyJson = mapper.writeValueAsString(phaseTapChangerCreation); + mockMvc.perform(post(getNetworkModificationUri()).content(modificationToModifyJson).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + + PhaseTapChanger phaseTapChanger = twt3.getPhaseTapChanger(); + + // modification 1 assert + assertEquals(PhaseTapChanger.RegulationMode.CURRENT_LIMITER, phaseTapChanger.getRegulationMode()); + assertTrue(phaseTapChanger.isRegulating()); + assertEquals(0.0, phaseTapChanger.getTargetDeadband()); + assertEquals(10.0, phaseTapChanger.getRegulationValue()); + + // modification 2 : CURRENT_LIMITER -> FIXED_TAP + phaseTapChangerCreation.getPhaseTapChanger().setRegulationMode(new AttributeModification<>(PhaseTapChanger.RegulationMode.FIXED_TAP, OperationType.SET)); + phaseTapChangerCreation.getPhaseTapChanger().setRegulationValue(null); + + String modificationToModifyJson2 = mapper.writeValueAsString(phaseTapChangerCreation); + mockMvc.perform(post(getNetworkModificationUri()).content(modificationToModifyJson2).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + phaseTapChanger = getNetwork().getTwoWindingsTransformer(twtId).getPhaseTapChanger(); + + // modification 2 assert + assertEquals(PhaseTapChanger.RegulationMode.CURRENT_LIMITER, phaseTapChanger.getRegulationMode()); + assertEquals(0.0, phaseTapChanger.getTargetDeadband()); + assertEquals(10.0, phaseTapChanger.getRegulationValue()); + assertFalse(phaseTapChanger.isRegulating()); + + // modification 3 : FIXED_TAP -> ACTIVE_POWER_CONTROL + phaseTapChangerCreation.getPhaseTapChanger().setRegulationMode(new AttributeModification<>(PhaseTapChanger.RegulationMode.ACTIVE_POWER_CONTROL, OperationType.SET)); + phaseTapChangerCreation.getPhaseTapChanger().setTargetDeadband(new AttributeModification<>(1.0, OperationType.SET)); + + String modificationToModifyJson3 = mapper.writeValueAsString(phaseTapChangerCreation); + mockMvc.perform(post(getNetworkModificationUri()).content(modificationToModifyJson3).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + + phaseTapChanger = getNetwork().getTwoWindingsTransformer(twtId).getPhaseTapChanger(); + + // modification 3 assert + assertEquals(PhaseTapChanger.RegulationMode.ACTIVE_POWER_CONTROL, phaseTapChanger.getRegulationMode()); + assertEquals(1.0, phaseTapChanger.getTargetDeadband()); + assertEquals(10.0, phaseTapChanger.getRegulationValue()); + assertTrue(phaseTapChanger.isRegulating()); + + // modification 4 : ACTIVE_POWER_CONTROL -> CURRENT_LIMITER + phaseTapChangerCreation.getPhaseTapChanger().setRegulationMode(new AttributeModification<>(PhaseTapChanger.RegulationMode.CURRENT_LIMITER, OperationType.SET)); + phaseTapChangerCreation.getPhaseTapChanger().setRegulationValue(new AttributeModification<>(8.0, OperationType.SET)); + phaseTapChangerCreation.getPhaseTapChanger().setTargetDeadband(new AttributeModification<>(2.0, OperationType.SET)); + + String modificationToModifyJson4 = mapper.writeValueAsString(phaseTapChangerCreation); + mockMvc.perform(post(getNetworkModificationUri()).content(modificationToModifyJson4).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + + phaseTapChanger = getNetwork().getTwoWindingsTransformer(twtId).getPhaseTapChanger(); + + // modification 4 assert + assertEquals(PhaseTapChanger.RegulationMode.CURRENT_LIMITER, phaseTapChanger.getRegulationMode()); + assertEquals(2.0, phaseTapChanger.getTargetDeadband()); + assertEquals(8.0, phaseTapChanger.getRegulationValue()); + assertTrue(phaseTapChanger.isRegulating()); + + // modification 5 : CURRENT_LIMITER -> FIX_TAP + phaseTapChangerCreation.getPhaseTapChanger().setRegulationMode(new AttributeModification<>(PhaseTapChanger.RegulationMode.FIXED_TAP, OperationType.SET)); + phaseTapChangerCreation.getPhaseTapChanger().setRegulationValue(null); + phaseTapChangerCreation.getPhaseTapChanger().setTargetDeadband(null); + + String modificationToModifyJson5 = mapper.writeValueAsString(phaseTapChangerCreation); + mockMvc.perform(post(getNetworkModificationUri()).content(modificationToModifyJson5).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + + phaseTapChanger = getNetwork().getTwoWindingsTransformer(twtId).getPhaseTapChanger(); + + // modification 5 assert + assertEquals(PhaseTapChanger.RegulationMode.CURRENT_LIMITER, phaseTapChanger.getRegulationMode()); + assertEquals(2.0, phaseTapChanger.getTargetDeadband()); + assertEquals(8.0, phaseTapChanger.getRegulationValue()); + assertFalse(phaseTapChanger.isRegulating()); + } + + @Test + void testPhaseTapChangerRegulationModification2() throws Exception { + TwoWindingsTransformer twt3 = createPhaseTapChanger(); + String twtId = "trf3"; + + // modification 1 : FIXED_TAP -> ACTIVE_POWER_CONTROL error + TwoWindingsTransformerModificationInfos phaseTapChangerCreation = TwoWindingsTransformerModificationInfos.builder() + .stashed(false) + .equipmentId(twtId) + .ratioTapChanger(RatioTapChangerModificationInfos.builder() + .build()) + .phaseTapChanger(PhaseTapChangerModificationInfos.builder() + .enabled(new AttributeModification<>(true, OperationType.SET)) + .regulationMode(new AttributeModification<>(PhaseTapChanger.RegulationMode.ACTIVE_POWER_CONTROL, OperationType.SET)) + .build()) + .build(); + + String modificationToModifyJson1 = mapper.writeValueAsString(phaseTapChangerCreation); + + // modification 1 assert + mockMvc.perform(post(getNetworkModificationUri()) + .content(modificationToModifyJson1).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + assertLogMessage(new NetworkModificationException(MODIFY_TWO_WINDINGS_TRANSFORMER_ERROR, "Regulation value is missing, phase tap changer can not regulate").getMessage(), + phaseTapChangerCreation.getErrorType().name(), reportService); + + // modification 2 : FIXED_TAP -> FIXED_TAP + phaseTapChangerCreation.getPhaseTapChanger().setRegulationMode(new AttributeModification<>(PhaseTapChanger.RegulationMode.FIXED_TAP, OperationType.SET)); + + String modificationToModifyJson2 = mapper.writeValueAsString(phaseTapChangerCreation); + mockMvc.perform(post(getNetworkModificationUri()).content(modificationToModifyJson2).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + + PhaseTapChanger phaseTapChanger = twt3.getPhaseTapChanger(); + + // modification 2 assert + assertEquals(PhaseTapChanger.RegulationMode.FIXED_TAP, phaseTapChanger.getRegulationMode()); + assertTrue(Double.isNaN(phaseTapChanger.getTargetDeadband())); + assertTrue(Double.isNaN(phaseTapChanger.getRegulationValue())); + assertFalse(phaseTapChanger.isRegulating()); + + // modification 3 : FIXED_TAP -> ACTIVE_POWER_CONTROL + phaseTapChangerCreation.getPhaseTapChanger().setRegulationMode(new AttributeModification<>(PhaseTapChanger.RegulationMode.ACTIVE_POWER_CONTROL, OperationType.SET)); + phaseTapChangerCreation.getPhaseTapChanger().setRegulationValue(new AttributeModification<>(8.0, OperationType.SET)); + + String modificationToModifyJson3 = mapper.writeValueAsString(phaseTapChangerCreation); + mockMvc.perform(post(getNetworkModificationUri()).content(modificationToModifyJson3).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + + phaseTapChanger = getNetwork().getTwoWindingsTransformer(twtId).getPhaseTapChanger(); + + // modification 3 assert + assertEquals(PhaseTapChanger.RegulationMode.ACTIVE_POWER_CONTROL, phaseTapChanger.getRegulationMode()); + assertEquals(0.0, phaseTapChanger.getTargetDeadband()); + assertEquals(8.0, phaseTapChanger.getRegulationValue()); + assertTrue(phaseTapChanger.isRegulating()); + + // modification 4 : ACTIVE_POWER_CONTROL -> CURRENT_LIMITER + twt3.remove(); + createPhaseTapChanger(PhaseTapChanger.RegulationMode.ACTIVE_POWER_CONTROL); + phaseTapChangerCreation.getPhaseTapChanger().setRegulationMode(new AttributeModification<>(PhaseTapChanger.RegulationMode.CURRENT_LIMITER, OperationType.SET)); + phaseTapChangerCreation.getPhaseTapChanger().setRegulationValue(new AttributeModification<>(6.0, OperationType.SET)); + phaseTapChangerCreation.getPhaseTapChanger().setTargetDeadband(null); + String modificationToModifyJson4 = mapper.writeValueAsString(phaseTapChangerCreation); + mockMvc.perform(post(getNetworkModificationUri()).content(modificationToModifyJson4).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + + phaseTapChanger = getNetwork().getTwoWindingsTransformer(twtId).getPhaseTapChanger(); + + // modification 4 assert + assertEquals(PhaseTapChanger.RegulationMode.CURRENT_LIMITER, phaseTapChanger.getRegulationMode()); + assertEquals(0.0, phaseTapChanger.getTargetDeadband()); + assertEquals(6.0, phaseTapChanger.getRegulationValue()); + assertTrue(phaseTapChanger.isRegulating()); + } + @Override protected void testCreationModificationMessage(ModificationInfos modificationInfos) throws Exception { assertEquals("TWO_WINDINGS_TRANSFORMER_MODIFICATION", modificationInfos.getMessageType()); @@ -623,5 +843,222 @@ private void changeConnectionState(TwoWindingsTransformer existingEquipment, Two assertThat(terminal.isConnected()).isEqualTo(expectedState); } } + + @Test + void testProcessPhaseTapChangerModification() { + TwoWindingsTransformer twt = createPhaseTapChanger(); + PhaseTapChanger phaseTapChanger = twt.getPhaseTapChanger(); + List regulationReports = new ArrayList<>(); + processPhaseTapRegulation(phaseTapChanger, null, true, + new AttributeModification<>(PhaseTapChanger.RegulationMode.FIXED_TAP, OperationType.SET), + null, null, regulationReports); + assertEquals(PhaseTapChanger.RegulationMode.FIXED_TAP, phaseTapChanger.getRegulationMode()); + assertTrue(Double.isNaN(phaseTapChanger.getRegulationValue())); + assertTrue(Double.isNaN(phaseTapChanger.getTargetDeadband())); + assertFalse(phaseTapChanger.isRegulating()); + + processPhaseTapRegulation(phaseTapChanger, null, true, + new AttributeModification<>(PhaseTapChanger.RegulationMode.ACTIVE_POWER_CONTROL, OperationType.SET), + new AttributeModification<>(10.0, OperationType.SET), null, regulationReports); + assertEquals(PhaseTapChanger.RegulationMode.ACTIVE_POWER_CONTROL, phaseTapChanger.getRegulationMode()); + assertEquals(10.0, phaseTapChanger.getRegulationValue()); + assertEquals(0.0, phaseTapChanger.getTargetDeadband()); + assertTrue(phaseTapChanger.isRegulating()); + + processPhaseTapRegulation(phaseTapChanger, null, true, + new AttributeModification<>(PhaseTapChanger.RegulationMode.FIXED_TAP, OperationType.SET), + null, null, regulationReports); + assertEquals(PhaseTapChanger.RegulationMode.ACTIVE_POWER_CONTROL, phaseTapChanger.getRegulationMode()); + assertEquals(10.0, phaseTapChanger.getRegulationValue()); + assertEquals(0.0, phaseTapChanger.getTargetDeadband()); + assertFalse(phaseTapChanger.isRegulating()); + + processPhaseTapRegulation(phaseTapChanger, null, true, + new AttributeModification<>(PhaseTapChanger.RegulationMode.CURRENT_LIMITER, OperationType.SET), + new AttributeModification<>(12.0, OperationType.SET), + new AttributeModification<>(8.0, OperationType.SET), + regulationReports); + assertEquals(PhaseTapChanger.RegulationMode.CURRENT_LIMITER, phaseTapChanger.getRegulationMode()); + assertEquals(12.0, phaseTapChanger.getRegulationValue()); + assertEquals(8.0, phaseTapChanger.getTargetDeadband()); + assertTrue(phaseTapChanger.isRegulating()); + + processPhaseTapRegulation(phaseTapChanger, null, true, + new AttributeModification<>(PhaseTapChanger.RegulationMode.FIXED_TAP, OperationType.SET), + null, null, regulationReports); + assertEquals(PhaseTapChanger.RegulationMode.CURRENT_LIMITER, phaseTapChanger.getRegulationMode()); + assertEquals(12.0, phaseTapChanger.getRegulationValue()); + assertEquals(8.0, phaseTapChanger.getTargetDeadband()); + assertFalse(phaseTapChanger.isRegulating()); + } + + @Test + void testProcessPhaseTapChangerCreation() { + TwoWindingsTransformer twt = createTwoWindingsTransformer(getNetwork().getSubstation("s1"), "trf3", "trf3", 2.0, 14.745, 0.0, 3.2E-5, 400.0, 225.0, + 41, 151, getNetwork().getVoltageLevel("v1").getId(), getNetwork().getVoltageLevel("v2").getId(), + "trf3", 1, ConnectablePosition.Direction.TOP, + "trf3", 2, ConnectablePosition.Direction.TOP); + List regulationReports = new ArrayList<>(); + PhaseTapChangerAdder adder = twt.newPhaseTapChanger(); + preparePhaseTapChangerAdder(adder); + String message = assertThrows(NetworkModificationException.class, () -> processPhaseTapRegulation(null, adder, false, + null, null, null, regulationReports)).getMessage(); + assertEquals("CREATE_TWO_WINDINGS_TRANSFORMER_ERROR : Regulation mode is missing when creating tap phase changer", message); + + AttributeModification regulationModeModification = new AttributeModification<>(PhaseTapChanger.RegulationMode.CURRENT_LIMITER, OperationType.SET); + String message2 = assertThrows(NetworkModificationException.class, () -> processPhaseTapRegulation(null, adder, false, + regulationModeModification, null, null, regulationReports)).getMessage(); + assertEquals("CREATE_TWO_WINDINGS_TRANSFORMER_ERROR : Regulation value is missing when creating tap phase changer with regulation enabled (different from FIXED_TAP)", message2); + processPhaseTapRegulation(null, adder, false, + new AttributeModification<>(PhaseTapChanger.RegulationMode.FIXED_TAP, OperationType.SET), + null, null, regulationReports); + adder.add(); + PhaseTapChanger phaseTapChanger = twt.getPhaseTapChanger(); + assertEquals(PhaseTapChanger.RegulationMode.FIXED_TAP, phaseTapChanger.getRegulationMode()); + assertTrue(Double.isNaN(phaseTapChanger.getRegulationValue())); + assertTrue(Double.isNaN(phaseTapChanger.getTargetDeadband())); + assertFalse(phaseTapChanger.isRegulating()); + + PhaseTapChangerAdder adder1 = twt.newPhaseTapChanger(); + preparePhaseTapChangerAdder(adder1); + processPhaseTapRegulation(null, adder1, false, + new AttributeModification<>(PhaseTapChanger.RegulationMode.CURRENT_LIMITER, OperationType.SET), + new AttributeModification<>(10.0, OperationType.SET), null, regulationReports); + adder1.add(); + phaseTapChanger = twt.getPhaseTapChanger(); + assertEquals(PhaseTapChanger.RegulationMode.CURRENT_LIMITER, phaseTapChanger.getRegulationMode()); + assertEquals(10.0, phaseTapChanger.getRegulationValue()); + assertEquals(0.0, phaseTapChanger.getTargetDeadband()); + assertTrue(phaseTapChanger.isRegulating()); + } + + private void preparePhaseTapChangerAdder(PhaseTapChangerAdder phaseTapChangerAdder) { + Terminal phaseTapChangerTerminal = ModificationUtils.getInstance().getTerminalFromIdentifiable(getNetwork(), + "v3load", + "LOAD", + "V3"); + phaseTapChangerAdder.setLowTapPosition(0) + .setTapPosition(1) + .setRegulationTerminal(phaseTapChangerTerminal) + .beginStep() + .setR(39.78473) + .setX(39.784725) + .setG(0.0) + .setB(0.0) + .setRho(1.0) + .setAlpha(1.) + .endStep() + .beginStep() + .setR(39.78475) + .setX(39.784727) + .setG(0.0) + .setB(0.0) + .setRho(1.0) + .setAlpha(1.1) + .endStep(); + } + + @Test + void testPhaseTapChangerRegulationCreation() throws Exception { + // test with non pre-existent phase tap changer + String twtId = "trf3"; + TwoWindingsTransformer twt3 = createTwoWindingsTransformer(getNetwork().getSubstation("s1"), "trf3", "trf3", 2.0, 14.745, 0.0, 3.2E-5, 400.0, 225.0, + 41, 151, getNetwork().getVoltageLevel("v1").getId(), getNetwork().getVoltageLevel("v2").getId(), + "trf3", 1, ConnectablePosition.Direction.TOP, + "trf3", 2, ConnectablePosition.Direction.TOP); + // creation 1 : CURRENT_LIMITER + TwoWindingsTransformerModificationInfos phaseTapChangerCreation = TwoWindingsTransformerModificationInfos.builder() + .stashed(false) + .equipmentId(twtId) + .ratioTapChanger(RatioTapChangerModificationInfos.builder() + .build()) + .phaseTapChanger(PhaseTapChangerModificationInfos.builder() + .enabled(new AttributeModification<>(true, OperationType.SET)) + .regulationMode(new AttributeModification<>(PhaseTapChanger.RegulationMode.CURRENT_LIMITER, OperationType.SET)) + .regulationValue(new AttributeModification<>(10.0, OperationType.SET)) + .lowTapPosition(new AttributeModification<>(0, OperationType.SET)) + .tapPosition(new AttributeModification<>(1, OperationType.SET)) + .regulatingTerminalId(new AttributeModification<>("v3load", OperationType.SET)) + .regulatingTerminalType(new AttributeModification<>("LOAD", OperationType.SET)) + .regulatingTerminalVlId(new AttributeModification<>("V3", OperationType.SET)) + .steps(List.of(TapChangerStepCreationInfos.builder() + .index(0) + .r(0) + .g(0) + .b(0) + .x(0) + .rho(1) + .build(), + TapChangerStepCreationInfos.builder() + .index(1) + .r(0) + .g(0) + .b(0) + .x(0) + .rho(1) + .build() + )) + .build()) + .build(); + + String modificationToModifyJson = mapper.writeValueAsString(phaseTapChangerCreation); + mockMvc.perform(post(getNetworkModificationUri()).content(modificationToModifyJson).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + + PhaseTapChanger phaseTapChanger = twt3.getPhaseTapChanger(); + + // creation 1 assert + assertEquals(PhaseTapChanger.RegulationMode.CURRENT_LIMITER, phaseTapChanger.getRegulationMode()); + assertTrue(phaseTapChanger.isRegulating()); + assertEquals(0.0, phaseTapChanger.getTargetDeadband()); + assertEquals(10.0, phaseTapChanger.getRegulationValue()); + + // creation 2 : FIXED_TAP + twt3.getPhaseTapChanger().remove(); + phaseTapChangerCreation = TwoWindingsTransformerModificationInfos.builder() + .stashed(false) + .equipmentId(twtId) + .ratioTapChanger(RatioTapChangerModificationInfos.builder() + .build()) + .phaseTapChanger(PhaseTapChangerModificationInfos.builder() + .enabled(new AttributeModification<>(true, OperationType.SET)) + .regulationMode(new AttributeModification<>(PhaseTapChanger.RegulationMode.FIXED_TAP, OperationType.SET)) + .lowTapPosition(new AttributeModification<>(0, OperationType.SET)) + .tapPosition(new AttributeModification<>(1, OperationType.SET)) + .regulatingTerminalId(new AttributeModification<>("v3load", OperationType.SET)) + .regulatingTerminalType(new AttributeModification<>("LOAD", OperationType.SET)) + .regulatingTerminalVlId(new AttributeModification<>("V3", OperationType.SET)) + .steps(List.of(TapChangerStepCreationInfos.builder() + .index(0) + .r(0) + .g(0) + .b(0) + .x(0) + .rho(1) + .build(), + TapChangerStepCreationInfos.builder() + .index(1) + .r(0) + .g(0) + .b(0) + .x(0) + .rho(1) + .build() + )) + .build()) + .build(); + + modificationToModifyJson = mapper.writeValueAsString(phaseTapChangerCreation); + mockMvc.perform(post(getNetworkModificationUri()).content(modificationToModifyJson).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + + phaseTapChanger = twt3.getPhaseTapChanger(); + + // creation 2 assert + assertEquals(PhaseTapChanger.RegulationMode.FIXED_TAP, phaseTapChanger.getRegulationMode()); + assertFalse(phaseTapChanger.isRegulating()); + assertTrue(Double.isNaN(phaseTapChanger.getTargetDeadband())); + assertTrue(Double.isNaN(phaseTapChanger.getRegulationValue())); + } }