diff --git a/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/action/LineConnectionAction.java b/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/action/LineConnectionAction.java deleted file mode 100644 index 7b72273a633..00000000000 --- a/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/action/LineConnectionAction.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) 2022, RTE (http://www.rte-france.com) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -package com.powsybl.security.action; - -import java.util.Objects; - -/** - * An action opening or closing one side or both sides of a line. - * - * @author Anne Tilloy {@literal } - */ -public class LineConnectionAction extends AbstractAction { - - public static final String NAME = "LINE_CONNECTION"; - - private final String lineId; - private final boolean openSide1; - private final boolean openSide2; - - public LineConnectionAction(String id, String lineId, boolean openSide1, boolean openSide2) { - super(id); - this.lineId = Objects.requireNonNull(lineId); - this.openSide1 = openSide1; - this.openSide2 = openSide2; - } - - public LineConnectionAction(String id, String lineId, boolean open) { - super(id); - this.lineId = Objects.requireNonNull(lineId); - this.openSide1 = open; - this.openSide2 = open; - } - - @Override - public String getType() { - return NAME; - } - - public String getLineId() { - return lineId; - } - - /** - * If {@code true}, applying the action will open the terminal 1 of the line, - * else it will close it. - */ - public boolean isOpenSide1() { - return openSide1; - } - - /** - * If {@code true}, applying the action will open the terminal 2 of the line, - * else it will close it. - */ - public boolean isOpenSide2() { - return openSide2; - } -} diff --git a/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/action/TerminalsConnectionAction.java b/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/action/TerminalsConnectionAction.java new file mode 100644 index 00000000000..fbd40aa3c04 --- /dev/null +++ b/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/action/TerminalsConnectionAction.java @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2024, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.security.action; + +import com.powsybl.iidm.network.ThreeSides; + +import java.util.Objects; +import java.util.Optional; + +/** + * An action of opening or closing an equipment terminal(s). + * + * @author Anne Tilloy {@literal } + */ +public class TerminalsConnectionAction extends AbstractAction { + + public static final String NAME = "TERMINALS_CONNECTION"; + private final String elementId; + private ThreeSides side; + private final boolean open; + + /** + * @param id the id of the action. + * @param elementId the id of the element which terminals are operated. + * The element can be any connectable, including a tie line by referring the terminal of + * an underlying dangling line. + * @param side the side of the element to operate in the action. + * @param open the status for the terminal to operate. {@code true} means terminal opening. + */ + public TerminalsConnectionAction(String id, String elementId, ThreeSides side, boolean open) { + super(id); + this.elementId = Objects.requireNonNull(elementId); + this.side = Objects.requireNonNull(side); + this.open = open; + } + + /** + * @param id the id of the action. + * @param elementId the id of the element which terminals are operated. + * The element can be any connectable, including a tie line by referring the terminal of + * an underlying dangling line. + * @param open the status for all the terminals of the element to operate. {@code true} means all terminals opening. + */ + public TerminalsConnectionAction(String id, String elementId, boolean open) { + super(id); + this.elementId = Objects.requireNonNull(elementId); + this.open = open; + } + + @Override + public String getType() { + return NAME; + } + + /** + * @return the element id. + */ + public String getElementId() { + return elementId; + } + + /** + * The side is optional. Empty means that all the terminals of the element will be operated + * in the action with the defined open or close status. + * @return the optional side of the connection/disconnection action. + */ + public Optional getSide() { + return Optional.ofNullable(side); + } + + /** + * If {@code true}, applying the action will open the terminal reference with side is given, + * else it will close it. If the side is not given, if {@code true}, applying the action will open all the terminals + * of the element, else it will close them. + */ + public boolean isOpen() { + return open; + } +} diff --git a/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/json/SecurityAnalysisJsonModule.java b/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/json/SecurityAnalysisJsonModule.java index 4de165f18a2..7ef8dfdf741 100644 --- a/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/json/SecurityAnalysisJsonModule.java +++ b/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/json/SecurityAnalysisJsonModule.java @@ -95,8 +95,8 @@ private void configureActionsSerialization() { setMixInAnnotation(Action.class, ActionMixIn.class); registerActionType(SwitchAction.class, SwitchAction.NAME, new SwitchActionSerializer(), new SwitchActionDeserializer()); - registerActionType(LineConnectionAction.class, LineConnectionAction.NAME, - new LineConnectionActionSerializer(), new LineConnectionActionDeserializer()); + registerActionType(TerminalsConnectionAction.class, TerminalsConnectionAction.NAME, + new TerminalsConnectionActionSerializer(), new TerminalsConnectionActionDeserializer()); registerActionType(MultipleActionsAction.class, MultipleActionsAction.NAME, new MultipleActionsActionSerializer(), new MultipleActionsActionDeserializer()); registerActionType(PhaseTapChangerTapPositionAction.class, PhaseTapChangerTapPositionAction.NAME, diff --git a/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/json/action/LineConnectionActionSerializer.java b/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/json/action/LineConnectionActionSerializer.java deleted file mode 100644 index a68b5ec5e0a..00000000000 --- a/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/json/action/LineConnectionActionSerializer.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2022, RTE (http://www.rte-france.com) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -package com.powsybl.security.json.action; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import com.powsybl.security.action.LineConnectionAction; - -import java.io.IOException; - -/** - * @author Etienne Lesot {@literal } - */ -public class LineConnectionActionSerializer extends StdSerializer { - - public LineConnectionActionSerializer() { - super(LineConnectionAction.class); - } - - @Override - public void serialize(LineConnectionAction action, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { - jsonGenerator.writeStartObject(); - jsonGenerator.writeStringField("type", action.getType()); - jsonGenerator.writeStringField("id", action.getId()); - jsonGenerator.writeStringField("lineId", action.getLineId()); - jsonGenerator.writeBooleanField("openSide1", action.isOpenSide1()); - jsonGenerator.writeBooleanField("openSide2", action.isOpenSide2()); - jsonGenerator.writeEndObject(); - } -} diff --git a/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/json/action/LineConnectionActionDeserializer.java b/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/json/action/TerminalsConnectionActionDeserializer.java similarity index 51% rename from security-analysis/security-analysis-api/src/main/java/com/powsybl/security/json/action/LineConnectionActionDeserializer.java rename to security-analysis/security-analysis-api/src/main/java/com/powsybl/security/json/action/TerminalsConnectionActionDeserializer.java index 4d0fd4c1983..af95c635f4b 100644 --- a/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/json/action/LineConnectionActionDeserializer.java +++ b/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/json/action/TerminalsConnectionActionDeserializer.java @@ -11,57 +11,62 @@ import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.powsybl.commons.json.JsonUtil; -import com.powsybl.security.action.LineConnectionAction; +import com.powsybl.iidm.network.ThreeSides; +import com.powsybl.security.action.TerminalsConnectionAction; import java.io.IOException; /** * @author Etienne Lesot {@literal } */ -public class LineConnectionActionDeserializer extends StdDeserializer { +public class TerminalsConnectionActionDeserializer extends StdDeserializer { - public LineConnectionActionDeserializer() { - super(LineConnectionAction.class); + public TerminalsConnectionActionDeserializer() { + super(TerminalsConnectionAction.class); } private static class ParsingContext { String id; - String lineId; - Boolean openSide1; - Boolean openSide2; + String elementId; + ThreeSides side; + Boolean open; } @Override - public LineConnectionAction deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { + public TerminalsConnectionAction deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { ParsingContext context = new ParsingContext(); JsonUtil.parsePolymorphicObject(jsonParser, name -> { switch (name) { case "type": - if (!LineConnectionAction.NAME.equals(jsonParser.nextTextValue())) { - throw JsonMappingException.from(jsonParser, "Expected type " + LineConnectionAction.NAME); + if (!TerminalsConnectionAction.NAME.equals(jsonParser.nextTextValue())) { + throw JsonMappingException.from(jsonParser, "Expected type " + TerminalsConnectionAction.NAME); } return true; case "id": context.id = jsonParser.nextTextValue(); return true; - case "lineId": - context.lineId = jsonParser.nextTextValue(); + case "elementId": + context.elementId = jsonParser.nextTextValue(); return true; - case "openSide1": + case "side": jsonParser.nextToken(); - context.openSide1 = jsonParser.getValueAsBoolean(); + context.side = ThreeSides.valueOf(jsonParser.getValueAsString()); return true; - case "openSide2": + case "open": jsonParser.nextToken(); - context.openSide2 = jsonParser.getValueAsBoolean(); + context.open = jsonParser.getValueAsBoolean(); return true; default: return false; } }); - if (context.openSide1 == null || context.openSide2 == null) { - throw JsonMappingException.from(jsonParser, "for line action openSide1 and openSide2 fields can't be null"); + if (context.open == null) { + throw JsonMappingException.from(jsonParser, "for terminal connection action open field can't be null"); + } + if (context.side == null) { + return new TerminalsConnectionAction(context.id, context.elementId, context.open); + } else { + return new TerminalsConnectionAction(context.id, context.elementId, context.side, context.open); } - return new LineConnectionAction(context.id, context.lineId, context.openSide1, context.openSide2); } } diff --git a/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/json/action/TerminalsConnectionActionSerializer.java b/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/json/action/TerminalsConnectionActionSerializer.java new file mode 100644 index 00000000000..a1eb748c157 --- /dev/null +++ b/security-analysis/security-analysis-api/src/main/java/com/powsybl/security/json/action/TerminalsConnectionActionSerializer.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2024, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.security.json.action; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import com.powsybl.commons.json.JsonUtil; +import com.powsybl.iidm.network.ThreeSides; +import com.powsybl.security.action.TerminalsConnectionAction; + +import java.io.IOException; +import java.util.Optional; + +/** + * @author Anne Tilloy {@literal } + */ +public class TerminalsConnectionActionSerializer extends StdSerializer { + + public TerminalsConnectionActionSerializer() { + super(TerminalsConnectionAction.class); + } + + @Override + public void serialize(TerminalsConnectionAction action, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { + jsonGenerator.writeStartObject(); + jsonGenerator.writeStringField("type", action.getType()); + jsonGenerator.writeStringField("id", action.getId()); + jsonGenerator.writeStringField("elementId", action.getElementId()); + Optional side = action.getSide(); + if (side.isPresent()) { + JsonUtil.writeOptionalStringField(jsonGenerator, "side", String.valueOf(side.get())); + } + jsonGenerator.writeBooleanField("open", action.isOpen()); + jsonGenerator.writeEndObject(); + } +} diff --git a/security-analysis/security-analysis-api/src/test/java/com/powsybl/security/json/JsonActionAndOperatorStrategyTest.java b/security-analysis/security-analysis-api/src/test/java/com/powsybl/security/json/JsonActionAndOperatorStrategyTest.java index f67cdaa3394..1de7a0855e8 100644 --- a/security-analysis/security-analysis-api/src/test/java/com/powsybl/security/json/JsonActionAndOperatorStrategyTest.java +++ b/security-analysis/security-analysis-api/src/test/java/com/powsybl/security/json/JsonActionAndOperatorStrategyTest.java @@ -47,8 +47,8 @@ void actionRoundTrip() throws IOException { List actions = new ArrayList<>(); actions.add(new SwitchAction("id1", "switchId1", true)); actions.add(new MultipleActionsAction("id2", Collections.singletonList(new SwitchAction("id3", "switchId2", true)))); - actions.add(new LineConnectionAction("id3", "lineId3", true, true)); - actions.add(new LineConnectionAction("id4", "lineId4", false)); + actions.add(new TerminalsConnectionAction("id3", "lineId3", true)); // both sides. + actions.add(new TerminalsConnectionAction("id4", "lineId4", false)); // both sides. actions.add(new PhaseTapChangerTapPositionAction("id5", "transformerId1", true, 5, ThreeSides.TWO)); actions.add(new PhaseTapChangerTapPositionAction("id6", "transformerId2", false, 12)); actions.add(new PhaseTapChangerTapPositionAction("id7", "transformerId3", true, -5, ThreeSides.ONE)); @@ -103,6 +103,7 @@ void actionRoundTrip() throws IOException { actions.add(new StaticVarCompensatorActionBuilder().withId("id24") .withStaticVarCompensatorId("svc").withRegulationMode(StaticVarCompensator.RegulationMode.REACTIVE_POWER) .withReactivePowerSetpoint(120.0).build()); + actions.add(new TerminalsConnectionAction("id4", "transformerId25", ThreeSides.THREE, true)); // only one side. ActionList actionList = new ActionList(actions); roundTripTest(actionList, ActionList::writeJsonFile, ActionList::readJsonFile, "/ActionFileTest.json"); } diff --git a/security-analysis/security-analysis-api/src/test/resources/ActionFileTest.json b/security-analysis/security-analysis-api/src/test/resources/ActionFileTest.json index 0fee70288e8..05bb2aaddd6 100644 --- a/security-analysis/security-analysis-api/src/test/resources/ActionFileTest.json +++ b/security-analysis/security-analysis-api/src/test/resources/ActionFileTest.json @@ -15,17 +15,15 @@ "open" : true } ] }, { - "type" : "LINE_CONNECTION", + "type" : "TERMINALS_CONNECTION", "id" : "id3", - "lineId" : "lineId3", - "openSide1" : true, - "openSide2" : true + "elementId" : "lineId3", + "open" : true }, { - "type" : "LINE_CONNECTION", + "type" : "TERMINALS_CONNECTION", "id" : "id4", - "lineId" : "lineId4", - "openSide1" : false, - "openSide2" : false + "elementId" : "lineId4", + "open" : false }, { "type" : "PHASE_TAP_CHANGER_TAP_POSITION", "id" : "id5", @@ -179,5 +177,11 @@ "staticVarCompensatorId" : "svc", "regulationMode" : "REACTIVE_POWER", "reactivePowerSetpoint" : 120.0 + }, { + "type" : "TERMINALS_CONNECTION", + "id" : "id4", + "elementId" : "transformerId25", + "side" : "THREE", + "open" : true } ] } \ No newline at end of file diff --git a/security-analysis/security-analysis-api/src/test/resources/ActionFileTestV1.0.json b/security-analysis/security-analysis-api/src/test/resources/ActionFileTestV1.0.json index 8bd8f28f184..3dcbed774ff 100644 --- a/security-analysis/security-analysis-api/src/test/resources/ActionFileTestV1.0.json +++ b/security-analysis/security-analysis-api/src/test/resources/ActionFileTestV1.0.json @@ -15,17 +15,15 @@ "open" : true } ] }, { - "type" : "LINE_CONNECTION", + "type" : "TERMINALS_CONNECTION", "id" : "id3", - "lineId" : "lineId3", - "openSide1" : true, - "openSide2" : true + "elementId" : "lineId3", + "open" : true }, { - "type" : "LINE_CONNECTION", + "type" : "TERMINALS_CONNECTION", "id" : "id4", - "lineId" : "lineId4", - "openSide1" : false, - "openSide2" : false + "elementId" : "lineId4", + "open" : false }, { "type" : "PHASE_TAP_CHANGER_TAP_POSITION", "id" : "id5", @@ -179,5 +177,11 @@ "staticVarCompensatorId" : "svc", "regulationMode" : "REACTIVE_POWER", "reactivePowerSetpoint" : 120.0 + }, { + "type" : "TERMINALS_CONNECTION", + "id" : "id4", + "elementId" : "transformerId25", + "side" : "THREE", + "open" : true } ] } \ No newline at end of file diff --git a/security-analysis/security-analysis-api/src/test/resources/ActionFileTestWrongVersion.json b/security-analysis/security-analysis-api/src/test/resources/ActionFileTestWrongVersion.json index 9f9131b8e42..acf0856c8d3 100644 --- a/security-analysis/security-analysis-api/src/test/resources/ActionFileTestWrongVersion.json +++ b/security-analysis/security-analysis-api/src/test/resources/ActionFileTestWrongVersion.json @@ -15,17 +15,15 @@ "open" : true } ] }, { - "type" : "LINE_CONNECTION", + "type" : "TERMINALS_CONNECTION", "id" : "id3", - "lineId" : "lineId3", - "openSide1" : true, - "openSide2" : true + "elementId" : "lineId3", + "open" : true }, { - "type" : "LINE_CONNECTION", + "type" : "TERMINALS_CONNECTION", "id" : "id4", - "lineId" : "lineId4", - "openSide1" : false, - "openSide2" : false + "elementId" : "lineId4", + "open" : false }, { "type" : "PHASE_TAP_CHANGER_TAP_POSITION", "id" : "id5",