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

[CGMES balances adjustment] Migrate from cgmes.extensions.CgmesControlArea to iidm.network.Area #178

Merged
merged 9 commits into from
Feb 26, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
@@ -0,0 +1,49 @@
/**
* Copyright (c) 2025, 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.entsoe.cgmes.balances_adjustment.util;

import com.powsybl.iidm.network.*;

import java.util.Optional;

/**
* @author Hugo Schindler{@literal <hugo.schindler at rte-france.com>}
*/
public final class CgmesAreaUtils {
private CgmesAreaUtils() {
// Utility class
}

static boolean hasAreaBoundaries(Area area) {
return area.getAreaBoundaryStream().map(AreaBoundary::getBoundary).anyMatch(Optional::isPresent);
}

static boolean hasAreaBoundaryTerminals(Area area) {
return area.getAreaBoundaryStream().map(AreaBoundary::getTerminal).anyMatch(Optional::isPresent);
}

static boolean isIdInAreaBoundaryTerminals(String elementId, Area area) {
return area.getAreaBoundaryStream()
.map(AreaBoundary::getTerminal)
.filter(Optional::isPresent)
.map(Optional::get)
.map(Terminal::getConnectable)
.map(Identifiable::getId)
.anyMatch(terminalId -> terminalId.equals(elementId));
}

static boolean isIdInAreaBoundariesDanglingLines(String elementId, Area area) {
return area.getAreaBoundaryStream()
.map(AreaBoundary::getBoundary)
.filter(Optional::isPresent)
.map(Optional::get)
.map(Boundary::getDanglingLine)
.map(Identifiable::getId)
.anyMatch(danglingLineId -> danglingLineId.equals(elementId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@
package com.powsybl.entsoe.cgmes.balances_adjustment.util;

import com.powsybl.balances_adjustment.util.NetworkArea;
import com.powsybl.cgmes.extensions.CgmesControlArea;
import com.powsybl.cgmes.extensions.CgmesDanglingLineBoundaryNode;
import com.powsybl.iidm.network.Bus;
import com.powsybl.iidm.network.Area;
import com.powsybl.iidm.network.DanglingLine;
import com.powsybl.iidm.network.Network;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
Expand All @@ -26,22 +23,16 @@ class CgmesBoundariesArea implements NetworkArea {

private final Set<DanglingLine> danglingLinesCache;

CgmesBoundariesArea(Network network, List<CgmesControlArea> areas) {
CgmesBoundariesArea(Network network, List<Area> areas) {
danglingLinesCache = network.getDanglingLineStream()
.filter(dl -> dl.getExtension(CgmesDanglingLineBoundaryNode.class) == null || !dl.getExtension(CgmesDanglingLineBoundaryNode.class).isHvdc())
.filter(dl -> dl.getTerminal().getBusView().getBus() != null && dl.getTerminal().getBusView().getBus().isInMainSynchronousComponent())
.filter(dl -> areas.isEmpty() || areas.stream().anyMatch(area -> area.getTerminals().stream().anyMatch(t -> t.getConnectable().getId().equals(dl.getId()))
|| area.getBoundaries().stream().anyMatch(b -> b.getDanglingLine().getId().equals(dl.getId()))))
.filter(dl -> areas.isEmpty() || areas.stream().anyMatch(area -> CgmesAreaUtils.isIdInAreaBoundaryTerminals(dl.getId(), area) || CgmesAreaUtils.isIdInAreaBoundariesDanglingLines(dl.getId(), area)))
.collect(Collectors.toSet());
}

@Override
public double getNetPosition() {
return danglingLinesCache.parallelStream().mapToDouble(dl -> dl.getTerminal().isConnected() ? -dl.getBoundary().getP() : 0).sum();
}

@Override
public Collection<Bus> getContainedBusViewBuses() {
return Collections.emptyList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import com.powsybl.balances_adjustment.util.NetworkArea;
import com.powsybl.balances_adjustment.util.NetworkAreaFactory;
import com.powsybl.cgmes.extensions.CgmesControlArea;
import com.powsybl.iidm.network.Area;
import com.powsybl.iidm.network.Network;

import java.util.ArrayList;
Expand All @@ -20,12 +20,12 @@
*/
public class CgmesBoundariesAreaFactory implements NetworkAreaFactory {

private final List<CgmesControlArea> areas = new ArrayList<>();
private final List<Area> areas = new ArrayList<>();

public CgmesBoundariesAreaFactory() {
}

public CgmesBoundariesAreaFactory(List<CgmesControlArea> areas) {
public CgmesBoundariesAreaFactory(List<Area> areas) {
this.areas.addAll(Objects.requireNonNull(areas));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
package com.powsybl.entsoe.cgmes.balances_adjustment.util;

import com.powsybl.balances_adjustment.util.NetworkArea;
import com.powsybl.cgmes.extensions.CgmesControlArea;
import com.powsybl.cgmes.extensions.CgmesDanglingLineBoundaryNode;
import com.powsybl.iidm.network.*;

Expand All @@ -26,7 +25,7 @@ class CgmesVoltageLevelsArea implements NetworkArea {

private final Set<Bus> busesCache;

CgmesVoltageLevelsArea(Network network, CgmesControlArea area, List<String> excludedXnodes, List<String> voltageLevelIds) {
CgmesVoltageLevelsArea(Network network, Area area, List<String> excludedXnodes, List<String> voltageLevelIds) {
this.voltageLevelIds.addAll(voltageLevelIds);

danglingLineBordersCache = createDanglingLinesCache(network, area, excludedXnodes);
Expand All @@ -38,14 +37,15 @@ class CgmesVoltageLevelsArea implements NetworkArea {
.collect(Collectors.toSet());
}

private List<DanglingLine> createDanglingLinesCache(Network network, CgmesControlArea area, List<String> excludedXnodes) {
private List<DanglingLine> createDanglingLinesCache(Network network, Area area, List<String> excludedXnodes) {
return network.getDanglingLineStream()
.filter(this::isAreaBorder)
.filter(dl -> dl.getTerminal().getBusView().getBus() != null && dl.getTerminal().getBusView().getBus().isInMainSynchronousComponent()) // Only consider connected dangling lines in main synchronous component (other synchronous components are not considered)
.filter(dl -> dl.getExtension(CgmesDanglingLineBoundaryNode.class) == null || !dl.getExtension(CgmesDanglingLineBoundaryNode.class).isHvdc()) // Dangling lines connected to DC boundary points are disregarded
.filter(dl -> {
if (area != null && (!area.getTerminals().isEmpty() || !area.getBoundaries().isEmpty())) { // if CgmesControlArea is defined, dangling lines with no associated tie flows are disregarded
return area.getTerminals().stream().anyMatch(t -> t.getConnectable().getId().equals(dl.getId())) || area.getBoundaries().stream().anyMatch(bd -> bd.getDanglingLine().getId().equals(dl.getId()));
if (area != null && (CgmesAreaUtils.hasAreaBoundaryTerminals(area) || CgmesAreaUtils.hasAreaBoundaries(area))) { // if CgmesControlArea is defined, dangling lines with no associated tie flows are disregarded
return CgmesAreaUtils.isIdInAreaBoundaryTerminals(dl.getId(), area) ||
CgmesAreaUtils.isIdInAreaBoundariesDanglingLines(dl.getId(), area);
}
return true;
})
Expand All @@ -58,15 +58,15 @@ private List<DanglingLine> createDanglingLinesCache(Network network, CgmesContro
.toList();
}

private List<? extends Branch<?>> createBranchesCache(Network network, CgmesControlArea area) {
private List<? extends Branch<?>> createBranchesCache(Network network, Area area) {
return network.getLineStream()
.filter(this::isAreaBorder)
.filter(b -> b.getTerminal1().getBusView().getBus() != null && b.getTerminal1().getBusView().getBus().isInMainSynchronousComponent()
&& b.getTerminal2().getBusView().getBus() != null && b.getTerminal2().getBusView().getBus().isInMainSynchronousComponent()) // Only consider branches connected on both sides and in main synchronous component (other synchronous components are not considered)
.filter(b -> !b.hasProperty("isHvdc")) // necessary as extensions of merged lines are not well handled. FIXME: when it is merged on mergingview, this should be deleted.
.filter(b -> {
if (area != null && (!area.getTerminals().isEmpty() || !area.getBoundaries().isEmpty())) { // if CgmesControlArea is defined, branches with no associated tie flows are disregarded
return area.getTerminals().stream().anyMatch(t -> b.getId().contains(t.getConnectable().getId()));
if (area != null && CgmesAreaUtils.hasAreaBoundaryTerminals(area)) { // if CgmesControlArea is defined, branches with no associated tie flows are disregarded
return CgmesAreaUtils.isIdInAreaBoundaryTerminals(b.getId(), area);
}
return true;
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import com.powsybl.balances_adjustment.util.NetworkArea;
import com.powsybl.balances_adjustment.util.NetworkAreaFactory;
import com.powsybl.cgmes.extensions.CgmesControlArea;
import com.powsybl.iidm.network.Area;
import com.powsybl.iidm.network.Network;

import java.util.Arrays;
Expand All @@ -20,23 +20,23 @@
*/
public class CgmesVoltageLevelsAreaFactory implements NetworkAreaFactory {

private final CgmesControlArea area;
private final Area area;
private final List<String> excludedXnodes;
private final List<String> voltageLevelIds;

public CgmesVoltageLevelsAreaFactory(CgmesControlArea area, String... voltageLevelIds) {
public CgmesVoltageLevelsAreaFactory(Area area, String... voltageLevelIds) {
this(area, Arrays.asList(voltageLevelIds));
}

public CgmesVoltageLevelsAreaFactory(CgmesControlArea area, List<String> voltageLevelIds) {
public CgmesVoltageLevelsAreaFactory(Area area, List<String> voltageLevelIds) {
this(area, null, voltageLevelIds);
}

public CgmesVoltageLevelsAreaFactory(List<String> excludedXnodes, List<String> voltageLevelIds) {
this(null, excludedXnodes, voltageLevelIds);
}

public CgmesVoltageLevelsAreaFactory(CgmesControlArea area, List<String> excludedXnodes, List<String> voltageLevelIds) {
public CgmesVoltageLevelsAreaFactory(Area area, List<String> excludedXnodes, List<String> voltageLevelIds) {
this.area = area;
this.excludedXnodes = excludedXnodes;
this.voltageLevelIds = Objects.requireNonNull(voltageLevelIds);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,10 @@

import com.powsybl.balances_adjustment.util.NetworkArea;
import com.powsybl.balances_adjustment.util.NetworkAreaFactory;
import com.powsybl.cgmes.extensions.CgmesControlAreas;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.test.DanglingLineNetworkFactory;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertEquals;
Expand All @@ -38,21 +34,36 @@ void testWithNoArea() {
}

@Test
void testWithArea() {
void testWithAreaFromOldExtension() {
Network network = Network.read("controlArea.xiidm", getClass().getResourceAsStream("/controlArea.xiidm"));
NetworkAreaFactory factory = new CgmesBoundariesAreaFactory(new ArrayList<>(network.getExtension(CgmesControlAreas.class).getCgmesControlAreas()));
NetworkAreaFactory factory = new CgmesBoundariesAreaFactory(network.getAreaStream().toList());
NetworkArea area = factory.create(network);

List<Double> ps = Stream.of(
network.getDanglingLine("_78736387-5f60-4832-b3fe-d50daf81b0a6"),
network.getDanglingLine("_17086487-56ba-4979-b8de-064025a6b4da"),
network.getDanglingLine("_b18cd1aa-7808-49b9-a7cf-605eaf07b006"))
.map(dl -> dl.getBoundary().getP()).collect(Collectors.toList());
double sum = ps.stream().mapToDouble(n -> n).sum();
double sum = Stream.of(
network.getDanglingLine("_78736387-5f60-4832-b3fe-d50daf81b0a6"),
network.getDanglingLine("_17086487-56ba-4979-b8de-064025a6b4da"),
network.getDanglingLine("_b18cd1aa-7808-49b9-a7cf-605eaf07b006"))
.mapToDouble(dl -> dl.getBoundary().getP()).sum();

sum = sum + network.getTieLine("TL_fict").getDanglingLine1().getBoundary().getP();
// FIXME: we miss the line "_b58bf21a-096a-4dae-9a01-3f03b60c24c7_fict_2" because it is not a tie line.
assertEquals(-sum, area.getNetPosition(), DELTA_POWER);
assertTrue(area.getContainedBusViewBuses().isEmpty());
}

@Test
void testWithAreaWithoutAreaExtension() {
Network network = Network.read("controlAreaWithoutExtension.xml", getClass().getResourceAsStream("/controlAreaWithoutExtension.xml"));
NetworkAreaFactory factory = new CgmesBoundariesAreaFactory(network.getAreaStream().toList());
NetworkArea area = factory.create(network);

double sum = Stream.of(
network.getDanglingLine("_78736387-5f60-4832-b3fe-d50daf81b0a6"),
network.getDanglingLine("_17086487-56ba-4979-b8de-064025a6b4da"),
network.getDanglingLine("_b18cd1aa-7808-49b9-a7cf-605eaf07b006"))
.mapToDouble(dl -> dl.getBoundary().getP()).sum();

assertEquals(-sum, area.getNetPosition(), DELTA_POWER);
assertTrue(area.getContainedBusViewBuses().isEmpty());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@

import com.powsybl.balances_adjustment.util.NetworkArea;
import com.powsybl.balances_adjustment.util.NetworkAreaFactory;
import com.powsybl.cgmes.extensions.CgmesControlArea;
import com.powsybl.cgmes.extensions.CgmesControlAreas;
import com.powsybl.iidm.network.Area;
import com.powsybl.iidm.network.Line;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.TieLine;
Expand All @@ -25,14 +24,13 @@
*/
class CgmesVoltageLevelsAreaTest {

private final String[] voltageLevelsIds = {"_d0486169-2205-40b2-895e-b672ecb9e5fc", "_4ba71b59-ee2f-450b-9f7d-cc2f1cc5e386", "_8bbd7e74-ae20-4dce-8780-c20f8e18c2e0", "_469df5f7-058f-4451-a998-57a48e8a56fe", "_b10b171b-3bc5-4849-bb1f-61ed9ea1ec7c"};
private final Network network = Network.read("controlArea.xiidm", getClass().getResourceAsStream("/controlArea.xiidm"));

static final double DELTA_POWER = 1e-5;

@Test
void testWithArea() {
CgmesControlArea cgmesArea = network.getExtension(CgmesControlAreas.class).getCgmesControlArea("_BECONTROLAREA");
void testWithAreaFromOldExtension() {
String[] voltageLevelsIds = {"_d0486169-2205-40b2-895e-b672ecb9e5fc", "_4ba71b59-ee2f-450b-9f7d-cc2f1cc5e386", "_8bbd7e74-ae20-4dce-8780-c20f8e18c2e0", "_469df5f7-058f-4451-a998-57a48e8a56fe", "_b10b171b-3bc5-4849-bb1f-61ed9ea1ec7c"};
Network network = Network.read("controlArea.xiidm", getClass().getResourceAsStream("/controlArea.xiidm"));
Area cgmesArea = network.getArea("_BECONTROLAREA");
NetworkAreaFactory factory = new CgmesVoltageLevelsAreaFactory(cgmesArea, voltageLevelsIds);
NetworkArea area = factory.create(network);
assertEquals(5, area.getContainedBusViewBuses().size());
Expand All @@ -51,7 +49,9 @@ void testWithArea() {
}

@Test
void testWithExcludedXnodes() {
void testWithExcludedXnodesFromOldExtension() {
String[] voltageLevelsIds = {"_d0486169-2205-40b2-895e-b672ecb9e5fc", "_4ba71b59-ee2f-450b-9f7d-cc2f1cc5e386", "_8bbd7e74-ae20-4dce-8780-c20f8e18c2e0", "_469df5f7-058f-4451-a998-57a48e8a56fe", "_b10b171b-3bc5-4849-bb1f-61ed9ea1ec7c"};
Network network = Network.read("controlArea.xiidm", getClass().getResourceAsStream("/controlArea.xiidm"));
NetworkAreaFactory factory = new CgmesVoltageLevelsAreaFactory(Arrays.asList("TN_Border_GY11", "XNODE"), Arrays.asList(voltageLevelsIds));
NetworkArea area = factory.create(network);
assertEquals(5, area.getContainedBusViewBuses().size());
Expand All @@ -65,4 +65,41 @@ void testWithExcludedXnodes() {
+ lineFlow;
assertEquals(realNetPosition, area.getNetPosition(), DELTA_POWER);
}

@Test
void testWithAreaWithoutAreaExtension() {
String[] voltageLevelsIds = {"_d0486169-2205-40b2-895e-b672ecb9e5fc", "_4ba71b59-ee2f-450b-9f7d-cc2f1cc5e386", "_8bbd7e74-ae20-4dce-8780-c20f8e18c2e0", "_469df5f7-058f-4451-a998-57a48e8a56fe", "_b10b171b-3bc5-4849-bb1f-61ed9ea1ec7c"};
Network network = Network.read("controlAreaWithoutExtension.xml", getClass().getResourceAsStream("/controlAreaWithoutExtension.xml"));
Area cgmesArea = network.getArea("_BECONTROLAREA");
NetworkAreaFactory factory = new CgmesVoltageLevelsAreaFactory(cgmesArea, voltageLevelsIds);
NetworkArea area = factory.create(network);
assertEquals(5, area.getContainedBusViewBuses().size());

Line line = network.getLine("_b58bf21a-096a-4dae-9a01-3f03b60c24c7_fict_2");
double lineFlow = (line.getTerminal2().getP() - line.getTerminal1().getP()) / 2;
double realNetPosition = -network.getDanglingLine("_78736387-5f60-4832-b3fe-d50daf81b0a6").getBoundary().getP()
- network.getDanglingLine("_17086487-56ba-4979-b8de-064025a6b4da").getBoundary().getP()
- network.getDanglingLine("_b18cd1aa-7808-49b9-a7cf-605eaf07b006").getBoundary().getP()
+ lineFlow;
assertEquals(realNetPosition, area.getNetPosition(), DELTA_POWER);
}

@Test
void testWithExcludedXnodesWithoutAreaExtension() {
String[] voltageLevelsIds = {"_d0486169-2205-40b2-895e-b672ecb9e5fc", "_4ba71b59-ee2f-450b-9f7d-cc2f1cc5e386", "_8bbd7e74-ae20-4dce-8780-c20f8e18c2e0", "_469df5f7-058f-4451-a998-57a48e8a56fe", "_b10b171b-3bc5-4849-bb1f-61ed9ea1ec7c"};
Network network = Network.read("controlAreaWithoutExtension.xml", getClass().getResourceAsStream("/controlAreaWithoutExtension.xml"));
NetworkAreaFactory factory = new CgmesVoltageLevelsAreaFactory(Arrays.asList("TN_Border_GY11", "XNODE"), Arrays.asList(voltageLevelsIds));
NetworkArea area = factory.create(network);
assertEquals(5, area.getContainedBusViewBuses().size());
Line line1 = network.getLine("_b58bf21a-096a-4dae-9a01-3f03b60c24c7_fict");
Line line2 = network.getLine("_b58bf21a-096a-4dae-9a01-3f03b60c24c7_fict_2");
double lineFlow = (line1.getTerminal2().getP() - line1.getTerminal1().getP()) / 2
+ (line2.getTerminal1().getP() - line2.getTerminal2().getP()) / 2;
double realNetPosition = -network.getDanglingLine("_78736387-5f60-4832-b3fe-d50daf81b0a6").getBoundary().getP()
- network.getDanglingLine("_17086487-56ba-4979-b8de-064025a6b4da").getBoundary().getP()
- network.getDanglingLine("_ed0c5d75-4a54-43c8-b782-b20d7431630b").getBoundary().getP()
+ lineFlow;
assertEquals(realNetPosition, area.getNetPosition(), DELTA_POWER);
}

}
Loading
Loading