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

Update ActivePowerControl extension #839

Merged
merged 3 commits into from
Sep 23, 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.
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 @@ -30,7 +30,10 @@ public class ActivePowerControlDataframeAdder extends AbstractSimpleAdder {
private static final List<SeriesMetadata> METADATA = List.of(
SeriesMetadata.stringIndex("id"),
SeriesMetadata.doubles("droop"),
SeriesMetadata.booleans("participate")
SeriesMetadata.booleans("participate"),
SeriesMetadata.doubles("participation_factor"),
SeriesMetadata.doubles("max_target_p"),
SeriesMetadata.doubles("min_target_p")
);

@Override
Expand All @@ -43,11 +46,17 @@ private static class ActivePowerControlSeries {
private final StringSeries id;
private final DoubleSeries droop;
private final IntSeries participate;
private final DoubleSeries participationFactor;
private final DoubleSeries maxTargetP;
private final DoubleSeries minTargetP;

ActivePowerControlSeries(UpdatingDataframe dataframe) {
this.id = dataframe.getStrings("id");
this.droop = dataframe.getDoubles("droop");
this.participate = dataframe.getInts("participate");
this.participationFactor = dataframe.getDoubles("participation_factor");
this.maxTargetP = dataframe.getDoubles("max_target_p");
this.minTargetP = dataframe.getDoubles("min_target_p");
}

void create(Network network, int row) {
Expand All @@ -57,8 +66,11 @@ void create(Network network, int row) {
throw new PowsyblException("Invalid generator id : could not find " + generatorId);
}
var adder = g.newExtension(ActivePowerControlAdder.class);
SeriesUtils.applyIfPresent(droop, row, x -> adder.withDroop((float) x));
SeriesUtils.applyIfPresent(droop, row, adder::withDroop);
SeriesUtils.applyBooleanIfPresent(participate, row, adder::withParticipate);
SeriesUtils.applyIfPresent(participationFactor, row, adder::withParticipationFactor);
SeriesUtils.applyIfPresent(maxTargetP, row, adder::withMaxTargetP);
SeriesUtils.applyIfPresent(minTargetP, row, adder::withMinTargetP);
adder.add();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,12 @@ public String getExtensionName() {
public ExtensionInformation getExtensionInformation() {
return new ExtensionInformation(ActivePowerControl.NAME,
"Provides information about the participation of generators to balancing",
"index : id (str), participate (bool), droop (float)");
"index : id (str), " +
"participate (bool), " +
"droop (float), " +
"participation_factor (float), " +
"max_target_p (float), " +
"min_target_p (float)");
}

private Stream<ActivePowerControl> itemsStream(Network network) {
Expand All @@ -62,8 +67,11 @@ private ActivePowerControl getOrThrow(Network network, String id) {
public NetworkDataframeMapper createMapper() {
return NetworkDataframeMapperBuilder.ofStream(this::itemsStream, this::getOrThrow)
.stringsIndex("id", ext -> ((Identifiable<?>) ext.getExtendable()).getId())
.doubles("droop", (apc, context) -> apc.getDroop(), (apc, droop, context) -> apc.setDroop((float) droop))
.doubles("droop", (apc, context) -> apc.getDroop(), (apc, droop, context) -> apc.setDroop(droop))
.booleans("participate", ActivePowerControl::isParticipate, ActivePowerControl::setParticipate)
.doubles("participation_factor", (apc, context) -> apc.getParticipationFactor(), (apc, participationFactor, context) -> apc.setParticipationFactor(participationFactor))
.doubles("max_target_p", (apc, context) -> apc.getMaxTargetP().orElse(Double.NaN), (apc, maxTargetP, context) -> apc.setMaxTargetP(maxTargetP))
.doubles("min_target_p", (apc, context) -> apc.getMinTargetP().orElse(Double.NaN), (apc, minTargetP, context) -> apc.setMinTargetP(minTargetP))
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public static Network createEurostagTutorialExample1WithApcExtension() {
network.getGenerator("GEN")
.newExtension(ActivePowerControlAdder.class)
.withParticipate(true)
.withDroop(1.1f)
.withDroop(1.1)
.add();
return network;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,24 +163,45 @@ void generatorsExtension() {
List<Series> series = createExtensionDataFrame("activePowerControl", network);
assertThat(series)
.extracting(Series::getName)
.containsExactly("id", "droop", "participate");
.containsExactly("id", "droop", "participate",
"participation_factor",
"max_target_p",
"min_target_p");
assertThat(series.get(1).getDoubles())
.containsExactly(1.1f);
.containsExactly(1.1);
assertThat(series.get(2).getBooleans())
.containsExactly(true);
assertThat(series.get(3).getDoubles())
.containsExactly(Double.NaN);
assertThat(series.get(4).getDoubles())
.containsExactly(Double.NaN);
assertThat(series.get(5).getDoubles())
.containsExactly(Double.NaN);

DefaultUpdatingDataframe dataframe = new DefaultUpdatingDataframe(1);
dataframe.addSeries("id", true, new TestStringSeries("GEN"));
dataframe.addSeries("droop", false, new TestDoubleSeries(1.2));
dataframe.addSeries("participation_factor", false, new TestDoubleSeries(1.5));
dataframe.addSeries("max_target_p", false, new TestDoubleSeries(900.));
dataframe.addSeries("min_target_p", false, new TestDoubleSeries(200.));
updateExtension("activePowerControl", network, dataframe);
series = createExtensionDataFrame("activePowerControl", network);
assertThat(series)
.extracting(Series::getName)
.containsExactly("id", "droop", "participate");
.containsExactly("id", "droop", "participate",
"participation_factor",
"max_target_p",
"min_target_p");
assertThat(series.get(1).getDoubles())
.containsExactly(1.2f);
.containsExactly(1.2);
assertThat(series.get(2).getBooleans())
.containsExactly(true);
assertThat(series.get(3).getDoubles())
.containsExactly(1.5);
assertThat(series.get(4).getDoubles())
.containsExactly(900.);
assertThat(series.get(5).getDoubles())
.containsExactly(200.);

NetworkExtensions.removeExtensions(network, "activePowerControl",
network.getGeneratorStream().map(Generator::getNameOrId).collect(Collectors.toList()));
Expand Down
25 changes: 21 additions & 4 deletions tests/test_network_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,33 @@ def test_extensions():
assert len(generators_extensions) == 1
assert generators_extensions['participate']['GEN']
assert generators_extensions['droop']['GEN'] == pytest.approx(1.1, abs=1e-3)
assert np.isnan(generators_extensions['participation_factor']['GEN'])
assert np.isnan(generators_extensions['max_target_p']['GEN'])
assert np.isnan(generators_extensions['min_target_p']['GEN'])
assert n.get_extensions('hvdcOperatorActivePowerRange').empty


def test_update_extensions():
n = pn._create_network('eurostag_tutorial_example1_with_apc_extension')
n.update_extensions('activePowerControl', pd.DataFrame.from_records(index='id', data=[
{'id': 'GEN', 'droop': 1.2}
{'id': 'GEN', 'droop': 1.2, 'participation_factor': 1.5, 'max_target_p': 900., 'min_target_p': 200.}
]))
generators_extensions = n.get_extensions('activePowerControl')
assert len(generators_extensions) == 1
assert generators_extensions['participate']['GEN']
assert generators_extensions['droop']['GEN'] == pytest.approx(1.2, abs=1e-3)
n.update_extensions('activePowerControl', id='GEN', droop=1.4)
assert generators_extensions['participation_factor']['GEN'] == pytest.approx(1.5, abs=1e-3)
assert generators_extensions['max_target_p']['GEN'] == pytest.approx(900., abs=1e-3)
assert generators_extensions['min_target_p']['GEN'] == pytest.approx(200., abs=1e-3)
n.update_extensions('activePowerControl',
id='GEN', droop=1.4, participation_factor=1.8, max_target_p=800., min_target_p=150.)
generators_extensions = n.get_extensions('activePowerControl')
assert len(generators_extensions) == 1
assert generators_extensions['participate']['GEN']
assert generators_extensions['droop']['GEN'] == pytest.approx(1.4, abs=1e-3)
assert generators_extensions['participation_factor']['GEN'] == pytest.approx(1.8, abs=1e-3)
assert generators_extensions['max_target_p']['GEN'] == pytest.approx(800., abs=1e-3)
assert generators_extensions['min_target_p']['GEN'] == pytest.approx(150., abs=1e-3)


def test_remove_extensions():
Expand All @@ -55,18 +65,25 @@ def test_remove_extensions():
def test_create_extensions():
n = pn._create_network('eurostag_tutorial_example1')
n.create_extensions('activePowerControl', pd.DataFrame.from_records(index='id', data=[
{'id': 'GEN', 'droop': 1.2, 'participate': True}
{'id': 'GEN', 'droop': 1.2, 'participate': True, 'participation_factor': 1.5,
'max_target_p': 900., 'min_target_p': 200.}
]))
generators_extensions = n.get_extensions('activePowerControl')
assert len(generators_extensions) == 1
assert generators_extensions['participate']['GEN']
assert generators_extensions['droop']['GEN'] == pytest.approx(1.2, abs=1e-3)
assert generators_extensions['participation_factor']['GEN'] == pytest.approx(1.5, abs=1e-3)
assert generators_extensions['max_target_p']['GEN'] == pytest.approx(900., abs=1e-3)
assert generators_extensions['min_target_p']['GEN'] == pytest.approx(200., abs=1e-3)

n.create_extensions('activePowerControl', id='GEN2', droop=1.3, participate=False)
generators_extensions = n.get_extensions('activePowerControl')
assert len(generators_extensions) == 2
assert not generators_extensions['participate']['GEN2']
assert generators_extensions['droop']['GEN2'] == pytest.approx(1.3, abs=1e-3)
assert np.isnan(generators_extensions['participation_factor']['GEN2'])
assert np.isnan(generators_extensions['max_target_p']['GEN2'])
assert np.isnan(generators_extensions['min_target_p']['GEN2'])


def test_entsoe_area():
Expand Down Expand Up @@ -476,7 +493,7 @@ def test_get_extensions_information():
assert extensions_information.loc['hvdcOperatorActivePowerRange']['detail'] == ''
assert extensions_information.loc['hvdcOperatorActivePowerRange']['attributes'] == 'index : id (str), opr_from_cs1_to_cs2 (float), opr_from_cs2_to_cs1 (float)'
assert extensions_information.loc['activePowerControl']['detail'] == 'Provides information about the participation of generators to balancing'
assert extensions_information.loc['activePowerControl']['attributes'] == 'index : id (str), participate (bool), droop (float)'
assert extensions_information.loc['activePowerControl']['attributes'] == 'index : id (str), participate (bool), droop (float), participation_factor (float), max_target_p (float), min_target_p (float)'
assert extensions_information.loc['entsoeCategory']['detail'] == 'Provides Entsoe category code for a generator'
assert extensions_information.loc['entsoeCategory']['attributes'] == 'index : id (str), code (int)'
assert extensions_information.loc['entsoeArea']['detail'] == 'Provides Entsoe geographical code for a substation'
Expand Down
Loading