Skip to content

Commit

Permalink
Adding dangling line's generation part mapping (#821)
Browse files Browse the repository at this point in the history
Signed-off-by: Hugo KULESZA <[email protected]>
  • Loading branch information
HugoKulesza authored Nov 20, 2024
1 parent b42ca61 commit 6d78722
Show file tree
Hide file tree
Showing 13 changed files with 321 additions and 28 deletions.
1 change: 1 addition & 0 deletions cpp/pypowsybl-cpp/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ PYBIND11_MODULE(_pypowsybl, m) {
.value("NON_LINEAR_SHUNT_COMPENSATOR_SECTION", element_type::NON_LINEAR_SHUNT_COMPENSATOR_SECTION)
.value("LINEAR_SHUNT_COMPENSATOR_SECTION", element_type::LINEAR_SHUNT_COMPENSATOR_SECTION)
.value("DANGLING_LINE", element_type::DANGLING_LINE)
.value("DANGLING_LINE_GENERATION", element_type::DANGLING_LINE_GENERATION)
.value("TIE_LINE", element_type::TIE_LINE)
.value("LCC_CONVERTER_STATION", element_type::LCC_CONVERTER_STATION)
.value("VSC_CONVERTER_STATION", element_type::VSC_CONVERTER_STATION)
Expand Down
1 change: 1 addition & 0 deletions cpp/pypowsybl-java/powsybl-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ typedef enum {
NON_LINEAR_SHUNT_COMPENSATOR_SECTION,
LINEAR_SHUNT_COMPENSATOR_SECTION,
DANGLING_LINE,
DANGLING_LINE_GENERATION,
TIE_LINE,
LCC_CONVERTER_STATION,
VSC_CONVERTER_STATION,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public enum DataframeElementType {
NON_LINEAR_SHUNT_COMPENSATOR_SECTION,
LINEAR_SHUNT_COMPENSATOR_SECTION,
DANGLING_LINE,
DANGLING_LINE_GENERATION,
TIE_LINE,
LCC_CONVERTER_STATION,
VSC_CONVERTER_STATION,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ private static Map<DataframeElementType, NetworkDataframeMapper> createMappers()
mappers.put(DataframeElementType.NON_LINEAR_SHUNT_COMPENSATOR_SECTION, shuntsNonLinear());
mappers.put(DataframeElementType.LINEAR_SHUNT_COMPENSATOR_SECTION, linearShuntsSections());
mappers.put(DataframeElementType.DANGLING_LINE, danglingLines());
mappers.put(DataframeElementType.DANGLING_LINE_GENERATION, danglingLinesGeneration());
mappers.put(DataframeElementType.TIE_LINE, tieLines());
mappers.put(DataframeElementType.LCC_CONVERTER_STATION, lccs());
mappers.put(DataframeElementType.VSC_CONVERTER_STATION, vscs());
Expand Down Expand Up @@ -653,6 +654,25 @@ static NetworkDataframeMapper danglingLines() {
.build();
}

static NetworkDataframeMapper danglingLinesGeneration() {
return NetworkDataframeMapperBuilder.ofStream(network -> network.getDanglingLineStream().filter(dl -> Optional.ofNullable(dl.getGeneration()).isPresent()),
getOrThrow(Network::getDanglingLine, "Dangling line with generation"))
.stringsIndex("id", DanglingLine::getId)
.doubles("min_p", (dl, context) -> perUnitPQ(context, dl.getGeneration().getMinP()),
(dl, minP, context) -> dl.getGeneration().setMinP(unPerUnitPQ(context, minP)))
.doubles("max_p", (dl, context) -> perUnitPQ(context, dl.getGeneration().getMaxP()),
(dl, maxP, context) -> dl.getGeneration().setMaxP(unPerUnitPQ(context, maxP)))
.doubles("target_p", (dl, context) -> perUnitPQ(context, dl.getGeneration().getTargetP()),
(dl, targetP, context) -> dl.getGeneration().setTargetP(unPerUnitPQ(context, targetP)))
.doubles("target_q", (dl, context) -> perUnitPQ(context, dl.getGeneration().getTargetQ()),
(dl, targetQ, context) -> dl.getGeneration().setTargetQ(unPerUnitPQ(context, targetQ)))
.doubles("target_v", (dl, context) -> perUnitV(context, dl.getGeneration().getTargetV(), dl.getTerminal()),
(dl, targetV, context) -> dl.getGeneration().setTargetV(unPerUnitV(context, targetV, dl.getTerminal())))
.booleans("voltage_regulator_on", dl -> dl.getGeneration().isVoltageRegulationOn(),
(dl, voltageRegulatorOn) -> dl.getGeneration().setVoltageRegulationOn(voltageRegulatorOn))
.build();
}

static NetworkDataframeMapper tieLines() {
return NetworkDataframeMapperBuilder.ofStream(Network::getTieLineStream, getOrThrow(Network::getTieLine, "Tie line"))
.stringsIndex("id", TieLine::getId)
Expand Down Expand Up @@ -1350,6 +1370,5 @@ private static Stream<Pair<Area, AreaBoundary>> areaBoundariesData(Network netwo
.flatMap(area -> area.getAreaBoundaryStream()
.map(areaBoundary -> Pair.of(area, areaBoundary)));
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,32 @@
*/
package com.powsybl.dataframe.network.adders;

import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.report.ReportNode;
import com.powsybl.dataframe.SeriesMetadata;
import com.powsybl.dataframe.update.DoubleSeries;
import com.powsybl.dataframe.update.IntSeries;
import com.powsybl.dataframe.update.StringSeries;
import com.powsybl.dataframe.update.UpdatingDataframe;
import com.powsybl.iidm.modification.topology.CreateFeederBay;
import com.powsybl.iidm.modification.topology.CreateFeederBayBuilder;
import com.powsybl.iidm.network.DanglingLineAdder;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.VoltageLevel;
import com.powsybl.iidm.network.extensions.ConnectablePosition;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.*;

import static com.powsybl.dataframe.network.adders.NetworkUtils.getVoltageLevelOrThrowWithBusOrBusbarSectionId;
import static com.powsybl.dataframe.network.adders.SeriesUtils.applyBooleanIfPresent;
import static com.powsybl.dataframe.network.adders.SeriesUtils.applyIfPresent;

/**
* @author Yichen TANG {@literal <yichen.tang at rte-france.com>}
* @author Etienne Lesot {@literal <etienne.lesot at rte-france.com>}
* @author Sylvain Leclerc {@literal <[email protected]>}
*/
public class DanglingLineDataframeAdder extends AbstractSimpleAdder {
public class DanglingLineDataframeAdder implements NetworkElementAdder {

private static final List<SeriesMetadata> METADATA = List.of(
SeriesMetadata.stringIndex("id"),
Expand All @@ -46,9 +50,19 @@ public class DanglingLineDataframeAdder extends AbstractSimpleAdder {
SeriesMetadata.strings("pairing_key")
);

private static final List<SeriesMetadata> GENERATION_METADATA = List.of(
SeriesMetadata.stringIndex("id"),
SeriesMetadata.doubles("min_p"),
SeriesMetadata.doubles("max_p"),
SeriesMetadata.doubles("target_p"),
SeriesMetadata.doubles("target_q"),
SeriesMetadata.doubles("target_v"),
SeriesMetadata.booleans("voltage_regulator_on")
);

@Override
public List<List<SeriesMetadata>> getMetadata() {
return Collections.singletonList(METADATA);
return List.of(METADATA, GENERATION_METADATA);
}

private static class DanglingLineSeries extends InjectionSeries {
Expand All @@ -63,7 +77,15 @@ private static class DanglingLineSeries extends InjectionSeries {
private final StringSeries busOrBusbarSections;
private final StringSeries pairingKey;

DanglingLineSeries(UpdatingDataframe dataframe) {
private final Map<String, Integer> generationIndexes;
private final DoubleSeries minP;
private final DoubleSeries maxP;
private final DoubleSeries targetP;
private final DoubleSeries targetQ;
private final DoubleSeries targetV;
private final IntSeries voltageRegulatorOn;

DanglingLineSeries(UpdatingDataframe dataframe, UpdatingDataframe generationDataframe) {
super(dataframe);
this.voltageLevels = dataframe.getStrings("voltage_level_id");
this.p0 = dataframe.getDoubles("p0");
Expand All @@ -74,6 +96,24 @@ private static class DanglingLineSeries extends InjectionSeries {
this.b = dataframe.getDoubles("b");
this.busOrBusbarSections = dataframe.getStrings("bus_or_busbar_section_id");
this.pairingKey = dataframe.getStrings("pairing_key");

if (generationDataframe != null && generationDataframe.getRowCount() > 0) {
this.minP = generationDataframe.getDoubles("min_p");
this.maxP = generationDataframe.getDoubles("max_p");
this.targetP = generationDataframe.getDoubles("target_p");
this.targetQ = generationDataframe.getDoubles("target_q");
this.targetV = generationDataframe.getDoubles("target_v");
this.voltageRegulatorOn = generationDataframe.getInts("voltage_regulator_on");
this.generationIndexes = getGenerationIndexes(generationDataframe);
} else {
this.minP = null;
this.maxP = null;
this.targetP = null;
this.targetQ = null;
this.targetV = null;
this.voltageRegulatorOn = null;
this.generationIndexes = null;
}
}

Optional<DanglingLineAdder> createAdder(Network network, int row, boolean throwException) {
Expand All @@ -89,21 +129,91 @@ Optional<DanglingLineAdder> createAdder(Network network, int row, boolean throwE
applyIfPresent(g, row, adder::setG);
applyIfPresent(b, row, adder::setB);
applyIfPresent(pairingKey, row, adder::setPairingKey);
addGenerationIfPresent(adder, row);
return Optional.of(adder);
} else {
return Optional.empty();
}
}

private void addGenerationIfPresent(DanglingLineAdder adder, int row) {
if (generationIndexes == null) {
return;
}
String id = ids.get(row);
Integer generationRow = generationIndexes.get(id);
if (generationRow != null) {
DanglingLineAdder.GenerationAdder genAdder = adder.newGeneration();
applyIfPresent(minP, generationRow, genAdder::setMinP);
applyIfPresent(maxP, generationRow, genAdder::setMaxP);
applyIfPresent(targetP, generationRow, genAdder::setTargetP);
applyIfPresent(targetQ, generationRow, genAdder::setTargetQ);
applyIfPresent(targetV, generationRow, genAdder::setTargetV);
applyBooleanIfPresent(voltageRegulatorOn, generationRow, genAdder::setVoltageRegulationOn);
genAdder.add();
}
}

/**
* Mapping shunt ID --> index of line in dataframe
*/
private static Map<String, Integer> getGenerationIndexes(UpdatingDataframe generationDf) {
StringSeries ids = generationDf.getStrings("id");
if (ids == null) {
throw new PowsyblException("Dangling line generation dataframe: id is not set");
}
Map<String, Integer> indexes = new HashMap<>();
for (int generationIndex = 0; generationIndex < generationDf.getRowCount(); generationIndex++) {
String danglingLineId = ids.get(generationIndex);
indexes.put(danglingLineId, generationIndex);
}
return indexes;
}

void create(Network network, int row, boolean throwException) {
Optional<DanglingLineAdder> adder = createAdder(network, row, throwException);
adder.ifPresent(DanglingLineAdder::add);
}

void createWithBay(Network network, int row, UpdatingDataframe primaryDataframe, boolean throwException, ReportNode reportNode) {
Optional<DanglingLineAdder> adder = createAdder(network, row, throwException);
adder.ifPresent(presentAdder -> addWithBay(network, row, primaryDataframe, presentAdder, throwException, reportNode));
}

void addWithBay(Network network, int row, UpdatingDataframe dataframe, DanglingLineAdder adder, boolean throwException, ReportNode reportNode) {
String busOrBusbarSectionId = busOrBusbarSections.get(row);
OptionalInt injectionPositionOrder = dataframe.getIntValue("position_order", row);
ConnectablePosition.Direction direction = ConnectablePosition.Direction.valueOf(dataframe.getStringValue("direction", row).orElse("BOTTOM"));
CreateFeederBayBuilder builder = new CreateFeederBayBuilder()
.withInjectionAdder(adder)
.withBusOrBusbarSectionId(busOrBusbarSectionId)
.withInjectionDirection(direction);
if (injectionPositionOrder.isPresent()) {
builder.withInjectionPositionOrder(injectionPositionOrder.getAsInt());
}
CreateFeederBay modification = builder.build();
modification.apply(network, throwException, reportNode == null ? ReportNode.NO_OP : reportNode);
}
}

@Override
public void addElements(Network network, UpdatingDataframe dataframe, AdditionStrategy additionStrategy, boolean throwException, ReportNode reportNode) {
DanglingLineSeries series = new DanglingLineSeries(dataframe);
public void addElements(Network network, List<UpdatingDataframe> dataframes) {
UpdatingDataframe dataframe = dataframes.get(0);
UpdatingDataframe generationDataframe = dataframes.get(1);
DanglingLineSeries series = new DanglingLineSeries(dataframe, generationDataframe);
for (int row = 0; row < dataframe.getRowCount(); row++) {
Optional<DanglingLineAdder> adder = series.createAdder(network, row, throwException);
if (adder.isPresent()) {
additionStrategy.add(network, dataframe, adder.get(), row, throwException, reportNode);
}
series.create(network, row, true);
}
}

@Override
public void addElementsWithBay(Network network, List<UpdatingDataframe> dataframes, boolean throwException, ReportNode reportNode) {
UpdatingDataframe dataframe = dataframes.get(0);
UpdatingDataframe generationDataframe = dataframes.get(1);
DanglingLineSeries series = new DanglingLineSeries(dataframe, generationDataframe);
for (int row = 0; row < dataframe.getRowCount(); row++) {
series.createWithBay(network, row, dataframe, true, reportNode);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,7 @@ public enum ElementType {
NON_LINEAR_SHUNT_COMPENSATOR_SECTION,
LINEAR_SHUNT_COMPENSATOR_SECTION,
DANGLING_LINE,
DANGLING_LINE_GENERATION,
TIE_LINE,
LCC_CONVERTER_STATION,
VSC_CONVERTER_STATION,
Expand Down
2 changes: 2 additions & 0 deletions java/src/main/java/com/powsybl/python/commons/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ public static PyPowsyblApiHeader.ElementType convert(DataframeElementType type)
case BATTERY -> PyPowsyblApiHeader.ElementType.BATTERY;
case SHUNT_COMPENSATOR -> PyPowsyblApiHeader.ElementType.SHUNT_COMPENSATOR;
case DANGLING_LINE -> PyPowsyblApiHeader.ElementType.DANGLING_LINE;
case DANGLING_LINE_GENERATION -> PyPowsyblApiHeader.ElementType.DANGLING_LINE_GENERATION;
case TIE_LINE -> PyPowsyblApiHeader.ElementType.TIE_LINE;
case LCC_CONVERTER_STATION -> PyPowsyblApiHeader.ElementType.LCC_CONVERTER_STATION;
case VSC_CONVERTER_STATION -> PyPowsyblApiHeader.ElementType.VSC_CONVERTER_STATION;
Expand Down Expand Up @@ -239,6 +240,7 @@ public static DataframeElementType convert(PyPowsyblApiHeader.ElementType type)
case BATTERY -> DataframeElementType.BATTERY;
case SHUNT_COMPENSATOR -> DataframeElementType.SHUNT_COMPENSATOR;
case DANGLING_LINE -> DataframeElementType.DANGLING_LINE;
case DANGLING_LINE_GENERATION -> DataframeElementType.DANGLING_LINE_GENERATION;
case TIE_LINE -> DataframeElementType.TIE_LINE;
case LCC_CONVERTER_STATION -> DataframeElementType.LCC_CONVERTER_STATION;
case VSC_CONVERTER_STATION -> DataframeElementType.VSC_CONVERTER_STATION;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -333,9 +333,19 @@ void danglingLines() {
.extracting(Series::getName)
.containsExactly("id", "name", "r", "x", "g", "b", "p0", "q0", "p", "q", "i",
"boundary_p", "boundary_q", "boundary_v_mag", "boundary_v_angle",
"voltage_level_id", "bus_id", "bus_breaker_bus_id", "node", "connected",
"pairing_key", "ucte_xnode_code", "paired", "fictitious", "tie_line_id",
"selected_limits_group");
"voltage_level_id", "bus_id", "bus_breaker_bus_id", "node", "connected", "pairing_key",
"ucte_xnode_code", "paired", "fictitious", "tie_line_id", "selected_limits_group");
}

@Test
void danglingLinesGeneration() {
Network network = EurostagTutorialExample1Factory.create();
List<Series> series = createDataFrame(DANGLING_LINE_GENERATION, network);

assertThat(series)
.extracting(Series::getName)
.containsExactly("id", "min_p", "max_p", "target_p", "target_q",
"target_v", "voltage_regulator_on");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,43 @@ void danglingLine() {
addDoubleColumn(dataframe, "b", Math.pow(10, -6) * 4);
addDoubleColumn(dataframe, "p0", 102d);
addDoubleColumn(dataframe, "q0", 151d);
NetworkElementAdders.addElements(DataframeElementType.DANGLING_LINE, network, singletonList(dataframe));
var emptyGenerationDataframe = new DefaultUpdatingDataframe(0);
NetworkElementAdders.addElements(DataframeElementType.DANGLING_LINE, network, List.of(dataframe, emptyGenerationDataframe));
assertEquals(2, network.getDanglingLineCount());
}

@Test
void danglingLineWithGeneration() {
var network = DanglingLineNetworkFactory.create();
var dataframe = new DefaultUpdatingDataframe(1);
addStringColumn(dataframe, "id", "dl2");
addStringColumn(dataframe, "name", "name-dl2");
addStringColumn(dataframe, "connectable_bus_id", "BUS");
addStringColumn(dataframe, "bus_id", "BUS");
addStringColumn(dataframe, "voltage_level_id", "VL");
addDoubleColumn(dataframe, "r", 0.6d);
addDoubleColumn(dataframe, "x", 1d);
addDoubleColumn(dataframe, "g", Math.pow(10, -6));
addDoubleColumn(dataframe, "b", Math.pow(10, -6) * 4);
addDoubleColumn(dataframe, "p0", 102d);
addDoubleColumn(dataframe, "q0", 151d);

var generationDataframe = new DefaultUpdatingDataframe(1);
addStringColumn(generationDataframe, "id", "dl2");
addDoubleColumn(generationDataframe, "min_p", 0);
addDoubleColumn(generationDataframe, "max_p", 200d);
addDoubleColumn(generationDataframe, "target_p", 102d);
addDoubleColumn(generationDataframe, "target_q", 151d);
addDoubleColumn(generationDataframe, "target_v", 100d);
addIntColumn(generationDataframe, "voltage_regulator_on", 1);
NetworkElementAdders.addElements(DataframeElementType.DANGLING_LINE, network, List.of(dataframe, generationDataframe));

assertEquals(2, network.getDanglingLineCount());
DanglingLine dl = network.getDanglingLine("dl2");
assertTrue(Optional.ofNullable(dl.getGeneration()).isPresent());
assertTrue(dl.getGeneration().isVoltageRegulationOn());
}

@Test
void busbar() {
var network = HvdcTestNetwork.createBase();
Expand Down
1 change: 1 addition & 0 deletions pypowsybl/_pypowsybl.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ class ElementType:
BUS_FROM_BUS_BREAKER_VIEW: ClassVar[ElementType] = ...
BUSBAR_SECTION: ClassVar[ElementType] = ...
DANGLING_LINE: ClassVar[ElementType] = ...
DANGLING_LINE_GENERATION: ClassVar[ElementType] = ...
TIE_LINE: ClassVar[ElementType] = ...
GENERATOR: ClassVar[ElementType] = ...
HVDC_LINE: ClassVar[ElementType] = ...
Expand Down
Loading

0 comments on commit 6d78722

Please sign in to comment.