FactsDeviceConverter.java
/**
* 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.psse.converter;
import java.util.*;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.util.ContainersMapping;
import com.powsybl.psse.model.PsseVersion;
import com.powsybl.psse.model.pf.PsseFacts;
import com.powsybl.psse.model.pf.PssePowerFlowModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.powsybl.psse.model.PsseVersion.Major.V35;
/**
* @author Luma Zamarre��o {@literal <zamarrenolm at aia.es>}
* @author Jos�� Antonio Marqu��s {@literal <marquesja at aia.es>}
*/
class FactsDeviceConverter extends AbstractConverter {
FactsDeviceConverter(PsseFacts psseFactsDevice, ContainersMapping containerMapping, Network network, PsseVersion version, NodeBreakerImport nodeBreakerImport) {
super(containerMapping, network);
this.psseFactsDevice = Objects.requireNonNull(psseFactsDevice);
this.version = version;
this.nodeBreakerImport = Objects.requireNonNull(nodeBreakerImport);
}
void create() {
if (!getContainersMapping().isBusDefined(psseFactsDevice.getI())) {
return;
}
if (isStatCom(psseFactsDevice)) {
createStatCom();
}
}
private void createStatCom() {
VoltageLevel voltageLevel = getNetwork().getVoltageLevel(getContainersMapping().getVoltageLevelId(psseFactsDevice.getI()));
double maxReactivePower = psseFactsDevice.getShmx();
double bMax = powerToShuntAdmittance(maxReactivePower, voltageLevel.getNominalV());
StaticVarCompensatorAdder adder = voltageLevel.newStaticVarCompensator()
.setId(getFactsDeviceId(psseFactsDevice.getName()))
.setName(psseFactsDevice.getName())
.setRegulating(false)
.setRegulationMode(StaticVarCompensator.RegulationMode.REACTIVE_POWER)
.setBmin(-bMax)
.setBmax(bMax);
String equipmentId = getNodeBreakerEquipmentId(PsseEquipmentType.PSSE_FACTS_DEVICE, psseFactsDevice.getI(), psseFactsDevice.getJ(), psseFactsDevice.getName());
OptionalInt node = nodeBreakerImport.getNode(getNodeBreakerEquipmentIdBus(equipmentId, psseFactsDevice.getI(), 0, 0, psseFactsDevice.getI(), "I"));
if (node.isPresent()) {
adder.setNode(node.getAsInt());
} else {
String busId = getBusId(psseFactsDevice.getI());
adder.setConnectableBus(busId);
adder.setBus(psseFactsDevice.getMode() == 0 ? null : busId);
}
adder.add();
}
void addControl() {
StaticVarCompensator staticVarCompensator = getNetwork().getStaticVarCompensator(getFactsDeviceId(psseFactsDevice.getName()));
// Add control only if staticVarCompensator has been created
if (staticVarCompensator == null) {
return;
}
Terminal regulatingTerminal = defineRegulatingTerminal(psseFactsDevice, getNetwork(), staticVarCompensator, version, nodeBreakerImport);
// Discard control if the staticVarCompensator is controlling an isolated bus
if (regulatingTerminal == null) {
return;
}
double vnom = regulatingTerminal.getVoltageLevel().getNominalV();
double targetQ = psseFactsDevice.getQdes();
double targetV = psseFactsDevice.getVset() * vnom;
boolean isRegulating = false;
StaticVarCompensator.RegulationMode regulationMode = StaticVarCompensator.RegulationMode.REACTIVE_POWER;
if (Double.isFinite(targetV) && targetV > 0.0) {
regulationMode = StaticVarCompensator.RegulationMode.VOLTAGE;
isRegulating = true;
} else if (Double.isFinite(targetQ)) {
isRegulating = true;
}
staticVarCompensator.setVoltageSetpoint(targetV)
.setReactivePowerSetpoint(targetQ)
.setRegulatingTerminal(regulatingTerminal)
.setRegulationMode(regulationMode)
.setRegulating(isRegulating);
}
private static Terminal defineRegulatingTerminal(PsseFacts psseFactsDevice, Network network, StaticVarCompensator staticVarCompensator, PsseVersion version, NodeBreakerImport nodeBreakerImport) {
Terminal regulatingTerminal = null;
if (factsDeviceRegulatingBus(psseFactsDevice, version) == 0) {
regulatingTerminal = staticVarCompensator.getTerminal();
} else {
Optional<NodeBreakerImport.ControlR> control = nodeBreakerImport.getControl(factsDeviceRegulatingBus(psseFactsDevice, version));
if (control.isPresent()) {
regulatingTerminal = findTerminalNode(network, control.get().voltageLevelId(), control.get().node());
} else {
String regulatingBusId = getBusId(factsDeviceRegulatingBus(psseFactsDevice, version));
Bus bus = network.getBusBreakerView().getBus(regulatingBusId);
if (bus != null) {
regulatingTerminal = bus.getConnectedTerminalStream().findFirst().orElse(null);
}
}
}
if (regulatingTerminal == null) {
LOGGER.warn("FactsDevice {}. Regulating terminal is not assigned as the bus is isolated", psseFactsDevice.getName());
}
return regulatingTerminal;
}
private static int factsDeviceRegulatingBus(PsseFacts factsDevice, PsseVersion psseVersion) {
if (psseVersion.major() == V35) {
return factsDevice.getFcreg();
} else {
return factsDevice.getRemot();
}
}
static void create(Network network, PssePowerFlowModel psseModel, ContextExport contextExport) {
network.getStaticVarCompensators().forEach(staticVarCompensator -> psseModel.addFacts(Collections.singletonList(createFactsDevice(staticVarCompensator, contextExport))));
psseModel.replaceAllFacts(psseModel.getFacts().stream().sorted(Comparator.comparing(PsseFacts::getName)).toList());
}
private static PsseFacts createFactsDevice(StaticVarCompensator staticVarCompensator, ContextExport contextExport) {
PsseFacts psseFactsDevice = createDefaultFactsDevice();
int busI = getTerminalBusI(staticVarCompensator.getTerminal(), contextExport);
double maxReactivePower = shuntAdmittanceToPower(staticVarCompensator.getBmax(), staticVarCompensator.getTerminal().getVoltageLevel().getNominalV());
psseFactsDevice.setName(extractFactsDeviceName(staticVarCompensator.getId()));
psseFactsDevice.setI(busI);
psseFactsDevice.setMode(getStatus(staticVarCompensator.getTerminal(), contextExport));
findTargetQ(staticVarCompensator).ifPresent(psseFactsDevice::setQdes);
findTargetV(staticVarCompensator).ifPresent(psseFactsDevice::setVset);
psseFactsDevice.setShmx(maxReactivePower);
psseFactsDevice.setFcreg(getRegulatingTerminalBusI(staticVarCompensator.getRegulatingTerminal(), busI, psseFactsDevice.getFcreg(), contextExport));
psseFactsDevice.setNreg(getRegulatingTerminalNode(staticVarCompensator.getRegulatingTerminal(), contextExport));
return psseFactsDevice;
}
private static PsseFacts createDefaultFactsDevice() {
PsseFacts psseFactsDevice = new PsseFacts();
psseFactsDevice.setName("");
psseFactsDevice.setI(0);
psseFactsDevice.setJ(0);
psseFactsDevice.setMode(1);
psseFactsDevice.setPdes(0.0);
psseFactsDevice.setQdes(0.0);
psseFactsDevice.setVset(1.0);
psseFactsDevice.setShmx(9999.0);
psseFactsDevice.setTrmx(9999.0);
psseFactsDevice.setVtmn(0.9);
psseFactsDevice.setVtmx(1.1);
psseFactsDevice.setVsmx(1.0);
psseFactsDevice.setImx(0.0);
psseFactsDevice.setLinx(0.05);
psseFactsDevice.setRmpct(100.0);
psseFactsDevice.setOwner(1);
psseFactsDevice.setSet1(0.0);
psseFactsDevice.setSet2(0.0);
psseFactsDevice.setVsref(0);
psseFactsDevice.setFcreg(0);
psseFactsDevice.setNreg(0);
psseFactsDevice.setMname("");
return psseFactsDevice;
}
static void update(Network network, PssePowerFlowModel psseModel) {
psseModel.getFacts().forEach(psseFactsDevice -> {
String factsDeviceName = getFactsDeviceId(psseFactsDevice.getName());
StaticVarCompensator staticVarCompensator = network.getStaticVarCompensator(factsDeviceName);
if (staticVarCompensator == null) {
psseFactsDevice.setMode(0);
} else if (isStatCom(psseFactsDevice)) {
psseFactsDevice.setMode(getUpdatedStatus(staticVarCompensator.getTerminal()));
} else {
psseFactsDevice.setMode(getUpdatedStatus(staticVarCompensator.getTerminal()));
findTargetQ(staticVarCompensator).ifPresent(psseFactsDevice::setQdes);
findTargetV(staticVarCompensator).ifPresent(psseFactsDevice::setVset);
}
});
}
private static OptionalDouble findTargetQ(StaticVarCompensator staticVarCompensator) {
return Double.isFinite(staticVarCompensator.getReactivePowerSetpoint()) ? OptionalDouble.of(staticVarCompensator.getReactivePowerSetpoint()) : OptionalDouble.empty();
}
private static OptionalDouble findTargetV(StaticVarCompensator staticVarCompensator) {
return staticVarCompensator.getRegulatingTerminal() != null ? OptionalDouble.of(staticVarCompensator.getVoltageSetpoint() / staticVarCompensator.getRegulatingTerminal().getVoltageLevel().getNominalV()) : OptionalDouble.empty();
}
private static boolean isStatCom(PsseFacts psseFactsDevice) {
return psseFactsDevice.getJ() == 0;
}
private final PsseFacts psseFactsDevice;
private final PsseVersion version;
private final NodeBreakerImport nodeBreakerImport;
private static final Logger LOGGER = LoggerFactory.getLogger(FactsDeviceConverter.class);
}