Skip to content

Commit

Permalink
Merge loads based on P/Q sign (#175)
Browse files Browse the repository at this point in the history
* Separation of merge/unmerge based on powers sign
* Refactor merge
* Refactor unit tests in commons
* Rename BusState into LoadState
* Remove unused iidm files
* Create LoadsToMerge only if merge required
* LoadPowers based on P0/Q0 instead of P/Q
* Fix unit tests
* Add unit tests
* Unit tests do not rewrite known iidm file

Signed-off-by: lisrte <laurent.issertial@rte-france.com>
Co-authored-by: Florian Dupuy <florian.dupuy@rte-france.com>
  • Loading branch information
Lisrte and flo-dup authored Feb 24, 2023
1 parent d629c10 commit f3b4baa
Show file tree
Hide file tree
Showing 23 changed files with 687 additions and 9,666 deletions.
109 changes: 0 additions & 109 deletions commons/src/main/java/com/powsybl/dynawo/commons/LoadsMerger.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
/**
* Copyright (c) 2021, RTE (http://www.rte-france.com)
* Copyright (c) 2023, 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.dynawo.commons;

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

import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
* @author Guillem Jané Guasch <janeg at aia.es>
*/
Expand Down Expand Up @@ -116,7 +123,19 @@ private static void update(Terminal target, Terminal source) {
target.setQ(source.getQ());
if (source.isConnected()) {
target.connect();
} else if (!source.isConnected()) {
} else {
target.disconnect();
}
}

private static void update(Terminal target, Terminal mergedSource, double targetGroupP, double targetGroupQ) {
double pRatio = target.getP() / targetGroupP;
double qRatio = target.getQ() / targetGroupQ;
target.setP(mergedSource.getP() * pRatio);
target.setQ(mergedSource.getQ() * qRatio);
if (mergedSource.isConnected()) {
target.connect();
} else {
target.disconnect();
}
}
Expand All @@ -128,42 +147,29 @@ private static void updateLoads(Network targetNetwork, Network sourceNetwork, bo
}
} 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);
}
updateLoads(busTarget, sourceNetwork.getBusBreakerView().getBus(busTarget.getId()));
}
}
}

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();
private static void updateLoads(Bus busTarget, Bus busSource) {
Iterable<Load> loadsTarget = busTarget.getLoads();
int nbLoads = Iterables.size(loadsTarget);
if (nbLoads == 0) {
return;
}
Map<LoadPowers, Terminal> mergedLoadsTerminal = busSource.getLoadStream()
.collect(Collectors.toMap(LoadsMerger::getLoadPowers, Load::getTerminal));
LoadsMerger.getLoadPowersGrouping(busTarget).forEach((loadPowers, loadsGroup) -> {
Terminal mergedLoadTerminal = Optional.ofNullable(mergedLoadsTerminal.get(loadPowers))
.orElseThrow(() -> new PowsyblException("Missing merged load in bus " + busTarget.getId()));
if (loadsGroup.size() == 1) {
update(loadsGroup.get(0).getTerminal(), mergedLoadTerminal);
} else {
double groupP = loadsGroup.stream().map(Load::getTerminal).mapToDouble(Terminal::getP).sum();
double groupQ = loadsGroup.stream().map(Load::getTerminal).mapToDouble(Terminal::getQ).sum();
loadsGroup.forEach(load -> update(load.getTerminal(), mergedLoadTerminal, groupP, groupQ));
}
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Copyright (c) 2023, 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.dynawo.commons.loadmerge;

/**
* @author Laurent Isertial <laurent.issertial at rte-france.com>
*/
public enum LoadPowers {
P_POS_Q_POS(".pppq"),
P_POS_Q_NEG(".ppnq"),
P_NEG_Q_POS(".nppq"),
P_NEG_Q_NEG(".npnq");

private final String mergeLoadSuffixId;

LoadPowers(String suffix) {
mergeLoadSuffixId = suffix;
}

public String getMergeLoadSuffixId() {
return mergeLoadSuffixId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* Copyright (c) 2023, 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.dynawo.commons.loadmerge;

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

import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.powsybl.dynawo.commons.loadmerge.LoadPowers.*;

/**
* @author Florian Dupuy <florian.dupuy at rte-france.com>
* @author Laurent Isertial <laurent.issertial at rte-france.com>
* @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<LoadsToMerge> loadsToMergeList = mergedLoadsNetwork.getBusBreakerView().getBusStream()
.filter(bus -> bus.getLoadStream().count() > 1)
.map(LoadsMerger::mergeLoads)
.flatMap(List::stream)
.collect(Collectors.toList());

for (LoadsToMerge loadsToMerge : loadsToMergeList) {
loadsToMerge.getLoads().forEach(Connectable::remove);
loadsToMerge.getLoadAdder().setP0(loadsToMerge.getMergedP0());
loadsToMerge.getLoadAdder().setQ0(loadsToMerge.getMergedQ0());
Load load = loadsToMerge.getLoadAdder().add();
load.getTerminal().setP(loadsToMerge.getMergedP());
load.getTerminal().setQ(loadsToMerge.getMergedQ());
}

return mergedLoadsNetwork;
}

private static List<LoadsToMerge> mergeLoads(Bus bus) {
return getLoadsToMergeList(bus).stream()
.map(loadsToMerge -> mergeLoads(bus, loadsToMerge))
.collect(Collectors.toList());
}

private static LoadsToMerge mergeLoads(Bus bus, LoadsToMerge loadsToMerge) {
LoadAdder loadAdder = loadsToMerge.getLoadAdder();
loadAdder.setId(MERGE_LOAD_PREFIX_ID + bus.getId() + loadsToMerge.getLoadPowers().getMergeLoadSuffixId());
loadAdder.setLoadType(LoadType.UNDEFINED);

TopologyKind topologyKind = bus.getVoltageLevel().getTopologyKind();
if (TopologyKind.BUS_BREAKER.equals(topologyKind)) {
loadAdder.setBus(bus.getId());
loadAdder.setConnectableBus(bus.getId());
} else if (TopologyKind.NODE_BREAKER.equals(topologyKind)) {
loadAdder.setNode(loadsToMerge.getLoads().get(0).getTerminal().getNodeBreakerView().getNode());
}

return loadsToMerge;
}

public static List<LoadsToMerge> getLoadsToMergeList(Bus bus) {
List<LoadsToMerge> loadsToMerge = new ArrayList<>();
getLoadPowersGrouping(bus).forEach((loadPowers, loads) -> {
if (loads.size() > 1) {
loadsToMerge.add(new LoadsToMerge(loadPowers, loads, bus.getVoltageLevel().newLoad()));
}
});
return loadsToMerge;
}

public static Map<LoadPowers, List<Load>> getLoadPowersGrouping(Bus bus) {
EnumMap<LoadPowers, List<Load>> loadsGrouping = new EnumMap<>(LoadPowers.class);
for (Load load : bus.getLoads()) {
loadsGrouping.computeIfAbsent(getLoadPowers(load), k -> new ArrayList<>()).add(load);
}
return loadsGrouping;
}

public static LoadPowers getLoadPowers(Load load) {
if (load.getP0() >= 0) {
return load.getQ0() >= 0 ? P_POS_Q_POS : P_POS_Q_NEG;
} else {
return load.getQ0() >= 0 ? P_NEG_Q_POS : P_NEG_Q_NEG;
}
}
}
Loading

0 comments on commit f3b4baa

Please sign in to comment.