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

Add merge/unmerge loads feature. #131

Merged
merged 35 commits into from
Feb 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
93ffe08
DynaWaltz: update IIDM version when exporting a network
Nov 21, 2022
9073657
Add merge/unmerge loads feature.
Oct 28, 2022
eead11b
DynaWaltz: add mergeLoads feature
Nov 22, 2022
d75b991
DynaFlow: add mergeLoads
Nov 22, 2022
eee4a71
Merge branch 'main' into merge-loads
dimbdr Nov 24, 2022
24ea9f6
DynaWaltz: update tests
Nov 24, 2022
6c85f03
Merge branch 'main' into merge-loads
dimbdr Nov 24, 2022
28623b9
Complete coverage
Nov 24, 2022
37adc7a
Merge branch 'main' into merge-loads
dimbdr Nov 28, 2022
e1c1a4f
DynaFlow: tests correction
Nov 28, 2022
31e928b
MergeLoads: create a copy of a network.
Nov 28, 2022
82528db
Correction on how to update a network
Nov 28, 2022
92fc07a
Correction in dependency
Nov 28, 2022
bce1c1f
Correction in before methods
Nov 28, 2022
cead875
DynaFlow: rever modif of SmallBusBranch.xiidm
Nov 29, 2022
5c47c99
Merge branch 'main' into merge-loads
dimbdr Nov 30, 2022
3b52ab5
Merge branch 'main' into merge-loads
Dec 23, 2022
2db79ce
Merge branch 'main' into merge-loads
flo-dup Jan 4, 2023
fce6c7c
Merge branch 'main' into merge-loads
flo-dup Feb 15, 2023
9f2777c
Merge branch 'main' into merge-loads
flo-dup Feb 15, 2023
bc4ac28
Simplify DynaFlowProviderTest
flo-dup Feb 14, 2023
46a3052
Simplify DynaWaltsProviderTest
flo-dup Feb 14, 2023
8c593bd
Merge loads based on initial network instead of InfoLoad
flo-dup Jan 5, 2023
47df80d
Renaming to LoadsMerger
flo-dup Jan 24, 2023
f4b7eac
Lazy copy in loadsMerger
flo-dup Jan 24, 2023
abde1a0
Renaming to NetworkResultsUpdater
flo-dup Jan 24, 2023
c4fbb25
Loads not unmerged but initial network directly updated
flo-dup Feb 6, 2023
4840fa7
Use more consistent tests in DynawaltzProviderTest
flo-dup Feb 16, 2023
08799e4
Not creating a new Thread to copy network
flo-dup Feb 16, 2023
6c89312
Fix unit tests
flo-dup Feb 16, 2023
c29b9bc
Delete non-unit tests
flo-dup Feb 16, 2023
c24cd58
Multiply before dividing to avoid loss of precision
flo-dup Feb 16, 2023
fadf06f
Fix code smells
flo-dup Feb 17, 2023
9878784
Clean DynaFlowProviderTest
flo-dup Feb 17, 2023
8028186
Fix LoadsMerger thanks to new unit test
flo-dup Feb 17, 2023
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
109 changes: 109 additions & 0 deletions commons/src/main/java/com/powsybl/dynawo/commons/LoadsMerger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.powsybl.dynawo.commons;

import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.xml.NetworkXml;

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

/**
* @author Dimitri Baudrier <dimitri.baudrier at rte-france.com>
*/
public final class LoadsMerger {

private static final String MERGE_LOAD_PREFIX_ID = "merged_load_.";

private LoadsMerger() {
}

public static Network mergeLoads(Network network) throws PowsyblException {
Network mergedLoadsNetwork = NetworkXml.copy(network);

List<LoadsMerging> loadsMerging = mergedLoadsNetwork.getBusBreakerView().getBusStream()
.filter(bus -> bus.getLoadStream().count() > 1)
.map(LoadsMerger::mergeLoads)
.collect(Collectors.toList());

for (LoadsMerging merging : loadsMerging) {
merging.loadsToMerge.forEach(Connectable::remove);
merging.loadAdder.setP0(merging.busState.p0);
merging.loadAdder.setQ0(merging.busState.q0);
Load load = merging.loadAdder.add();
load.getTerminal().setP(merging.busState.p);
load.getTerminal().setQ(merging.busState.q);
}
return mergedLoadsNetwork;
}

private static LoadsMerging mergeLoads(Bus bus) {
TopologyKind topologyKind = bus.getVoltageLevel().getTopologyKind();

LoadAdder loadAdder = bus.getVoltageLevel().newLoad();
loadAdder.setId(MERGE_LOAD_PREFIX_ID + bus.getId());

loadAdder.setLoadType(LoadType.UNDEFINED);

if (TopologyKind.BUS_BREAKER.equals(topologyKind)) {
loadAdder.setBus(bus.getId());
loadAdder.setConnectableBus(bus.getId());
}

Iterable<Load> loadsToMerge = bus.getLoads();
if (TopologyKind.NODE_BREAKER.equals(topologyKind)) {
Load firstLoad = loadsToMerge.iterator().next();
int node = firstLoad.getTerminal().getNodeBreakerView().getNode();
loadAdder.setNode(node);
}

return new LoadsMerging(loadAdder, loadsToMerge, getBusState(bus));
}

static final class BusState {
private final double p;
private final double q;
private final double p0;
private final double q0;

private BusState(double p, double q, double p0, double q0) {
this.p = p;
this.q = q;
this.p0 = p0;
this.q0 = q0;
}

public double getP() {
return p;
}

public double getQ() {
return q;
}
}

static BusState getBusState(Bus bus) {
double p0 = 0;
double q0 = 0;
double p = 0;
double q = 0;
for (Load load : bus.getLoads()) {
p0 += load.getP0();
q0 += load.getQ0();
p += load.getTerminal().getP();
q += load.getTerminal().getQ();
}
return new BusState(p, q, p0, q0);
}

private static class LoadsMerging {
private final BusState busState;
private final LoadAdder loadAdder;
private final Iterable<Load> loadsToMerge;

public LoadsMerging(LoadAdder loadAdder, Iterable<Load> loadsToMerge, BusState busState) {
this.loadAdder = loadAdder;
this.loadsToMerge = loadsToMerge;
this.busState = busState;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,24 @@
*/
package com.powsybl.dynawo.commons;

import com.google.common.collect.Iterables;
import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @author Guillem Jané Guasch <janeg at aia.es>
*/
public final class DynawoResultsNetworkUpdate {
public final class NetworkResultsUpdater {

private static final Logger LOG = LoggerFactory.getLogger(DynawoResultsNetworkUpdate.class);
private static final Logger LOG = LoggerFactory.getLogger(NetworkResultsUpdater.class);

private DynawoResultsNetworkUpdate() {
private NetworkResultsUpdater() {
}

public static void update(Network targetNetwork, Network sourceNetwork) {
public static void update(Network targetNetwork, Network sourceNetwork, boolean mergeLoads) {
updateLoads(targetNetwork, sourceNetwork, mergeLoads);
for (Line lineSource : sourceNetwork.getLines()) {
update(targetNetwork.getLine(lineSource.getId()).getTerminal1(), lineSource.getTerminal1());
update(targetNetwork.getLine(lineSource.getId()).getTerminal2(), lineSource.getTerminal2());
Expand Down Expand Up @@ -62,9 +65,6 @@ public static void update(Network targetNetwork, Network sourceNetwork) {
update(targetThreeWindingsTransformer.getLeg2(), sourceThreeWindingsTransformer.getLeg2());
update(targetThreeWindingsTransformer.getLeg3(), sourceThreeWindingsTransformer.getLeg3());
}
for (Load sourceLoad : sourceNetwork.getLoads()) {
update(targetNetwork.getLoad(sourceLoad.getId()).getTerminal(), sourceLoad.getTerminal());
}
for (Generator sourceGenerator : sourceNetwork.getGenerators()) {
update(targetNetwork.getGenerator(sourceGenerator.getId()).getTerminal(), sourceGenerator.getTerminal());
}
Expand Down Expand Up @@ -120,4 +120,50 @@ private static void update(Terminal target, Terminal source) {
target.disconnect();
}
}

private static void updateLoads(Network targetNetwork, Network sourceNetwork, boolean mergeLoads) {
if (!mergeLoads) {
for (Load sourceLoad : sourceNetwork.getLoads()) {
update(targetNetwork.getLoad(sourceLoad.getId()).getTerminal(), sourceLoad.getTerminal());
}
} else {
for (Bus busTarget : targetNetwork.getBusBreakerView().getBuses()) {
Iterable<Load> loadsTarget = busTarget.getLoads();
int nbLoads = Iterables.size(loadsTarget);
if (nbLoads == 0) {
continue;
}

Terminal mergedLoadTerminal = getMergedLoad(sourceNetwork, busTarget.getId()).getTerminal();
if (nbLoads == 1) {
update(loadsTarget.iterator().next().getTerminal(), mergedLoadTerminal);
} else {
updateMultipleLoadsFromMergedLoad(loadsTarget, mergedLoadTerminal, busTarget);
}
}
}
}

private static Load getMergedLoad(Network sourceNetwork, String busId) {
Bus busSource = sourceNetwork.getBusBreakerView().getBus(busId);
if (busSource.getLoadStream().count() > 1) {
throw new PowsyblException("Loads not merged in bus " + busId);
}
return busSource.getLoadStream().findFirst()
.orElseThrow(() -> new PowsyblException("Missing merged load in bus " + busId));
}

private static void updateMultipleLoadsFromMergedLoad(Iterable<Load> loadsTarget, Terminal mergedLoadTerminal, Bus busTarget) {
LoadsMerger.BusState busState = LoadsMerger.getBusState(busTarget);
for (Load load : loadsTarget) {
Terminal loadTerminal = load.getTerminal();
loadTerminal.setP(mergedLoadTerminal.getP() * loadTerminal.getP() / busState.getP());
loadTerminal.setQ(mergedLoadTerminal.getQ() * loadTerminal.getQ() / busState.getQ());
if (mergedLoadTerminal.isConnected()) {
loadTerminal.connect();
} else if (!mergedLoadTerminal.isConnected()) {
loadTerminal.disconnect();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.powsybl.dynawo.commons;

import com.powsybl.commons.test.AbstractConverterTest;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.xml.NetworkXml;
import org.junit.Test;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

import static com.powsybl.commons.test.ComparisonUtils.compareTxt;
import static org.junit.Assert.assertNotNull;

public class LoadsMergerTest extends AbstractConverterTest {

@Test
public void mergeLoads() throws IOException {
Network network = createTestNetwork();
Network expectedIidm = Network.read("mergedLoads.xiidm", getClass().getResourceAsStream("/mergedLoads.xiidm"));
compare(expectedIidm, LoadsMerger.mergeLoads(network));
}

private static Network createTestNetwork() {
Network network = Network.create("test", "test");
Substation s = network.newSubstation().setId("substation").add();

VoltageLevel vl1 = s.newVoltageLevel().setId("vl1").setNominalV(250).setTopologyKind(TopologyKind.NODE_BREAKER).add();
vl1.getNodeBreakerView().newBusbarSection().setId("Busbar1").setNode(0).add();
vl1.getNodeBreakerView().newBusbarSection().setId("Busbar2").setNode(4).add();
vl1.getNodeBreakerView().newDisconnector().setNode1(0).setNode2(1).setId("d1").add();
vl1.getNodeBreakerView().newDisconnector().setNode1(0).setNode2(2).setId("d2").add();
vl1.getNodeBreakerView().newDisconnector().setNode1(0).setNode2(3).setId("d3").add();
vl1.getNodeBreakerView().newBreaker().setNode1(0).setNode2(4).setId("coupler").setOpen(true).add();
vl1.getNodeBreakerView().newDisconnector().setNode1(0).setNode2(5).setId("d4").add();
vl1.getNodeBreakerView().newDisconnector().setNode1(4).setNode2(6).setId("d5").add();
vl1.newLoad().setId("load1").setP0(10.0).setQ0(5.0).setNode(1).add();
vl1.newLoad().setId("load2").setP0(12.0).setQ0(1.0).setNode(2).add();
vl1.newLoad().setId("load3").setP0(22.0).setQ0(3.0).setNode(3).add();
vl1.newLoad().setId("load4").setP0(-2.0).setQ0(-1.0).setNode(6).add();

VoltageLevel vl2 = s.newVoltageLevel().setId("vl2").setNominalV(250).setTopologyKind(TopologyKind.BUS_BREAKER).add();
Bus b1 = vl2.getBusBreakerView().newBus().setId("b1").add();
Bus b2 = vl2.getBusBreakerView().newBus().setId("b2").add();
Bus b3 = vl2.getBusBreakerView().newBus().setId("b3").add();
vl2.getBusBreakerView().newSwitch().setId("c1").setBus1(b1.getId()).setBus2(b2.getId()).add();
vl2.getBusBreakerView().newSwitch().setId("c2").setBus1(b2.getId()).setBus2(b3.getId()).add();
vl2.newGenerator().setId("g1").setBus(b1.getId()).setTargetP(101).setTargetV(390).setMinP(0).setMaxP(150).setVoltageRegulatorOn(true).add();
vl2.newLoad().setId("load5").setP0(37.0).setQ0(1.0).setBus(b2.getId()).add();
vl2.newLoad().setId("load6").setP0(13.0).setQ0(6.0).setBus(b2.getId()).add();
vl2.newLoad().setId("load7").setP0(7.0).setQ0(-4.0).setBus(b3.getId()).add();

network.newLine().setId("l1").setVoltageLevel1(vl1.getId()).setNode1(5).setVoltageLevel2(vl2.getId()).setBus2(b1.getId())
.setR(1).setX(3).setG1(0).setG2(0).setB1(0).setB2(0).add();
return network;
}

private void compare(Network expected, Network actual) throws IOException {
Path pexpected = tmpDir.resolve("expected.xiidm");
assertNotNull(pexpected);
Path pactual = tmpDir.resolve("actual.xiidm");
assertNotNull(pactual);
NetworkXml.write(expected, pexpected);
actual.setCaseDate(expected.getCaseDate());
NetworkXml.write(actual, pactual);
compareTxt(Files.newInputStream(pexpected), Files.newInputStream(pactual));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,22 @@
/**
* @author Guillem Jané Guasch <janeg at aia.es>
*/
public class DynawoResultsNetworkUpdateTest extends AbstractConverterTest {
public class NetworkResultsUpdaterTest extends AbstractConverterTest {

@Test
public void testUpdateNodeBreaker() throws IOException {
Network expected = createTestCaseNodeBreaker();
Network actual = createTestCaseNodeBreaker();
reset(actual);
DynawoResultsNetworkUpdate.update(actual, expected);
NetworkResultsUpdater.update(actual, expected, false);
compare(expected, actual);
}

@Test
public void testUpdateNodeBreakerWithMergedLoads() throws IOException {
Network expected = createTestCaseNodeBreaker();
Network actual = createTestCaseNodeBreaker();
NetworkResultsUpdater.update(actual, LoadsMerger.mergeLoads(expected), true);
compare(expected, actual);
}

Expand All @@ -49,7 +57,7 @@ public void testUpdateNodeBreakerPassingThroughBusBreaker() throws IOException {
Path pexpectedAsBusBreaker = tmpDir.resolve("expected-as-busbreaker.xiidm");
NetworkXml.write(expected, new ExportOptions().setTopologyLevel(TopologyLevel.BUS_BREAKER), pexpectedAsBusBreaker);
Network expectedBusBreaker = NetworkXml.read(pexpectedAsBusBreaker);
DynawoResultsNetworkUpdate.update(actual, expectedBusBreaker);
NetworkResultsUpdater.update(actual, expectedBusBreaker, false);

compare(expected, actual);
}
Expand All @@ -59,7 +67,15 @@ public void testUpdateBusBranch() throws IOException {
Network expected = createTestCaseBusBranch();
Network actual = createTestCaseBusBranch();
reset(actual);
DynawoResultsNetworkUpdate.update(actual, expected);
NetworkResultsUpdater.update(actual, expected, false);
compare(expected, actual);
}

@Test
public void testUpdateBusBranchWithMergedLoads() throws IOException {
Network expected = createTestCaseBusBranch();
Network actual = createTestCaseBusBranch();
NetworkResultsUpdater.update(actual, LoadsMerger.mergeLoads(expected), true);
compare(expected, actual);
}

Expand All @@ -68,7 +84,7 @@ public void testUpdateMicro() throws IOException {
Network expected = createTestMicro();
Network actual = createTestMicro();
reset(actual);
DynawoResultsNetworkUpdate.update(actual, expected);
NetworkResultsUpdater.update(actual, expected, false);
compare(expected, actual);
}

Expand Down Expand Up @@ -97,7 +113,7 @@ public void testUpdateMicroDisconnects() throws IOException {

Network actual = createTestMicro();
reset(actual);
DynawoResultsNetworkUpdate.update(actual, expected);
NetworkResultsUpdater.update(actual, expected, false);
compare(expected, actual);
}

Expand Down
34 changes: 34 additions & 0 deletions commons/src/test/resources/mergedLoads.xiidm
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<iidm:network xmlns:iidm="http://www.powsybl.org/schema/iidm/1_9" id="test" caseDate="2023-02-17T05:41:11.194+01:00" forecastDistance="0" sourceFormat="test" minimumValidationLevel="STEADY_STATE_HYPOTHESIS">
<iidm:substation id="substation">
<iidm:voltageLevel id="vl1" nominalV="250.0" topologyKind="NODE_BREAKER">
<iidm:nodeBreakerTopology>
<iidm:busbarSection id="Busbar1" node="0"/>
<iidm:busbarSection id="Busbar2" node="4"/>
<iidm:switch id="d1" kind="DISCONNECTOR" retained="false" open="false" node1="0" node2="1"/>
<iidm:switch id="d2" kind="DISCONNECTOR" retained="false" open="false" node1="0" node2="2"/>
<iidm:switch id="d3" kind="DISCONNECTOR" retained="false" open="false" node1="0" node2="3"/>
<iidm:switch id="coupler" kind="BREAKER" retained="false" open="true" node1="0" node2="4"/>
<iidm:switch id="d4" kind="DISCONNECTOR" retained="false" open="false" node1="0" node2="5"/>
<iidm:switch id="d5" kind="DISCONNECTOR" retained="false" open="false" node1="4" node2="6"/>
</iidm:nodeBreakerTopology>
<iidm:load id="merged_load_.vl1_0" loadType="UNDEFINED" p0="44.0" q0="9.0" node="1"/>
<iidm:load id="load4" loadType="UNDEFINED" p0="-2.0" q0="-1.0" node="6"/>
</iidm:voltageLevel>
<iidm:voltageLevel id="vl2" nominalV="250.0" topologyKind="BUS_BREAKER">
<iidm:busBreakerTopology>
<iidm:bus id="b1"/>
<iidm:bus id="b2"/>
<iidm:bus id="b3"/>
<iidm:switch id="c1" kind="BREAKER" retained="true" open="false" bus1="b1" bus2="b2"/>
<iidm:switch id="c2" kind="BREAKER" retained="true" open="false" bus1="b2" bus2="b3"/>
</iidm:busBreakerTopology>
<iidm:generator id="g1" energySource="OTHER" minP="0.0" maxP="150.0" voltageRegulatorOn="true" targetP="101.0" targetV="390.0" bus="b1" connectableBus="b1">
<iidm:minMaxReactiveLimits minQ="-1.7976931348623157E308" maxQ="1.7976931348623157E308"/>
</iidm:generator>
<iidm:load id="merged_load_.b2" loadType="UNDEFINED" p0="50.0" q0="7.0" bus="b2" connectableBus="b2"/>
<iidm:load id="load7" loadType="UNDEFINED" p0="7.0" q0="-4.0" bus="b3" connectableBus="b3"/>
</iidm:voltageLevel>
</iidm:substation>
<iidm:line id="l1" r="1.0" x="3.0" g1="0.0" b1="0.0" g2="0.0" b2="0.0" node1="5" voltageLevelId1="vl1" bus2="b1" connectableBus2="b1" voltageLevelId2="vl2"/>
</iidm:network>
Loading