diff --git a/docs/flow_decomposition/algorithm-description.md b/docs/flow_decomposition/algorithm-description.md
index f1d392db..2f30724c 100644
--- a/docs/flow_decomposition/algorithm-description.md
+++ b/docs/flow_decomposition/algorithm-description.md
@@ -33,6 +33,15 @@ compensated at both sides proportionally to the resistance of each half line.
## Nodal Injections partitioning
+> **_NOTE:_** In PowSyBl terminology, nodal injections are injection connectables that
+> - are not paired dangling lines,
+> - are connected to the network,
+> - are in the main synchronous component (for sensitivity computation reasons),
+> - are not a bus bar section (because of a lack of reference injection),
+> - are not shunt compensator or static var compensator (for sensitivity computation reasons).
+
+> **_NOTE:_** In PowSyBl terminology, xnodes are unpaired dangling lines connected to the network and in the main synchronous component.
+
In order to distinguish internal/loop flows and allocated flows, the nodal injections in each zone must de decomposed in two parts:
- Nodal injections for allocated flows
- Nodal injections for loop flows and internal flows
@@ -63,6 +72,16 @@ where:
## Sensitivity analysis
+> **_NOTE:_** In PowSyBl terminology, only two windings transformers are considered. PSTs must:
+> - be connected to the network,
+> - have a phase tap changer,
+> - have a neutral step on the phase tap changer,
+> - have a bus at each terminal,
+> - be connected to the main synchronous component.
+> Therefore, three windings transformers are not supported.
+
+> **_NOTE:_** Each element of the sensitivity computation must be connected to the main synchronous component (variables (injections) and functions (branches)).
+
In order to assess the linear impact (implied by the DC approximation) of each nodal injection and phase shift transformer
on the network elements' flow, a sensitivity analysis is run.
@@ -89,7 +108,7 @@ where:
- $\mathrm{F}_\mathrm{PST}$ is the vector of the network element PST (phase shift transformer) flow,
- $\mathrm{F}_\mathrm{X}$ is the vector of the network element xnode flow,
- $\mathrm{AM}$ is the allocation matrix, which associates each injection to its zone. $\mathrm{AM}_{ij}$ = 1 if node i is in zone j, 0 otherwise,
-- $\mathrm{\Delta}_\mathrm{PST}$ is the phase shift transformers angle vector,
+- $\mathrm{\Delta}_\mathrm{PST}$ is the phase shift transformers angle vector. The neutral tap position of each PST is used to compute this difference.
## Flow parts rescaling
diff --git a/flow-decomposition/pom.xml b/flow-decomposition/pom.xml
index c2618d17..16e3d914 100644
--- a/flow-decomposition/pom.xml
+++ b/flow-decomposition/pom.xml
@@ -14,95 +14,102 @@
Implementation of ACER methodology for flow decomposition
+
com.powsybl
powsybl-commons
com.powsybl
- powsybl-iidm-api
+ powsybl-glsk-document-api
com.powsybl
- powsybl-loadflow-api
+ powsybl-iidm-api
com.powsybl
- powsybl-glsk-document-api
+ powsybl-loadflow-api
com.powsybl
powsybl-sensitivity-analysis-api
+
+ org.apache.commons
+ commons-csv
+ ${commonscsv.version}
+
org.ejml
ejml-all
${ejml.version}
+
- org.apache.commons
- commons-csv
- ${commonscsv.version}
+ com.powsybl
+ powsybl-iidm-impl
+ runtime
com.powsybl
- powsybl-glsk-document-io-api
- test
+ powsybl-iidm-serde
+ runtime
com.powsybl
- powsybl-glsk-document-ucte
- test
+ powsybl-open-loadflow
+ runtime
com.powsybl
- powsybl-iidm-impl
+ powsybl-ucte-converter
runtime
- com.powsybl
- powsybl-iidm-serde
+ ch.qos.logback
+ logback-classic
runtime
+
- com.powsybl
- powsybl-cgmes-conversion
+ com.google.jimfs
+ jimfs
test
com.powsybl
- powsybl-cgmes-conformity
+ powsybl-config-test
test
com.powsybl
- powsybl-triple-store-impl-rdf4j
+ powsybl-cgmes-conformity
test
com.powsybl
- powsybl-open-loadflow
- ${powsyblopenloadflow.version}
- runtime
+ powsybl-cgmes-conversion
+ test
com.powsybl
- powsybl-ucte-converter
- runtime
+ powsybl-glsk-document-io-api
+ test
- ch.qos.logback
- logback-classic
- runtime
+ com.powsybl
+ powsybl-glsk-document-ucte
+ test
- com.google.jimfs
- jimfs
+ com.powsybl
+ powsybl-iidm-test
test
com.powsybl
- powsybl-config-test
+ powsybl-triple-store-impl-rdf4j
test
diff --git a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/DecomposedFlow.java b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/DecomposedFlow.java
index edceba81..63b4b55a 100644
--- a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/DecomposedFlow.java
+++ b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/DecomposedFlow.java
@@ -60,7 +60,7 @@ public String getContingencyId() {
}
public String getId() {
- return NetworkUtil.getXnecId(contingencyId, branchId);
+ return getXnecId(contingencyId, branchId);
}
public Country getCountry1() {
@@ -140,4 +140,8 @@ private TreeMap getAllKeyMap() {
localDecomposedFlowMap.putAll(loopFlowsMap);
return localDecomposedFlowMap;
}
+
+ public static String getXnecId(String contingencyId, String branchId) {
+ return contingencyId.isEmpty() ? branchId : String.format("%s_%s", branchId, contingencyId);
+ }
}
diff --git a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/FlowDecompositionComputer.java b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/FlowDecompositionComputer.java
index 0dd0c290..51bee3f3 100644
--- a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/FlowDecompositionComputer.java
+++ b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/FlowDecompositionComputer.java
@@ -141,31 +141,27 @@ private void decomposeFlowForState(Network network,
Map netPositions,
Map> glsks,
LoadFlowRunningService.Result loadFlowServiceAcResult) {
- saveAcReferenceFlows(flowDecompositionResultsBuilder, xnecList, loadFlowServiceAcResult);
- compensateLosses(network);
- observers.computedAcFlows(network, loadFlowServiceAcResult);
+ // AC load flow
+ saveAcReferenceFlows(flowDecompositionResultsBuilder, network, xnecList, loadFlowServiceAcResult);
- // None
- NetworkMatrixIndexes networkMatrixIndexes = new NetworkMatrixIndexes(network, new ArrayList<>(xnecList));
- observers.computedAcNodalInjections(networkMatrixIndexes, loadFlowServiceAcResult.fallbackHasBeenActivated());
+ // Losses compensation
+ compensateLosses(network);
+ // DC load flow
runDcLoadFlow(network);
- observers.computedDcFlows(network);
- observers.computedDcNodalInjections(networkMatrixIndexes);
+ saveDcReferenceFlow(flowDecompositionResultsBuilder, network, xnecList);
- SparseMatrixWithIndexesTriplet nodalInjectionsMatrix = getNodalInjectionsMatrix(network,
- netPositions, networkMatrixIndexes, glsks);
- saveDcReferenceFlow(flowDecompositionResultsBuilder, xnecList);
- observers.computedNodalInjectionsMatrix(nodalInjectionsMatrix);
+ // Nodal injections
+ NetworkMatrixIndexes networkMatrixIndexes = new NetworkMatrixIndexes(network, new ArrayList<>(xnecList));
+ SparseMatrixWithIndexesTriplet nodalInjectionsMatrix = getNodalInjectionsMatrix(network, netPositions,
+ networkMatrixIndexes, glsks);
- // DC Sensi
+ // Sensitivity
SensitivityAnalyser sensitivityAnalyser = getSensitivityAnalyser(network, networkMatrixIndexes);
SparseMatrixWithIndexesTriplet ptdfMatrix = getPtdfMatrix(networkMatrixIndexes, sensitivityAnalyser);
- observers.computedPtdfMatrix(ptdfMatrix);
SparseMatrixWithIndexesTriplet psdfMatrix = getPsdfMatrix(networkMatrixIndexes, sensitivityAnalyser);
- observers.computedPsdfMatrix(psdfMatrix);
- // None
+ // Flows
computeAllocatedAndLoopFlows(flowDecompositionResultsBuilder, nodalInjectionsMatrix, ptdfMatrix);
computePstFlows(network, flowDecompositionResultsBuilder, networkMatrixIndexes, psdfMatrix);
@@ -184,11 +180,13 @@ private LoadFlowRunningService.Result runAcLoadFlow(Network network) {
return loadFlowRunningService.runAcLoadflow(network, loadFlowParameters, parameters.isDcFallbackEnabledAfterAcDivergence());
}
- private void saveAcReferenceFlows(FlowDecompositionResults.PerStateBuilder flowDecompositionResultBuilder, Set xnecList, LoadFlowRunningService.Result loadFlowServiceAcResult) {
+ private void saveAcReferenceFlows(FlowDecompositionResults.PerStateBuilder flowDecompositionResultBuilder, Network network, Set xnecList, LoadFlowRunningService.Result loadFlowServiceAcResult) {
Map acTerminal1ReferenceFlows = FlowComputerUtils.calculateAcTerminalReferenceFlows(xnecList, loadFlowServiceAcResult, TwoSides.ONE);
Map acTerminal2ReferenceFlows = FlowComputerUtils.calculateAcTerminalReferenceFlows(xnecList, loadFlowServiceAcResult, TwoSides.TWO);
flowDecompositionResultBuilder.saveAcTerminal1ReferenceFlow(acTerminal1ReferenceFlows);
flowDecompositionResultBuilder.saveAcTerminal2ReferenceFlow(acTerminal2ReferenceFlows);
+ observers.computedAcFlows(network, loadFlowServiceAcResult);
+ observers.computedAcNodalInjections(network, loadFlowServiceAcResult.fallbackHasBeenActivated());
}
private Map getZonesNetPosition(Network network) {
@@ -220,11 +218,15 @@ private SparseMatrixWithIndexesTriplet getNodalInjectionsMatrix(Network network,
NetworkMatrixIndexes networkMatrixIndexes,
Map> glsks) {
NodalInjectionComputer nodalInjectionComputer = new NodalInjectionComputer(networkMatrixIndexes);
- return nodalInjectionComputer.run(network, glsks, netPositions);
+ SparseMatrixWithIndexesTriplet nodalInjectionsMatrix = nodalInjectionComputer.run(network, glsks, netPositions);
+ observers.computedNodalInjectionsMatrix(nodalInjectionsMatrix);
+ return nodalInjectionsMatrix;
}
- private void saveDcReferenceFlow(FlowDecompositionResults.PerStateBuilder flowDecompositionResultBuilder, Set xnecList) {
+ private void saveDcReferenceFlow(FlowDecompositionResults.PerStateBuilder flowDecompositionResultBuilder, Network network, Set xnecList) {
flowDecompositionResultBuilder.saveDcReferenceFlow(FlowComputerUtils.getTerminalReferenceFlow(xnecList, TwoSides.ONE));
+ observers.computedDcFlows(network);
+ observers.computedDcNodalInjections(network);
}
private SensitivityAnalyser getSensitivityAnalyser(Network network, NetworkMatrixIndexes networkMatrixIndexes) {
@@ -233,9 +235,11 @@ private SensitivityAnalyser getSensitivityAnalyser(Network network, NetworkMatri
private SparseMatrixWithIndexesTriplet getPtdfMatrix(NetworkMatrixIndexes networkMatrixIndexes,
SensitivityAnalyser sensitivityAnalyser) {
- return sensitivityAnalyser.run(networkMatrixIndexes.getNodeIdList(),
+ SparseMatrixWithIndexesTriplet ptdfMatrix = sensitivityAnalyser.run(networkMatrixIndexes.getNodeIdList(),
networkMatrixIndexes.getNodeIndex(),
SensitivityVariableType.INJECTION_ACTIVE_POWER);
+ observers.computedPtdfMatrix(ptdfMatrix);
+ return ptdfMatrix;
}
private void computeAllocatedAndLoopFlows(FlowDecompositionResults.PerStateBuilder flowDecompositionResultBuilder,
@@ -248,8 +252,10 @@ private void computeAllocatedAndLoopFlows(FlowDecompositionResults.PerStateBuild
private SparseMatrixWithIndexesTriplet getPsdfMatrix(NetworkMatrixIndexes networkMatrixIndexes,
SensitivityAnalyser sensitivityAnalyser) {
- return sensitivityAnalyser.run(networkMatrixIndexes.getPstList(),
+ SparseMatrixWithIndexesTriplet psdfMatrix = sensitivityAnalyser.run(networkMatrixIndexes.getPstList(),
networkMatrixIndexes.getPstIndex(), SensitivityVariableType.TRANSFORMER_PHASE);
+ observers.computedPsdfMatrix(psdfMatrix);
+ return psdfMatrix;
}
private void computePstFlows(Network network,
diff --git a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/FlowDecompositionObserverList.java b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/FlowDecompositionObserverList.java
index 4a56c9a3..36ad609c 100644
--- a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/FlowDecompositionObserverList.java
+++ b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/FlowDecompositionObserverList.java
@@ -107,24 +107,24 @@ public void computedDcFlows(Network network) {
}
}
- public void computedAcNodalInjections(NetworkMatrixIndexes networkMatrixIndexes, boolean fallbackHasBeenActivated) {
+ public void computedAcNodalInjections(Network network, boolean fallbackHasBeenActivated) {
if (observers.isEmpty()) {
return;
}
- Map results = new ReferenceNodalInjectionComputer().run(networkMatrixIndexes.getNodeList());
+ Map results = new ReferenceNodalInjectionComputer().run(NetworkUtil.getNodeList(network));
for (FlowDecompositionObserver o : observers) {
o.computedAcNodalInjections(results, fallbackHasBeenActivated);
}
}
- public void computedDcNodalInjections(NetworkMatrixIndexes networkMatrixIndexes) {
+ public void computedDcNodalInjections(Network network) {
if (observers.isEmpty()) {
return;
}
- Map results = new ReferenceNodalInjectionComputer().run(networkMatrixIndexes.getNodeList());
+ Map results = new ReferenceNodalInjectionComputer().run(NetworkUtil.getNodeList(network));
for (FlowDecompositionObserver o : observers) {
o.computedDcNodalInjections(results);
diff --git a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/FlowDecompositionResults.java b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/FlowDecompositionResults.java
index f6329f9b..255f0439 100644
--- a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/FlowDecompositionResults.java
+++ b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/FlowDecompositionResults.java
@@ -77,7 +77,7 @@ void saveDcReferenceFlow(Map dcReferenceFlow) {
void build(DecomposedFlowRescaler decomposedFlowRescaler) {
allocatedAndLoopFlowsMatrix.toMap()
.forEach((branchId, decomposedFlow) -> {
- String xnecId = NetworkUtil.getXnecId(contingencyId, branchId);
+ String xnecId = DecomposedFlow.getXnecId(contingencyId, branchId);
decomposedFlowMap.put(xnecId, createDecomposedFlow(branchId, decomposedFlow, decomposedFlowRescaler));
});
}
diff --git a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/LossesCompensator.java b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/LossesCompensator.java
index aff9ddea..874541f8 100644
--- a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/LossesCompensator.java
+++ b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/LossesCompensator.java
@@ -18,10 +18,12 @@
*
* @author Sebastien Murgey {@literal }
* @author Hugo Schindler {@literal }
+ * @author Caio Luke {@literal }
*/
class LossesCompensator {
private final double epsilon;
private Integer networkHash;
+ public static final String LOSSES_ID_PREFIX = "LOSSES ";
LossesCompensator(double epsilon) {
this.epsilon = epsilon;
@@ -33,7 +35,7 @@ class LossesCompensator {
}
static String getLossesId(String id) {
- return String.format("LOSSES %s", id);
+ return LOSSES_ID_PREFIX + id;
}
public void run(Network network) {
@@ -58,39 +60,17 @@ private void addZeroMWLossesLoadsOnBuses(Network network) {
private void compensateLossesOnBranches(Network network) {
network.getBranchStream()
- .filter(this::hasBuses)
- .filter(this::hasP0s)
+ .filter(branch -> branch.getTerminal1().isConnected() || branch.getTerminal2().isConnected())
.forEach(branch -> compensateLossesOnBranch(network, branch));
}
- private boolean hasBus(Terminal terminal) {
- return terminal.getBusBreakerView().getBus() != null;
- }
-
- private boolean hasBuses(Branch> branch) {
- return hasBus(branch.getTerminal1()) && hasBus(branch.getTerminal2());
- }
-
- private boolean hasP0(Terminal terminal) {
- return !Double.isNaN(terminal.getP());
- }
-
- private boolean hasP0s(Branch> branch) {
- return hasP0(branch.getTerminal1()) && hasP0(branch.getTerminal2());
- }
-
private static void addZeroMWLossesLoad(Network network, String busId) {
String lossesId = getLossesId(busId);
Bus bus = network.getBusBreakerView().getBus(busId);
switch (bus.getVoltageLevel().getTopologyKind()) {
- case BUS_BREAKER:
- addZeroMWLossesLoadForBusBreakerTopology(bus, lossesId);
- return;
- case NODE_BREAKER:
- addZeroMWLossesLoadForNodeTopology(bus, lossesId);
- return;
- default:
- throw new PowsyblException("This topology is not managed by the loss compensation.");
+ case BUS_BREAKER -> addZeroMWLossesLoadForBusBreakerTopology(bus, lossesId);
+ case NODE_BREAKER -> addZeroMWLossesLoadForNodeBreakerTopology(bus, lossesId);
+ default -> throw new PowsyblException("Topology not supported by loss compensation.");
}
}
@@ -100,10 +80,11 @@ private static void addZeroMWLossesLoadForBusBreakerTopology(Bus bus, String los
.setBus(bus.getId())
.setP0(0)
.setQ0(0)
+ .setFictitious(true)
.add();
}
- private static void addZeroMWLossesLoadForNodeTopology(Bus bus, String lossesId) {
+ private static void addZeroMWLossesLoadForNodeBreakerTopology(Bus bus, String lossesId) {
VoltageLevel voltageLevel = bus.getVoltageLevel();
VoltageLevel.NodeBreakerView nodeBreakerView = voltageLevel.getNodeBreakerView();
int nodeNum = nodeBreakerView.getMaximumNodeIndex() + 1;
@@ -116,12 +97,13 @@ private static void addZeroMWLossesLoadForNodeTopology(Bus bus, String lossesId)
.setNode(nodeNum)
.setP0(0)
.setQ0(0)
+ .setFictitious(true)
.add();
}
private void compensateLossesOnBranch(Network network, Branch> branch) {
- if (branch instanceof TieLine) {
- compensateLossesOnTieLine(network, (TieLine) branch);
+ if (branch instanceof TieLine tieLine) {
+ compensateLossesOnTieLine(network, tieLine);
} else {
Terminal sendingTerminal = getSendingTerminal(branch);
double losses = branch.getTerminal1().getP() + branch.getTerminal2().getP();
@@ -144,13 +126,26 @@ private void compensateLossesOnTieLine(Network network, TieLine tieLine) {
}
private void updateLoadForLossesOnTerminal(Network network, Terminal terminal, double losses) {
- if (Math.abs(losses) > epsilon) {
+ if (losses > epsilon) {
Load load = network.getLoad(getLossesId(terminal.getBusBreakerView().getBus().getId()));
load.setP0(load.getP0() + losses);
}
}
private Terminal getSendingTerminal(Branch> branch) {
- return branch.getTerminal1().getP() > 0 ? branch.getTerminal1() : branch.getTerminal2();
+ Terminal terminal1 = branch.getTerminal1();
+ Terminal terminal2 = branch.getTerminal2();
+
+ // if only one terminal is connected, that is the sending terminal
+ if (!(terminal1.isConnected() && terminal2.isConnected())) {
+ return terminal1.isConnected() ? terminal1 : terminal2;
+ }
+
+ // terminal with greater P is the sending terminal
+ if (terminal1.getP() >= terminal2.getP()) {
+ return terminal1;
+ } else {
+ return terminal2;
+ }
}
}
diff --git a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/NetPositionComputer.java b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/NetPositionComputer.java
index 3fe22400..44356ac2 100644
--- a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/NetPositionComputer.java
+++ b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/NetPositionComputer.java
@@ -13,7 +13,7 @@
/**
* @author Sebastien Murgey {@literal }
- * @author Hugo Schindler{@literal }
+ * @author Hugo Schindler{@literal }
*/
class NetPositionComputer {
Map run(Network network) {
diff --git a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/NetworkMatrixIndexes.java b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/NetworkMatrixIndexes.java
index dc4245e3..358eac3a 100644
--- a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/NetworkMatrixIndexes.java
+++ b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/NetworkMatrixIndexes.java
@@ -10,13 +10,9 @@
import java.util.List;
import java.util.Map;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-import java.util.stream.Stream;
/**
- * @author Hugo Schindler{@literal }
+ * @author Hugo Schindler{@literal }
* @author Sebastien Murgey{@literal }
*/
class NetworkMatrixIndexes {
@@ -31,13 +27,13 @@ class NetworkMatrixIndexes {
NetworkMatrixIndexes(Network network, List xnecList) {
this.xnecList = xnecList;
- nodeList = getNodeList(network);
+ nodeList = NetworkUtil.getNodeList(network);
nodeIdList = getNodeIdList(nodeList);
- pstList = getPstIdList(network);
- xnecIndex = getXnecIndex(this.xnecList);
+ pstList = NetworkUtil.getPstIdList(network);
+ xnecIndex = NetworkUtil.getIndex(getXnecIdList(this.xnecList));
nodeIndex = NetworkUtil.getIndex(nodeIdList);
pstIndex = NetworkUtil.getIndex(pstList);
- xnodeList = getXNodeList(network);
+ xnodeList = NetworkUtil.getXNodeList(network);
}
List getXnecList() {
@@ -76,74 +72,11 @@ public List> getUnmergedXNodeList() {
return xnodeList;
}
- private List> getNodeList(Network network) {
- return getAllNetworkInjections(network)
- .filter(this::isNotPairedDanglingLine)
- .filter(this::isInjectionConnected)
- .filter(this::isInjectionInMainSynchronousComponent)
- .filter(this::managedInjectionTypes)
- .collect(Collectors.toList());
- }
-
- private boolean managedInjectionTypes(Injection> injection) {
- return !(injection instanceof BusbarSection || injection instanceof ShuntCompensator || injection instanceof StaticVarCompensator); // TODO Remove this fix once the active power computation after a DC load flow is fixed in OLF
- }
-
- private Stream> getAllNetworkInjections(Network network) {
- return network.getConnectableStream()
- .filter(Injection.class::isInstance)
- .map(connectable -> (Injection>) connectable);
- }
-
- private boolean isInjectionConnected(Injection> injection) {
- return injection.getTerminal().isConnected();
- }
-
- private boolean isNotPairedDanglingLine(Injection> injection) {
- return !(injection instanceof DanglingLine && ((DanglingLine) injection).isPaired());
- }
-
- private boolean isInjectionInMainSynchronousComponent(Injection> injection) {
- return NetworkUtil.isTerminalInMainSynchronousComponent(injection.getTerminal());
- }
-
private List getNodeIdList(List> nodeList) {
- return nodeList.stream()
- .map(Injection::getId)
- .collect(Collectors.toList());
- }
-
- private List getPstIdList(Network network) {
- return network.getTwoWindingsTransformerStream()
- .filter(this::isPst)
- .filter(this::hasNeutralStep)
- .map(Identifiable::getId)
- .collect(Collectors.toList());
- }
-
- private boolean isPst(TwoWindingsTransformer twt) {
- return twt.getPhaseTapChanger() != null;
- }
-
- private boolean hasNeutralStep(TwoWindingsTransformer pst) {
- return pst.getPhaseTapChanger().getNeutralStep().isPresent();
- }
-
- private Map getXnecIndex(List xnecList) {
- return IntStream.range(0, xnecList.size())
- .boxed()
- .collect(Collectors.toMap(
- i -> xnecList.get(i).getId(),
- Function.identity()
- ));
+ return nodeList.stream().map(Injection::getId).toList();
}
- private List> getXNodeList(Network network) {
- return network.getDanglingLineStream()
- .filter(dl -> !dl.isPaired())
- .filter(this::isInjectionConnected)
- .filter(this::isInjectionInMainSynchronousComponent)
- .map(danglingLine -> (Injection>) danglingLine)
- .collect(Collectors.toList());
+ private List getXnecIdList(List xnecList) {
+ return xnecList.stream().map(Identifiable::getId).toList();
}
}
diff --git a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/NetworkUtil.java b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/NetworkUtil.java
index 2f5a2641..3c0fd036 100644
--- a/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/NetworkUtil.java
+++ b/flow-decomposition/src/main/java/com/powsybl/flow_decomposition/NetworkUtil.java
@@ -11,26 +11,40 @@
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
+import java.util.stream.Stream;
/**
- * @author Hugo Schindler{@literal }
+ * @author Hugo Schindler{@literal }
* @author Sebastien Murgey{@literal }
*/
public final class NetworkUtil {
static final String LOOP_FLOWS_COLUMN_PREFIX = "Loop Flow from";
private NetworkUtil() {
- throw new AssertionError("Utility class should not be instantiated");
+ // Utility class
+ }
+
+ public static String getLoopFlowIdFromCountry(Network network, String identifiableId) {
+ Identifiable> identifiable = network.getIdentifiable(identifiableId);
+ if (identifiable instanceof Injection> injection) {
+ return getLoopFlowIdFromCountry(getInjectionCountry(injection));
+ }
+ throw new PowsyblException(String.format("Identifiable %s must be an Injection", identifiableId));
}
public static String getLoopFlowIdFromCountry(Country country) {
return String.format("%s %s", LOOP_FLOWS_COLUMN_PREFIX, country.toString());
}
+ public static Country getInjectionCountry(Injection> injection) {
+ return getTerminalCountry(injection.getTerminal());
+ }
+
public static Country getTerminalCountry(Terminal terminal) {
Optional optionalSubstation = terminal.getVoltageLevel().getSubstation();
if (optionalSubstation.isEmpty()) {
@@ -40,37 +54,23 @@ public static Country getTerminalCountry(Terminal terminal) {
Substation substation = optionalSubstation.get();
Optional optionalCountry = substation.getCountry();
if (optionalCountry.isEmpty()) {
- throw new PowsyblException(String.format("Substation %s does not have country property" +
+ throw new PowsyblException(String.format("Substation %s does not have country property " +
"needed for the algorithm.", substation.getId()));
}
return optionalCountry.get();
}
- static String getLoopFlowIdFromCountry(Network network, String identifiableId) {
- Identifiable> identifiable = network.getIdentifiable(identifiableId);
- if (identifiable instanceof Injection) {
- return getLoopFlowIdFromCountry(getInjectionCountry((Injection>) identifiable));
- }
- throw new PowsyblException(String.format("Identifiable %s must be an Injection", identifiableId));
- }
-
- static Map getIndex(List idList) {
+ public static Map getIndex(List idList) {
return IntStream.range(0, idList.size())
.boxed()
- .collect(Collectors.toMap(
- idList::get,
- Function.identity()
- ));
- }
-
- public static Country getInjectionCountry(Injection> injection) {
- return getTerminalCountry(injection.getTerminal());
+ .collect(Collectors.toMap(idList::get, Function.identity()));
}
public static List getAllValidBranches(Network network) {
return network.getBranchStream()
.filter(NetworkUtil::isConnected)
- .filter(NetworkUtil::isInMainSynchronousComponent) // TODO Is connectedCompenent enough ?
+ .filter(NetworkUtil::hasABusToEachTerminal)
+ .filter(NetworkUtil::isInMainSynchronousComponent)
.collect(Collectors.toList());
}
@@ -78,16 +78,81 @@ private static boolean isConnected(Branch> branch) {
return branch.getTerminal1().isConnected() && branch.getTerminal2().isConnected();
}
+ private static boolean hasABusToEachTerminal(Branch branch) {
+ return hasABusInBusBreakerView(branch.getTerminal1()) && hasABusInBusBreakerView(branch.getTerminal2());
+ }
+
+ private static boolean hasABusInBusBreakerView(Terminal terminal1) {
+ return Objects.nonNull(terminal1.getBusBreakerView().getBus());
+ }
+
private static boolean isInMainSynchronousComponent(Branch> branch) {
return isTerminalInMainSynchronousComponent(branch.getTerminal1())
&& isTerminalInMainSynchronousComponent(branch.getTerminal2());
}
- static boolean isTerminalInMainSynchronousComponent(Terminal terminal) {
+ private static boolean isTerminalInMainSynchronousComponent(Terminal terminal) {
+ // Sensitivity analysis does not work outside synchronous component...
return terminal.getBusBreakerView().getBus().isInMainSynchronousComponent();
}
- static String getXnecId(String contingencyId, String branchId) {
- return contingencyId.isEmpty() ? branchId : String.format("%s_%s", branchId, contingencyId);
+ public static List> getNodeList(Network network) {
+ return getAllNetworkInjections(network)
+ .filter(NetworkUtil::isNotPairedDanglingLine)
+ .filter(NetworkUtil::isInjectionConnected)
+ .filter(NetworkUtil::isInjectionInMainSynchronousComponent)
+ .filter(NetworkUtil::hasReferenceInjections)
+ .filter(NetworkUtil::isValidInjectionsForSensitivityComputation)
+ .toList();
+ }
+
+ public static List> getXNodeList(Network network) {
+ return network.getDanglingLineStream()
+ .filter(NetworkUtil::isNotPairedDanglingLine)
+ .filter(NetworkUtil::isInjectionConnected)
+ .filter(NetworkUtil::isInjectionInMainSynchronousComponent)
+ .map(danglingLine -> (Injection>) danglingLine)
+ .collect(Collectors.toList());
+ }
+
+ private static Stream> getAllNetworkInjections(Network network) {
+ return network.getConnectableStream()
+ .filter(Injection.class::isInstance)
+ .map(connectable -> (Injection>) connectable);
+ }
+
+ private static boolean isNotPairedDanglingLine(Injection> injection) {
+ return !(injection instanceof DanglingLine danglingLine && danglingLine.isPaired());
+ }
+
+ private static boolean isInjectionConnected(Injection> injection) {
+ return injection.getTerminal().isConnected();
+ }
+
+ private static boolean isInjectionInMainSynchronousComponent(Injection> injection) {
+ return isTerminalInMainSynchronousComponent(injection.getTerminal());
+ }
+
+ private static boolean hasReferenceInjections(Injection> injection) {
+ return !(injection instanceof BusbarSection);
+ }
+
+ private static boolean isValidInjectionsForSensitivityComputation(Injection> injection) {
+ return !(injection instanceof ShuntCompensator || injection instanceof StaticVarCompensator);
+ }
+
+ public static List getPstIdList(Network network) {
+ return network.getTwoWindingsTransformerStream()
+ .filter(NetworkUtil::isConnected)
+ .filter(PhaseTapChangerHolder::hasPhaseTapChanger)
+ .filter(NetworkUtil::hasNeutralStep)
+ .filter(NetworkUtil::hasABusToEachTerminal)
+ .filter(NetworkUtil::isInMainSynchronousComponent)
+ .map(Identifiable::getId)
+ .toList();
+ }
+
+ private static boolean hasNeutralStep(TwoWindingsTransformer pst) {
+ return pst.getPhaseTapChanger().getNeutralStep().isPresent();
}
}
diff --git a/flow-decomposition/src/test/java/com/powsybl/flow_decomposition/FlowDecompositionObserverTest.java b/flow-decomposition/src/test/java/com/powsybl/flow_decomposition/FlowDecompositionObserverTest.java
index 327c9660..2239f08e 100644
--- a/flow-decomposition/src/test/java/com/powsybl/flow_decomposition/FlowDecompositionObserverTest.java
+++ b/flow-decomposition/src/test/java/com/powsybl/flow_decomposition/FlowDecompositionObserverTest.java
@@ -44,20 +44,20 @@ private enum Event {
* ObserverReport gathers all observed events from the flow decomposition. It keeps the events occuring, and the
* matrices
*/
- private final class ObserverReport implements FlowDecompositionObserver {
+ private static final class ObserverReport implements FlowDecompositionObserver {
- private List events = new LinkedList<>();
+ private final List events = new LinkedList<>();
private String currentContingency = null;
- private ContingencyValue> eventsPerContingency = new ContingencyValue<>();
+ private final ContingencyValue> eventsPerContingency = new ContingencyValue<>();
private Map> glsks;
private Map netPositions;
- private ContingencyValue