Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,10 @@ static NetworkDataframeMapper buses(boolean busBreakerView) {
builder.strings("bus_id", b -> NetworkUtil.getBusViewBus(b).map(Bus::getId).orElse(""));
}
return builder.booleans("fictitious", Identifiable::isFictitious, Identifiable::setFictitious, false)
.doubles("fictitious_p0", (b, context) -> perUnitPQ(context, b.getFictitiousP0()),
(b, p, context) -> b.setFictitiousP0(unPerUnitPQ(context, p)), false)
.doubles("fictitious_q0", (b, context) -> perUnitPQ(context, b.getFictitiousQ0()),
(b, q, context) -> b.setFictitiousQ0(unPerUnitPQ(context, q)), false)
.addProperties()
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,61 @@ void buses() {
.containsExactly(0, 0, 0, 0);
assertThat(series.get(6).getStrings())
.containsExactly("VLGEN", "VLHV1", "VLHV2", "VLLOAD");

List<Series> allAttributeSeries = createDataFrame(BUS, network, new DataframeFilter(ALL_ATTRIBUTES, Collections.emptyList()));
assertThat(allAttributeSeries)
.extracting(Series::getName)
.contains("fictitious_p0", "fictitious_q0");
}

@Test
void busesFictitiousInjectionUpdate() {
Network network = EurostagTutorialExample1Factory.create();

DefaultUpdatingDataframe dataframe = new DefaultUpdatingDataframe(1);
dataframe.addSeries("id", true, new TestStringSeries("VLGEN_0"));
dataframe.addSeries("fictitious_p0", false, new TestDoubleSeries(1.0));
dataframe.addSeries("fictitious_q0", false, new TestDoubleSeries(2.0));
NetworkDataframeMapper mapper = NetworkDataframes.getDataframeMapper(BUS);
mapper.updateSeries(network, dataframe, NetworkDataframeContext.DEFAULT);

Bus bus = network.getBusView().getBus("VLGEN_0");
assertEquals(1.0, bus.getFictitiousP0(), 0.0);
assertEquals(2.0, bus.getFictitiousQ0(), 0.0);

Map<String, Series> attributes = createDataFrame(BUS, network, new DataframeFilter(ALL_ATTRIBUTES, Collections.emptyList()))
.stream().collect(ImmutableMap.toImmutableMap(Series::getName, Function.identity()));
assertThat(attributes.get("fictitious_p0").getDoubles()).contains(1.0);
assertThat(attributes.get("fictitious_q0").getDoubles()).contains(2.0);
}

@Test
void busBreakerViewBusesFictitiousInjection() {
// VL1 is Node/Breaker, VL2 is Bus/Breaker
Network network = TwoVoltageLevelNetworkFactory.create();
List<Series> series = createDataFrame(BUS_FROM_BUS_BREAKER_VIEW, network,
new DataframeFilter(ALL_ATTRIBUTES, Collections.emptyList()));
assertThat(series)
.extracting(Series::getName)
.contains("fictitious_p0", "fictitious_q0");
}

@Test
void busesFictitiousInjectionUpdateNodeBreaker() {
// VL1 is Node/Breaker: its bus view bus is a calculated bus aggregating the fictitious injection over its nodes
Network network = TwoVoltageLevelNetworkFactory.create();
String busId = network.getBusView().getBusStream().findFirst().orElseThrow().getId();

DefaultUpdatingDataframe dataframe = new DefaultUpdatingDataframe(1);
dataframe.addSeries("id", true, new TestStringSeries(busId));
dataframe.addSeries("fictitious_p0", false, new TestDoubleSeries(1.0));
dataframe.addSeries("fictitious_q0", false, new TestDoubleSeries(2.0));
NetworkDataframeMapper mapper = NetworkDataframes.getDataframeMapper(BUS);
mapper.updateSeries(network, dataframe, NetworkDataframeContext.DEFAULT);

Bus bus = network.getBusView().getBus(busId);
assertEquals(1.0, bus.getFictitiousP0(), 0.0);
assertEquals(2.0, bus.getFictitiousQ0(), 0.0);
}

@Test
Expand Down
6 changes: 6 additions & 0 deletions pypowsybl/network/impl/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,8 @@ def get_buses(self, all_attributes: bool = False, attributes: Optional[List[str]
- **connected_component**: The connected component to which the bus belongs
- **synchronous_component**: The synchronous component to which the bus belongs
- **voltage_level_id**: at which substation the bus is connected
- **fictitious_p0** (optional): the fictitious active power injection of the bus (in MW, using the load sign convention)
- **fictitious_q0** (optional): the fictitious reactive power injection of the bus (in MVar, using the load sign convention)

This dataframe is indexed on the bus ID in the bus view.

Expand Down Expand Up @@ -903,6 +905,8 @@ def get_bus_breaker_view_buses(self, all_attributes: bool = False, attributes: O
- **synchronous_component**: The synchronous component to which the bus belongs
- **voltage_level_id**: at which substation the bus is connected
- **bus_id**: the bus ID in the bus view
- **fictitious_p0** (optional): the fictitious active power injection of the bus (in MW, using the load sign convention)
- **fictitious_q0** (optional): the fictitious reactive power injection of the bus (in MVar, using the load sign convention)

This dataframe is indexed on the bus ID in the bus/breaker view.

Expand Down Expand Up @@ -3454,6 +3458,8 @@ def update_buses(self, df: Optional[DataFrame] = None, **kwargs: ArrayLike) -> N
- `v_mag`
- `v_angle`
- `fictitious`
- `fictitious_p0`
- `fictitious_q0`

See Also:
:meth:`get_buses`
Expand Down
51 changes: 46 additions & 5 deletions tests/test_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,47 @@ def test_buses():
pd.testing.assert_frame_equal(expected, buses, check_dtype=False)


def test_bus_fictitious_injection():
n = pp.network.create_eurostag_tutorial_example1_network()
buses = n.get_buses(all_attributes=True)
assert 'fictitious_p0' in buses.columns
assert 'fictitious_q0' in buses.columns
assert buses['fictitious_p0']['VLGEN_0'] == 0
assert buses['fictitious_q0']['VLGEN_0'] == 0

n.update_buses(pd.DataFrame(index=['VLGEN_0'], columns=['fictitious_p0', 'fictitious_q0'], data=[[10.0, 20.0]]))
buses = n.get_buses(all_attributes=True)
assert buses['fictitious_p0']['VLGEN_0'] == 10.0
assert buses['fictitious_q0']['VLGEN_0'] == 20.0


def test_bus_breaker_view_fictitious_injection():
n = pp.network.create_eurostag_tutorial_example1_network()
buses = n.get_bus_breaker_view_buses(all_attributes=True)
assert 'fictitious_p0' in buses.columns
assert 'fictitious_q0' in buses.columns
assert buses['fictitious_p0']['NGEN'] == 0
assert buses['fictitious_q0']['NGEN'] == 0


def test_bus_fictitious_injection_node_breaker():
n = pp.network.create_four_substations_node_breaker_network()
# both bus views expose the fictitious injection columns for a node/breaker network
buses = n.get_buses(all_attributes=True)
assert 'fictitious_p0' in buses.columns
assert 'fictitious_q0' in buses.columns
bus_breaker_buses = n.get_bus_breaker_view_buses(all_attributes=True)
assert 'fictitious_p0' in bus_breaker_buses.columns
assert 'fictitious_q0' in bus_breaker_buses.columns

# updating through the bus view round-trips: the value is aggregated over the calculated bus nodes
bus_id = buses.index[0]
n.update_buses(pd.DataFrame(index=[bus_id], columns=['fictitious_p0', 'fictitious_q0'], data=[[10.0, 20.0]]))
buses = n.get_buses(all_attributes=True)
assert buses['fictitious_p0'][bus_id] == 10.0
assert buses['fictitious_q0'][bus_id] == 20.0


def test_loads_data_frame():
n = pp.network.create_eurostag_tutorial_example1_network()
loads = n.get_loads(all_attributes=True)
Expand Down Expand Up @@ -2181,11 +2222,11 @@ def test_dataframe_attributes_filtering():
expected_all_attributes = pd.DataFrame(
index=pd.Series(name='id', data=['VLGEN_0', 'VLHV1_0', 'VLHV2_0', 'VLLOAD_0']),
columns=['name', 'v_mag', 'v_angle', 'connected_component', 'synchronous_component',
'voltage_level_id', 'fictitious'],
data=[['', nan, nan, 0, 0, 'VLGEN', False],
['', 380, nan, 0, 0, 'VLHV1', False],
['', 380, nan, 0, 0, 'VLHV2', False],
['', nan, nan, 0, 0, 'VLLOAD', False]])
'voltage_level_id', 'fictitious', 'fictitious_p0', 'fictitious_q0'],
data=[['', nan, nan, 0, 0, 'VLGEN', False, 0, 0],
['', 380, nan, 0, 0, 'VLHV1', False, 0, 0],
['', 380, nan, 0, 0, 'VLHV2', False, 0, 0],
['', nan, nan, 0, 0, 'VLLOAD', False, 0, 0]])
pd.testing.assert_frame_equal(expected_all_attributes, buses_all_attributes, check_dtype=False)
with pytest.raises(RuntimeError) as e:
n.get_buses(all_attributes=True, attributes=['v_mag', 'voltage_level_id'])
Expand Down
Loading