Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Hvdc action #2454

Merged
merged 16 commits into from
Mar 10, 2023
6 changes: 6 additions & 0 deletions commons/src/main/java/com/powsybl/commons/json/JsonUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -631,4 +631,10 @@ public static void writeOptionalDouble(JsonGenerator jsonGenerator, String field
jsonGenerator.writeNumberField(field, optional.getAsDouble());
}
}

public static void writeOptionalBoolean(JsonGenerator jsonGenerator, String field, Optional<Boolean> optional) throws IOException {
if (optional.isPresent()) {
jsonGenerator.writeBooleanField(field, optional.get());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/**
* Copyright (c) 2023, 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.HvdcLine;

import java.util.Objects;
import java.util.Optional;
import java.util.OptionalDouble;

/**
* An action to modify HVDC parameters and/or operating mode.
* <ul>
* <li>{@code acEmulationEnabled} parameter set to true correspond to AC emulation operation,
* false to fixed active power setpoint.
* <li>Note that AC emulation is relevant only for VSC converter station.
* <li>{@code droop} and {@code p0} parameters are used for AC emulation only.<br>
* <li>{@code activePowerSetpoint} and {@code converterMode} parameters are for fixed
* active power setpoint operation only. The {@code relativeValue} attribute should be used only
* when defining fixed active power setpoint.
* </ul>
*
* @author Etienne Lesot <etienne.lesot@rte-france.com>
*/
public class HvdcAction extends AbstractAction {

public static final String NAME = "HVDC";

private final String hvdcId;
private final boolean acEmulationEnabled;
private final Double activePowerSetpoint;
private final HvdcLine.ConvertersMode converterMode;
private final Double droop;
private final Double p0;
private final Boolean relativeValue;

HvdcAction(String id, String hvdcId, boolean acEmulationEnabled, Double activePowerSetpoint, HvdcLine.ConvertersMode converterMode, Double droop, Double p0, Boolean relativeValue) {
super(id);
this.hvdcId = Objects.requireNonNull(hvdcId);
this.acEmulationEnabled = acEmulationEnabled;
this.activePowerSetpoint = activePowerSetpoint;
this.converterMode = converterMode;
this.droop = droop;
this.p0 = p0;
this.relativeValue = relativeValue;
}

@Override
public String getType() {
return NAME;
}

public String getHvdcId() {
return hvdcId;
}

public Optional<HvdcLine.ConvertersMode> getConverterMode() {
return Optional.ofNullable(converterMode);
}

public OptionalDouble getDroop() {
return droop == null ? OptionalDouble.empty() : OptionalDouble.of(droop);
}

public OptionalDouble getActivePowerSetpoint() {
return activePowerSetpoint == null ? OptionalDouble.empty() : OptionalDouble.of(activePowerSetpoint);
}

public OptionalDouble getP0() {
return p0 == null ? OptionalDouble.empty() : OptionalDouble.of(p0);
}

public boolean isAcEmulationEnabled() {
jeandemanged marked this conversation as resolved.
Show resolved Hide resolved
return acEmulationEnabled;
}

public Optional<Boolean> isRelativeValue() {
return Optional.ofNullable(relativeValue);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* Copyright (c) 2023, 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.HvdcLine;

/**
*
* @author Etienne Lesot <etienne.lesot@rte-france.com>
*/
public class HvdcActionBuilder {

private String id;
private String hvdcId;
private boolean acEmulationEnabled;
private Double activePowerSetpoint = null;
private HvdcLine.ConvertersMode converterMode = null;
private Double droop = null;
private Double p0 = null;
private Boolean relativeValue = null;

public HvdcAction build() {
return new HvdcAction(id, hvdcId, acEmulationEnabled, activePowerSetpoint, converterMode, droop, p0, relativeValue);
}

public HvdcActionBuilder withId(String id) {
this.id = id;
return this;
}

public HvdcActionBuilder withHvdcId(String hvdcId) {
this.hvdcId = hvdcId;
return this;
}

public HvdcActionBuilder withAcEmulationEnabled(Boolean acEmulationEnabled) {
this.acEmulationEnabled = acEmulationEnabled;
return this;
}

public HvdcActionBuilder withActivePowerSetpoint(Double activePowerSetpoint) {
this.activePowerSetpoint = activePowerSetpoint;
return this;
}

public HvdcActionBuilder withDroop(Double droop) {
this.droop = droop;
return this;
}

public HvdcActionBuilder withP0(Double p0) {
this.p0 = p0;
return this;
}

public HvdcActionBuilder withRelativeValue(Boolean relativeValue) {
this.relativeValue = relativeValue;
return this;
}

public HvdcActionBuilder withConverterMode(HvdcLine.ConvertersMode converterMode) {
this.converterMode = converterMode;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,9 @@ private void configureActionsSerialization() {
new PhaseTapChangerRegulationActionSerializer(), new PhaseTapChangerRegulationActionDeserializer());
registerActionType(RatioTapChangerRegulationAction.class, RatioTapChangerRegulationAction.NAME,
new RatioTapChangerRegulationActionSerializer(), new RatioTapChangerRegulationActionDeserializer());
registerActionType(GeneratorAction.class, GeneratorAction.NAME,
new GeneratorActionSerializer(), new GeneratorActionDeserializer());
registerActionType(LoadAction.class, LoadAction.NAME,
new LoadActionSerializer(), new LoadActionDeserializer());
registerActionType(GeneratorAction.class, GeneratorAction.NAME, new GeneratorActionSerializer(), new GeneratorActionDeserializer());
registerActionType(LoadAction.class, LoadAction.NAME, new LoadActionSerializer(), new LoadActionDeserializer());
registerActionType(HvdcAction.class, HvdcAction.NAME, new HvdcActionSerializer(), new HvdcActionDeserializer());
}

private <T> void registerActionType(Class<T> actionClass, String typeName, JsonSerializer<T> serializer, JsonDeserializer<T> deserializer) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* Copyright (c) 2023, 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.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.powsybl.commons.json.JsonUtil;
import com.powsybl.iidm.network.HvdcLine;
import com.powsybl.security.action.HvdcAction;
import com.powsybl.security.action.HvdcActionBuilder;

import java.io.IOException;

/**
* @author Etienne Lesot <etienne.lesot@rte-france.com>
*/
public class HvdcActionDeserializer extends StdDeserializer<HvdcAction> {

public HvdcActionDeserializer() {
super(HvdcAction.class);
}

private static class ParsingContext {
String id;
String hvdcId;
boolean acEmulationEnabled;
Double activePowerSetpoint;
HvdcLine.ConvertersMode converterMode;
Double droop;
Double p0;
Boolean relativeValue = null;
}

@Override
public HvdcAction deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
ParsingContext context = new ParsingContext();
JsonUtil.parsePolymorphicObject(jsonParser, name -> {
switch (name) {
case "type":
if (!HvdcAction.NAME.equals(jsonParser.nextTextValue())) {
throw JsonMappingException.from(jsonParser, "Expected type " + HvdcAction.NAME);
}
return true;
case "id":
context.id = jsonParser.nextTextValue();
return true;
case "hvdcId":
context.hvdcId = jsonParser.nextTextValue();
return true;
case "acEmulationEnabled":
jsonParser.nextToken();
context.acEmulationEnabled = jsonParser.getValueAsBoolean();
return true;
case "activePowerSetpoint":
jsonParser.nextToken();
context.activePowerSetpoint = jsonParser.getValueAsDouble();
return true;
case "converterMode":
context.converterMode = HvdcLine.ConvertersMode.valueOf(jsonParser.nextTextValue());
return true;
case "droop":
jsonParser.nextToken();
context.droop = jsonParser.getValueAsDouble();
return true;
case "p0":
jsonParser.nextToken();
context.p0 = jsonParser.getValueAsDouble();
return true;
case "relativeValue":
jsonParser.nextToken();
context.relativeValue = jsonParser.getValueAsBoolean();
return true;
default:
return false;
}
});
return new HvdcActionBuilder()
.withId(context.id)
.withHvdcId(context.hvdcId)
.withAcEmulationEnabled(context.acEmulationEnabled)
.withActivePowerSetpoint(context.activePowerSetpoint)
.withConverterMode(context.converterMode)
.withDroop(context.droop)
.withP0(context.p0)
.withRelativeValue(context.relativeValue)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Copyright (c) 2023, 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.security.action.HvdcAction;

import java.io.IOException;

/**
* @author Etienne Lesot <etienne.lesot@rte-france.com>
*/
public class HvdcActionSerializer extends StdSerializer<HvdcAction> {
public HvdcActionSerializer() {
super(HvdcAction.class);
}

@Override
public void serialize(HvdcAction action, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("type", action.getType());
jsonGenerator.writeStringField("id", action.getId());
jsonGenerator.writeStringField("hvdcId", action.getHvdcId());
jsonGenerator.writeBooleanField("acEmulationEnabled", action.isAcEmulationEnabled());
JsonUtil.writeOptionalDouble(jsonGenerator, "activePowerSetpoint", action.getActivePowerSetpoint());
JsonUtil.writeOptionalEnum(jsonGenerator, "converterMode", action.getConverterMode());
JsonUtil.writeOptionalDouble(jsonGenerator, "droop", action.getDroop());
JsonUtil.writeOptionalDouble(jsonGenerator, "p0", action.getP0());
JsonUtil.writeOptionalBoolean(jsonGenerator, "relativeValue", action.isRelativeValue());
jsonGenerator.writeEndObject();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.util.Collections;
import java.util.List;

import static com.powsybl.iidm.network.HvdcLine.ConvertersMode.SIDE_1_RECTIFIER_SIDE_2_INVERTER;
import static org.junit.jupiter.api.Assertions.*;
import static com.powsybl.security.LimitViolationType.*;

Expand Down Expand Up @@ -68,6 +69,32 @@ void actionRoundTrip() throws IOException {
PhaseTapChanger.RegulationMode.ACTIVE_POWER_CONTROL, 15.0));
actions.add(RatioTapChangerRegulationAction.activateRegulationAndChangeTargetV("id20", "transformerId5", 90.0));
actions.add(RatioTapChangerRegulationAction.deactivateRegulation("id21", "transformerId5", ThreeWindingsTransformer.Side.THREE));
actions.add(new HvdcActionBuilder()
.withId("id22")
.withHvdcId("hvdc1")
.withAcEmulationEnabled(false)
.build());
actions.add(new HvdcActionBuilder()
.withId("id23")
.withHvdcId("hvdc2")
.withAcEmulationEnabled(true)
.build());
actions.add(new HvdcActionBuilder()
.withId("id24")
.withHvdcId("hvdc2")
.withAcEmulationEnabled(true)
.withDroop(121.0)
.withP0(42.0)
.withConverterMode(SIDE_1_RECTIFIER_SIDE_2_INVERTER)
.withRelativeValue(false)
.build());
actions.add(new HvdcActionBuilder()
.withId("id25")
.withHvdcId("hvdc1")
.withAcEmulationEnabled(false)
.withActivePowerSetpoint(12.0)
.withRelativeValue(true)
.build());
ActionList actionList = new ActionList(actions);
roundTripTest(actionList, ActionList::writeJsonFile, ActionList::readJsonFile, "/ActionFileTest.json");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,5 +136,31 @@
"transformerId" : "transformerId5",
"regulating" : false,
"side" : "THREE"
}, {
"type" : "HVDC",
"id" : "id22",
"hvdcId" : "hvdc1",
"acEmulationEnabled" : false
}, {
"type" : "HVDC",
"id" : "id23",
"hvdcId" : "hvdc2",
"acEmulationEnabled" : true
}, {
"type" : "HVDC",
"id" : "id24",
"hvdcId" : "hvdc2",
"acEmulationEnabled" : true,
"converterMode" : "SIDE_1_RECTIFIER_SIDE_2_INVERTER",
"droop" : 121.0,
"p0" : 42.0,
"relativeValue" : false
}, {
"type" : "HVDC",
"id" : "id25",
"hvdcId" : "hvdc1",
"acEmulationEnabled" : false,
"activePowerSetpoint" : 12.0,
"relativeValue" : true
} ]
}
Loading