com.powsybl.flow_decomposition.LossesCompensator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of powsybl-flow-decomposition Show documentation
Show all versions of powsybl-flow-decomposition Show documentation
Implementation of ACER methodology for flow decomposition
The newest version!
/*
* 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.flow_decomposition;
import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.*;
import java.util.stream.Stream;
/**
* This class can
* 1- add zero MW loss loads to a network
* 2- set those loads to the correct AC loss
*
* @author Sebastien Murgey {@literal }
* @author Hugo Schindler {@literal }
* @author Caio Luke {@literal }
*/
class LossesCompensator {
private final double epsilon;
private Integer networkHash;
public static final String LOSSES_ID_PREFIX = "LOSSES ";
LossesCompensator(double epsilon) {
this.epsilon = epsilon;
networkHash = null;
}
LossesCompensator(FlowDecompositionParameters parameters) {
this(parameters.getLossesCompensationEpsilon());
}
static String getLossesId(String id) {
return LOSSES_ID_PREFIX + id;
}
public void run(Network network) {
if (networkHash == null || networkHash != network.hashCode()) {
addZeroMWLossesLoadsOnBuses(network);
networkHash = network.hashCode();
}
compensateLossesOnBranches(network);
}
private void addZeroMWLossesLoadsOnBuses(Network network) {
// We want to add a single null load per bus
// Mapping by bus Id is important as bus are generated on-fly
// This matters for node breaker topology
network.getBranchStream()
.flatMap(branch -> Stream.of(branch.getTerminal1(), branch.getTerminal2()))
.map(terminal -> terminal.getBusBreakerView().getConnectableBus())
.map(Identifiable::getId)
.distinct()
.forEach(busId -> addZeroMWLossesLoad(network, busId));
}
private void compensateLossesOnBranches(Network network) {
network.getBranchStream()
.filter(branch -> branch.getTerminal1().isConnected() || branch.getTerminal2().isConnected())
.forEach(branch -> compensateLossesOnBranch(network, branch));
}
private static void addZeroMWLossesLoad(Network network, String busId) {
String lossesId = getLossesId(busId);
Bus bus = network.getBusBreakerView().getBus(busId);
switch (bus.getVoltageLevel().getTopologyKind()) {
case BUS_BREAKER -> addZeroMWLossesLoadForBusBreakerTopology(bus, lossesId);
case NODE_BREAKER -> addZeroMWLossesLoadForNodeBreakerTopology(bus, lossesId);
default -> throw new PowsyblException("Topology not supported by loss compensation.");
}
}
private static void addZeroMWLossesLoadForBusBreakerTopology(Bus bus, String lossesId) {
bus.getVoltageLevel().newLoad()
.setId(lossesId)
.setBus(bus.getId())
.setP0(0)
.setQ0(0)
.setFictitious(true)
.add();
}
private static void addZeroMWLossesLoadForNodeBreakerTopology(Bus bus, String lossesId) {
VoltageLevel voltageLevel = bus.getVoltageLevel();
VoltageLevel.NodeBreakerView nodeBreakerView = voltageLevel.getNodeBreakerView();
int nodeNum = nodeBreakerView.getMaximumNodeIndex() + 1;
nodeBreakerView.newInternalConnection()
.setNode1(nodeNum)
.setNode2(nodeBreakerView.getNodes()[0])
.add();
voltageLevel.newLoad()
.setId(lossesId)
.setNode(nodeNum)
.setP0(0)
.setQ0(0)
.setFictitious(true)
.add();
}
private void compensateLossesOnBranch(Network network, Branch> branch) {
if (branch instanceof TieLine tieLine) {
compensateLossesOnTieLine(network, tieLine);
} else {
Terminal sendingTerminal = getSendingTerminal(branch);
double losses = branch.getTerminal1().getP() + branch.getTerminal2().getP();
updateLoadForLossesOnTerminal(network, sendingTerminal, losses);
}
}
private void compensateLossesOnTieLine(Network network, TieLine tieLine) {
DanglingLine danglingLine1 = tieLine.getDanglingLine1();
DanglingLine danglingLine2 = tieLine.getDanglingLine2();
Terminal terminal1 = danglingLine1.getTerminal();
Terminal terminal2 = danglingLine2.getTerminal();
double lossesSide1 = terminal1.getP() + danglingLine1.getBoundary().getP();
double lossesSide2 = terminal2.getP() + danglingLine2.getBoundary().getP();
updateLoadForLossesOnTerminal(network, terminal1, lossesSide1);
updateLoadForLossesOnTerminal(network, terminal2, lossesSide2);
}
private void updateLoadForLossesOnTerminal(Network network, Terminal terminal, double losses) {
if (losses > epsilon) {
Load load = network.getLoad(getLossesId(terminal.getBusBreakerView().getBus().getId()));
load.setP0(load.getP0() + losses);
}
}
private Terminal getSendingTerminal(Branch> branch) {
Terminal terminal1 = branch.getTerminal1();
Terminal terminal2 = branch.getTerminal2();
// if only one terminal is connected, that is the sending terminal
if (!(terminal1.isConnected() && terminal2.isConnected())) {
return terminal1.isConnected() ? terminal1 : terminal2;
}
// terminal with greater P is the sending terminal
if (terminal1.getP() >= terminal2.getP()) {
return terminal1;
} else {
return terminal2;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy