com.powsybl.dataframe.network.adders.AreaBoundariesDataframeAdder Maven / Gradle / Ivy
/**
* Copyright (c) 2024, Coreso SA (https://www.coreso.eu/) and TSCNET Services GmbH (https://www.tscnet.eu/)
* 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;
import com.powsybl.dataframe.SeriesMetadata;
import com.powsybl.dataframe.update.IntSeries;
import com.powsybl.dataframe.update.StringSeries;
import com.powsybl.dataframe.update.UpdatingDataframe;
import com.powsybl.iidm.network.*;
import com.powsybl.python.commons.PyPowsyblApiHeader;
import org.apache.commons.lang3.tuple.Pair;
import java.util.*;
import static com.powsybl.dataframe.network.adders.SeriesUtils.getRequiredStrings;
/**
* @author Damien Jeandemange
*/
public class AreaBoundariesDataframeAdder implements NetworkElementAdder {
private static final List METADATA = List.of(
SeriesMetadata.stringIndex("id"),
SeriesMetadata.strings("boundary_type"),
SeriesMetadata.strings("element"),
SeriesMetadata.strings("side"),
SeriesMetadata.booleans("ac")
);
@Override
public List> getMetadata() {
return Collections.singletonList(METADATA);
}
private static final class AreaBoundaries {
private final StringSeries ids;
private final StringSeries boundaryTypes;
private final StringSeries elements;
private final StringSeries sides;
private final IntSeries acs;
AreaBoundaries(UpdatingDataframe dataframe) {
this.ids = getRequiredStrings(dataframe, "id");
this.boundaryTypes = dataframe.getStrings("boundary_type");
this.elements = getRequiredStrings(dataframe, "element");
this.sides = dataframe.getStrings("side");
this.acs = dataframe.getInts("ac");
}
public StringSeries getIds() {
return ids;
}
public StringSeries getBoundaryTypes() {
return boundaryTypes;
}
public StringSeries getElements() {
return elements;
}
public StringSeries getSides() {
return sides;
}
public IntSeries getAcs() {
return acs;
}
}
@Override
public void addElements(Network network, List dataframes) {
UpdatingDataframe primaryTable = dataframes.get(0);
AreaBoundaries series = new AreaBoundaries(primaryTable);
Map>> danglingLineBoundaries = new HashMap<>();
Map>> terminalBoundaries = new HashMap<>();
for (int i = 0; i < primaryTable.getRowCount(); i++) {
String areaId = series.getIds().get(i);
String boundaryTypeStr = series.getBoundaryTypes() == null ? "DANGLING_LINE" : series.getBoundaryTypes().get(i);
String element = series.getElements().get(i);
String side = series.getSides() == null ? "" : series.getSides().get(i);
boolean ac = series.getAcs() == null || series.getAcs().get(i) == 1;
Area area = NetworkUtils.getAreaOrThrow(network, areaId);
// an empty element alone for an area indicates remove all boundaries in area
Connectable> connectable = element.isEmpty() ? null : NetworkUtils.getConnectableOrThrow(network, element);
if (connectable == null) {
// add an entry so that everything will be deleted for the area
danglingLineBoundaries.computeIfAbsent(area, k -> new ArrayList<>()).add(Pair.of(null, null));
terminalBoundaries.computeIfAbsent(area, k -> new ArrayList<>()).add(Pair.of(null, null));
continue;
}
PyPowsyblApiHeader.ElementType boundaryType = PyPowsyblApiHeader.ElementType.valueOf(boundaryTypeStr);
if (Objects.equals(boundaryType, PyPowsyblApiHeader.ElementType.DANGLING_LINE)) {
// Boundary modeled by a dangling line
DanglingLine danglingLine = NetworkUtils.getDanglingLineOrThrow(network, element);
danglingLineBoundaries.computeIfAbsent(area, k -> new ArrayList<>()).add(Pair.of(danglingLine, ac));
} else if (Objects.equals(boundaryType, PyPowsyblApiHeader.ElementType.TERMINAL)) {
// Boundary modeled by a terminal
Terminal terminal = NetworkUtils.getTerminalOrThrow(network, element, side);
terminalBoundaries.computeIfAbsent(area, k -> new ArrayList<>()).add(Pair.of(terminal, ac));
} else {
throw new PowsyblException("Area boundary boundary_type must be either DANGLING_LINE or TERMINAL");
}
}
// delete boundaries of involved areas
// If a given area has *only* a null boundary in the updating dataframe, this results
// in the area having all its boundaries unlinked.
Set areas = new HashSet<>(danglingLineBoundaries.keySet());
areas.addAll(terminalBoundaries.keySet());
areas.forEach(a -> a.getAreaBoundaryStream().toList()
.forEach(areaBoundary -> {
areaBoundary.getBoundary().ifPresent(a::removeAreaBoundary);
areaBoundary.getTerminal().ifPresent(a::removeAreaBoundary);
}));
// create new boundaries
danglingLineBoundaries.forEach((area, list) -> list.stream()
.filter(pair -> pair.getLeft() != null)
.forEach(pair -> area.newAreaBoundary()
.setBoundary(pair.getLeft().getBoundary())
.setAc(pair.getRight())
.add()));
terminalBoundaries.forEach((area, list) -> list.stream()
.filter(pair -> pair.getLeft() != null)
.forEach(pair -> area.newAreaBoundary()
.setTerminal(pair.getLeft())
.setAc(pair.getRight())
.add()));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy