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 regulating element for generator, vsc and svc creation #683

Merged
merged 3 commits into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/user_guide/flowdecomposition.rst
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ As we cannot set a PST on an interconnection, we set an equivalent null load cal
>>> network.get_generators()
name energy_source target_p min_p max_p min_q max_q rated_s reactive_limits_kind target_v target_q voltage_regulator_on regulated_element_id p q i voltage_level_id bus_id connected
id
FGEN 11_generator OTHER 100.0 -1000.0 1000.0 -1000.0 1000.0 NaN MIN_MAX 400.0 0.0 True NaN NaN NaN FGEN 1 FGEN 1_0 True
BLOAD 12_generator OTHER 100.0 -1000.0 1000.0 -1000.0 1000.0 NaN MIN_MAX 400.0 0.0 True NaN NaN NaN BLOAD 1 BLOAD 1_1 True
FGEN 11_generator OTHER 100.0 -1000.0 1000.0 -1000.0 1000.0 NaN MIN_MAX 400.0 0.0 True FGEN 11_generator NaN NaN NaN FGEN 1 FGEN 1_0 True
BLOAD 12_generator OTHER 100.0 -1000.0 1000.0 -1000.0 1000.0 NaN MIN_MAX 400.0 0.0 True BLOAD 12_generator NaN NaN NaN BLOAD 1 BLOAD 1_1 True
>>> network.get_loads()
name type p0 q0 p q i voltage_level_id bus_id connected
id
Expand Down
4 changes: 2 additions & 2 deletions docs/user_guide/network.rst
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ For example, you can retrieve generators data as follows:
>>> network.get_generators() # doctest: +NORMALIZE_WHITESPACE
name energy_source target_p min_p max_p min_q max_q rated_s reactive_limits_kind target_v target_q voltage_regulator_on regulated_element_id p q i voltage_level_id bus_id connected
id
GEN OTHER 607.0 -9999.99 4999.0 -9.999990e+03 9.999990e+03 NaN MIN_MAX 24.5 301.0 True NaN NaN NaN VLGEN VLGEN_0 True
GEN2 OTHER 607.0 -9999.99 4999.0 -1.797693e+308 1.797693e+308 NaN MIN_MAX 24.5 301.0 True NaN NaN NaN VLGEN VLGEN_0 True
GEN OTHER 607.0 -9999.99 4999.0 -9.999990e+03 9.999990e+03 NaN MIN_MAX 24.5 301.0 True GEN NaN NaN NaN VLGEN VLGEN_0 True
GEN2 OTHER 607.0 -9999.99 4999.0 -1.797693e+308 1.797693e+308 NaN MIN_MAX 24.5 301.0 True GEN2 NaN NaN NaN VLGEN VLGEN_0 True

Most dataframes are indexed on the ID of the elements.
However, some more complex dataframes have a multi-index : for example,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,8 @@ static NetworkDataframeMapper generators() {
.doubles("target_v", Generator::getTargetV, Generator::setTargetV)
.doubles("target_q", Generator::getTargetQ, Generator::setTargetQ)
.booleans("voltage_regulator_on", Generator::isVoltageRegulatorOn, Generator::setVoltageRegulatorOn)
.strings("regulated_element_id", NetworkDataframes::getRegulatedElementId, NetworkDataframes::setRegulatedElement)
.strings("regulated_element_id", generator -> NetworkUtil.getRegulatedElementId(generator::getRegulatingTerminal),
(generator, elementId) -> NetworkUtil.setRegulatingTerminal(generator::setRegulatingTerminal, generator.getNetwork(), elementId))
.doubles("p", getP(), setP())
.doubles("q", getQ(), setQ())
.doubles("i", g -> g.getTerminal().getI())
Expand All @@ -275,48 +276,6 @@ static NetworkDataframeMapper generators() {
.build();
}

private static String getRegulatedElementId(Injection<?> injection) {
Terminal terminal;
if (injection instanceof Generator generator) {
terminal = generator.getRegulatingTerminal();
} else if (injection instanceof VscConverterStation converterStation) {
terminal = converterStation.getRegulatingTerminal();
} else if (injection instanceof StaticVarCompensator svc) {
terminal = svc.getRegulatingTerminal();
} else {
throw new UnsupportedOperationException(String.format("%s is neither a generator, a vsc station or a var static compensator", injection.getId()));
}
if (terminal.getVoltageLevel().getTopologyKind() == TopologyKind.BUS_BREAKER) {
//Not supported for the moment
return null;
}
return terminal.getConnectable() != null ? terminal.getConnectable().getId() : null;
}

private static void setRegulatedElement(Injection<?> injection, String elementId) {
Network network = injection.getNetwork();
Identifiable<?> identifiable = network.getIdentifiable(elementId);
if (identifiable instanceof Injection) {
Terminal terminal = ((Injection<?>) identifiable).getTerminal();
if (terminal.getVoltageLevel().getTopologyKind() == TopologyKind.BUS_BREAKER) {
throw new UnsupportedOperationException("Cannot set regulated element to " + elementId +
": not currently supported for bus breaker topologies.");
}
if (injection instanceof Generator) {
((Generator) injection).setRegulatingTerminal(((Injection<?>) identifiable).getTerminal());
} else if (injection instanceof VscConverterStation) {
((VscConverterStation) injection).setRegulatingTerminal(((Injection<?>) identifiable).getTerminal());
} else if (injection instanceof StaticVarCompensator) {
((StaticVarCompensator) injection).setRegulatingTerminal(((Injection<?>) identifiable).getTerminal());
} else {
throw new UnsupportedOperationException(String.format("%s is neither a generator, a vsc station or a var static compensator", injection.getId()));
}
} else {
throw new UnsupportedOperationException("Cannot set regulated element to " + elementId +
": the regulated element may only be a busbar section or an injection.");
}
}

private static NetworkDataframeMapper subNetworks() {
return NetworkDataframeMapperBuilder.ofStream(n -> n.getSubnetworks().stream(),
getOrThrow(Network::getSubnetwork, "SubNetwork"))
Expand Down Expand Up @@ -656,7 +615,8 @@ static NetworkDataframeMapper vscs() {
.doubles("target_v", VscConverterStation::getVoltageSetpoint, VscConverterStation::setVoltageSetpoint)
.doubles("target_q", VscConverterStation::getReactivePowerSetpoint, VscConverterStation::setReactivePowerSetpoint)
.booleans("voltage_regulator_on", VscConverterStation::isVoltageRegulatorOn, VscConverterStation::setVoltageRegulatorOn)
.strings("regulated_element_id", NetworkDataframes::getRegulatedElementId, NetworkDataframes::setRegulatedElement)
.strings("regulated_element_id", vsc -> NetworkUtil.getRegulatedElementId(vsc::getRegulatingTerminal),
(vsc, elementId) -> NetworkUtil.setRegulatingTerminal(vsc::setRegulatingTerminal, vsc.getNetwork(), elementId))
.doubles("p", getP(), setP())
.doubles("q", getQ(), setQ())
.doubles("i", st -> st.getTerminal().getI())
Expand All @@ -680,7 +640,8 @@ private static NetworkDataframeMapper svcs() {
.doubles("target_q", StaticVarCompensator::getReactivePowerSetpoint, StaticVarCompensator::setReactivePowerSetpoint)
.enums("regulation_mode", StaticVarCompensator.RegulationMode.class,
StaticVarCompensator::getRegulationMode, StaticVarCompensator::setRegulationMode)
.strings("regulated_element_id", NetworkDataframes::getRegulatedElementId, NetworkDataframes::setRegulatedElement)
.strings("regulated_element_id", svc -> NetworkUtil.getRegulatedElementId(svc::getRegulatingTerminal),
(svc, elementId) -> NetworkUtil.setRegulatingTerminal(svc::setRegulatingTerminal, svc.getNetwork(), elementId))
.doubles("p", getP(), setP())
.doubles("q", getQ(), setQ())
.doubles("i", st -> st.getTerminal().getI())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@
import com.powsybl.dataframe.update.IntSeries;
import com.powsybl.dataframe.update.StringSeries;
import com.powsybl.dataframe.update.UpdatingDataframe;
import com.powsybl.iidm.network.EnergySource;
import com.powsybl.iidm.network.GeneratorAdder;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.*;
import com.powsybl.python.network.NetworkUtil;

import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -43,7 +42,8 @@ public class GeneratorDataframeAdder extends AbstractSimpleAdder {
SeriesMetadata.doubles("target_q"),
SeriesMetadata.doubles("rated_s"),
SeriesMetadata.doubles("target_v"),
SeriesMetadata.booleans("voltage_regulator_on")
SeriesMetadata.booleans("voltage_regulator_on"),
SeriesMetadata.strings("regulating_element_id")
);

@Override
Expand All @@ -63,6 +63,7 @@ private static class GeneratorSeries extends InjectionSeries {
private final IntSeries voltageRegulatorOn;
private final StringSeries energySource;
private final StringSeries busOrBusbarSections;
private final StringSeries regulatingElements;

GeneratorSeries(UpdatingDataframe dataframe) {
super(dataframe);
Expand All @@ -76,11 +77,13 @@ private static class GeneratorSeries extends InjectionSeries {
this.voltageRegulatorOn = dataframe.getInts("voltage_regulator_on");
this.energySource = dataframe.getStrings("energy_source");
this.busOrBusbarSections = dataframe.getStrings("bus_or_busbar_section_id");
this.regulatingElements = dataframe.getStrings("regulating_element_id");
}

GeneratorAdder createAdder(Network network, int row) {
GeneratorAdder adder = getVoltageLevelOrThrowWithBusOrBusbarSectionId(network, row, voltageLevels, busOrBusbarSections)
.newGenerator();

setInjectionAttributes(adder, row);
applyIfPresent(maxP, row, adder::setMaxP);
applyIfPresent(minP, row, adder::setMinP);
Expand All @@ -90,6 +93,8 @@ GeneratorAdder createAdder(Network network, int row) {
applyIfPresent(ratedS, row, adder::setRatedS);
applyBooleanIfPresent(voltageRegulatorOn, row, adder::setVoltageRegulatorOn);
applyIfPresent(energySource, row, EnergySource.class, adder::setEnergySource);
applyIfPresent(regulatingElements, row, elementId -> NetworkUtil
.setRegulatingTerminal(adder::setRegulatingTerminal, network, elementId));
return adder;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@
import com.powsybl.dataframe.update.DoubleSeries;
import com.powsybl.dataframe.update.StringSeries;
import com.powsybl.dataframe.update.UpdatingDataframe;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.StaticVarCompensator;
import com.powsybl.iidm.network.StaticVarCompensatorAdder;
import com.powsybl.iidm.network.*;
import com.powsybl.python.network.NetworkUtil;

import java.util.Collections;
import java.util.List;
Expand All @@ -39,7 +38,8 @@ public class SvcDataframeAdder extends AbstractSimpleAdder {
SeriesMetadata.doubles("b_min"),
SeriesMetadata.strings("regulation_mode"),
SeriesMetadata.doubles("target_v"),
SeriesMetadata.doubles("target_q")
SeriesMetadata.doubles("target_q"),
SeriesMetadata.strings("regulating_element_id")
);

@Override
Expand All @@ -56,6 +56,7 @@ private static class StaticVarCompensatorSeries extends InjectionSeries {
private final DoubleSeries targetV;
private final DoubleSeries targetQ;
private final StringSeries busOrBusbarSections;
private final StringSeries regulatingElements;

StaticVarCompensatorSeries(UpdatingDataframe dataframe) {
super(dataframe);
Expand All @@ -66,6 +67,7 @@ private static class StaticVarCompensatorSeries extends InjectionSeries {
this.targetV = dataframe.getDoubles("target_v");
this.regulationModes = dataframe.getStrings("regulation_mode");
this.busOrBusbarSections = dataframe.getStrings("bus_or_busbar_section_id");
this.regulatingElements = dataframe.getStrings("regulating_element_id");
}

StaticVarCompensatorAdder createAdder(Network network, int row) {
Expand All @@ -77,6 +79,8 @@ StaticVarCompensatorAdder createAdder(Network network, int row) {
applyIfPresent(targetQ, row, adder::setReactivePowerSetpoint);
applyIfPresent(targetV, row, adder::setVoltageSetpoint);
applyIfPresent(regulationModes, row, StaticVarCompensator.RegulationMode.class, adder::setRegulationMode);
applyIfPresent(regulatingElements, row, elementId -> NetworkUtil
.setRegulatingTerminal(adder::setRegulatingTerminal, network, elementId));
return adder;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
/**
* 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.dataframe.network.adders;

import com.powsybl.commons.PowsyblException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.powsybl.dataframe.update.UpdatingDataframe;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.VscConverterStationAdder;
import com.powsybl.python.network.NetworkUtil;

import java.util.Collections;
import java.util.List;
Expand All @@ -39,7 +40,8 @@ public class VscStationDataframeAdder extends AbstractSimpleAdder {
SeriesMetadata.doubles("target_v"),
SeriesMetadata.doubles("target_q"),
SeriesMetadata.doubles("loss_factor"),
SeriesMetadata.booleans("voltage_regulator_on")
SeriesMetadata.booleans("voltage_regulator_on"),
SeriesMetadata.strings("regulating_element_id")
);

@Override
Expand All @@ -55,6 +57,7 @@ private static class VscStationSeries extends InjectionSeries {
private final DoubleSeries targetQ;
private final IntSeries voltageRegulatorOn;
private final StringSeries busOrBusbarSections;
private final StringSeries regulatingElements;

VscStationSeries(UpdatingDataframe dataframe) {
super(dataframe);
Expand All @@ -64,6 +67,7 @@ private static class VscStationSeries extends InjectionSeries {
this.targetQ = dataframe.getDoubles("target_q");
this.voltageRegulatorOn = dataframe.getInts("voltage_regulator_on");
this.busOrBusbarSections = dataframe.getStrings("bus_or_busbar_section_id");
this.regulatingElements = dataframe.getStrings("regulating_element_id");
}

VscConverterStationAdder createAdder(Network network, int row) {
Expand All @@ -74,6 +78,8 @@ VscConverterStationAdder createAdder(Network network, int row) {
applyIfPresent(targetV, row, adder::setVoltageSetpoint);
applyIfPresent(targetQ, row, adder::setReactivePowerSetpoint);
applyBooleanIfPresent(voltageRegulatorOn, row, adder::setVoltageRegulatorOn);
applyIfPresent(regulatingElements, row, elementId -> NetworkUtil
.setRegulatingTerminal(adder::setRegulatingTerminal, network, elementId));
return adder;
}
}
Expand Down
16 changes: 16 additions & 0 deletions java/src/main/java/com/powsybl/python/network/NetworkUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Expand Down Expand Up @@ -217,4 +219,18 @@ public static Stream<ConnectablePositionFeederData> getFeeders(Network network)
return feeders.build();
}

public static void setRegulatingTerminal(Consumer<Terminal> adder, Network network, String elementId) {
Identifiable<?> injection = network.getIdentifiable(elementId);
if (injection instanceof Injection<?>) {
adder.accept(((Injection<?>) injection).getTerminal());
} else {
throw new UnsupportedOperationException("Cannot set regulated element to " + elementId +
": the regulated element may only be a busbar section or an injection.");
}
}

public static String getRegulatedElementId(Supplier<Terminal> regulatingTerminalGetter) {
Terminal terminal = regulatingTerminalGetter.get();
return terminal.getConnectable() != null ? terminal.getConnectable().getId() : null;
}
}
11 changes: 5 additions & 6 deletions tests/test_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ def test_update_generators_data_frame():
generators = n.get_generators()
assert 607 == generators['target_p']['GEN']
assert generators['voltage_regulator_on']['GEN']
assert '' == generators['regulated_element_id']['GEN']
assert 'GEN' == generators['regulated_element_id']['GEN']
generators2 = pd.DataFrame(data=[[608.0, 302.0, 25.0, False]],
columns=['target_p', 'target_q', 'target_v', 'voltage_regulator_on'], index=['GEN'])
n.update_generators(generators2)
Expand All @@ -587,13 +587,12 @@ def test_regulated_terminal_node_breaker():
def test_regulated_terminal_bus_breaker():
n = pp.network.create_eurostag_tutorial_example1_network()
generators = n.get_generators()
assert '' == generators['regulated_element_id']['GEN']

assert 'GEN' == generators['regulated_element_id']['GEN']
with pytest.raises(pp.PyPowsyblError):
n.update_generators(id='GEN', regulated_element_id='NHV1')
with pytest.raises(pp.PyPowsyblError):
n.update_generators(id='GEN', regulated_element_id='LOAD')

n.update_generators(id='GEN', regulated_element_id='LOAD')
generators = n.get_generators()
assert 'LOAD' == generators['regulated_element_id']['GEN']

def test_update_unknown_data():
n = pp.network.create_eurostag_tutorial_example1_network()
Expand Down
10 changes: 8 additions & 2 deletions tests/test_network_elements_creation.py
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ def test_create_network_and_run_loadflow():

generators = pd.DataFrame.from_records(index='id', data=[
{'voltage_level_id': 'VL1', 'id': 'GEN', 'bus_id': 'B1', 'target_p': 100, 'min_p': 0, 'max_p': 200,
'target_v': 400, 'voltage_regulator_on': True}
'target_v': 400, 'voltage_regulator_on': True, 'regulating_element_id': 'LOAD'}
])
n.create_generators(generators)

Expand All @@ -562,6 +562,9 @@ def test_create_network_and_run_loadflow():
assert line.p1 == pytest.approx(100, abs=1e-1)
assert line.q1 == pytest.approx(9.7, abs=1e-1)

generator = n.get_generators().loc['GEN']
assert generator.regulated_element_id == 'LOAD'


def test_create_node_breaker_network_and_run_loadflow():
n = pn.create_empty()
Expand Down Expand Up @@ -605,7 +608,7 @@ def test_create_node_breaker_network_and_run_loadflow():

generators = pd.DataFrame.from_records(index='id', data=[
{'voltage_level_id': 'VL1', 'id': 'GEN', 'node': 3, 'target_p': 100, 'min_p': 0, 'max_p': 200,
'target_v': 400, 'voltage_regulator_on': True}
'target_v': 400, 'voltage_regulator_on': True, 'regulating_element_id': 'LOAD'}
])
n.create_generators(generators)

Expand All @@ -618,6 +621,9 @@ def test_create_node_breaker_network_and_run_loadflow():
assert line.p1 == pytest.approx(100, abs=1e-1)
assert line.q1 == pytest.approx(9.7, abs=1e-1)

generator = n.get_generators().loc['GEN']
assert generator.regulated_element_id == 'LOAD'


def test_create_limits():
net = pn.create_eurostag_tutorial_example1_network()
Expand Down