Skip to content

Commit

Permalink
Add DecomposedFlow rescaler proportional to max AC current load (#156)
Browse files Browse the repository at this point in the history
* Add DecomposedFlow rescaler proportional to max AC current load
* dcFlows for observers, extract static methods for DecomposedFlowRescalers
* move min flow tolerance to flow-dec-parameters
* add default rescale with null network (avoids breaking change)

---------

Signed-off-by: Caio Luke <caioluke97@gmail.com>
  • Loading branch information
caioluke authored Sep 20, 2024
1 parent 464d330 commit da53ae2
Show file tree
Hide file tree
Showing 21 changed files with 430 additions and 126 deletions.
18 changes: 16 additions & 2 deletions docs/flow_decomposition/algorithm-description.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,20 @@ The difference between reference AC flow and the sum of the parts of the decompo
parts proportionally to their rectified linear unit ($\mathrm{ReLU}(x) = \mathrm{max}(x, 0)$).

#### Proportional rescaling
Each flow is rescaled with a proportional coefficient. The coefficient is defined by $$\alpha_{\text{rescale}} = \frac{max(|AC p1|, |AC p2|)}{|DC p1|}$$.
Each flow is rescaled by a proportional coefficient. The coefficient is defined by $\alpha_{\text{rescale}} = \frac{max(|AC p1|, |AC p2|)}{|DC p1|}$.
In this way, the DC flow will have the same magnitude as the AC flow.
Since we divide by the DC flow to calculate the coefficient, lines with a too small DC flow are not rescaled.
Since we divide by the DC flow to calculate the coefficient, lines with a too small DC flow are not rescaled.

#### Max current overload rescaling
Each flow is rescaled by the same coefficient. The goal is to rescale DC flows in such a way that we find the same level of current overload as in the AC case - the maximum of the two terminals.
Therefore, we first compare AC current overloads to find which terminal (1 or 2) has the highest current overload. Then, we get the associated active power to rescale DC flows.
In case there are missing limits, we just compare AC currents instead of overloads.
Hence, the coefficient is defined as
1) With current limits:
- if $\frac{AC I1}{I_{max}1} >= \frac{AC I2}{I_{max}2}$, then $\alpha_{\text{rescale}} = \frac{\sqrt{3} \cdot AC I1 \cdot \frac{V1_{nominal}}{1000}}{|DC p1|}$
- else, $\alpha_{\text{rescale}} = \frac{\sqrt{3} \cdot AC I2 \cdot \frac{V2_{nominal}}{1000}}{|DC p1|}$
2) Without current limits:
- if $AC I1 >= AC I2$, then $\alpha_{\text{rescale}} = \frac{\sqrt{3} \cdot AC I1 \cdot \frac{V1_{nominal}}{1000}}{|DC p1|}$
- else, $\alpha_{\text{rescale}} = \frac{\sqrt{3} \cdot AC I2 \cdot \frac{V2_{nominal}}{1000}}{|DC p1|}$

Since we divide by the DC flow to calculate the coefficient, lines with a too small DC flow are not rescaled.
18 changes: 9 additions & 9 deletions docs/flow_decomposition/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

## Dedicated parameters

| Name | Type | Default value | Description |
|-------------------------------------------|---------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| enable-losses-compensation | boolean | false | When set to true, adds losses compensation step of the algorithm. Otherwise, all losses will be compensated using chosen power flow compensation strategy. |
| losses-compensation-epsilon | double | 1e-5 | Threshold used in losses compensation step of the algorihm. If actual losses are below the given threshold on a branch, no injection is created in the network to compensate these losses. Used to avoid creating too many injections in the network. May have an impact in overall algorithm performance and memory usage. |
| sensitivity-epsilon | double | 1e-5 | Threshold used when filling PTDF and PSDF matrices. If a sensitivity is below the given threshold, it is set to zero. Used to keep sparse matrices in the algorithm. May have an impact in overall algorithm performance and memory usage. |
| rescale-mode | enum | NONE | Use NONE if you don't want to rescale flow decomposition results. Use ACER_METHODOLOGY for the ACER methodology rescaling strategy. Use PROPORTIONAL for a proportional rescaling. See [Flow parts rescaling](../flow_decomposition/algorithm-description.md#flow-parts-rescaling) for more details. |
| proportional-rescaler-min-flow-tolerance | double | 1e-6 | Option only used if rescale-mode is PROPORTIONAL. Defines the minimum DC flow required in MW for the rescaling to happen. |
| dc-fallback-enabled-after-ac-divergence | boolean | true | Defines the fallback behavior after an AC divergence Use True to run DC loadflow if an AC loadflow diverges (default). Use False to throw an exception if an AC loadflow diverges. |
| sensitivity-variable-batch-size | int | 15000 | When set to a lower value, this parameter will reduce memory usage, but it might increase computation time |
| Name | Type | Default value | Description |
|-------------------------------------------|---------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| enable-losses-compensation | boolean | false | When set to true, adds losses compensation step of the algorithm. Otherwise, all losses will be compensated using chosen power flow compensation strategy. |
| losses-compensation-epsilon | double | 1e-5 | Threshold used in losses compensation step of the algorihm. If actual losses are below the given threshold on a branch, no injection is created in the network to compensate these losses. Used to avoid creating too many injections in the network. May have an impact in overall algorithm performance and memory usage. |
| sensitivity-epsilon | double | 1e-5 | Threshold used when filling PTDF and PSDF matrices. If a sensitivity is below the given threshold, it is set to zero. Used to keep sparse matrices in the algorithm. May have an impact in overall algorithm performance and memory usage. |
| rescale-mode | enum | NONE | Use NONE if you don't want to rescale flow decomposition results. Use ACER_METHODOLOGY for the ACER methodology rescaling strategy. Use PROPORTIONAL for a proportional rescaling. Use MAX_CURRENT_OVERLOAD for a rescaling based on AC current overloads. See [Flow parts rescaling](../flow_decomposition/algorithm-description.md#flow-parts-rescaling) for more details. |
| proportional-rescaler-min-flow-tolerance | double | 1e-6 | Option used from rescale modes PROPORTIONAL and MAX_CURRENT_OVERLOAD. Defines the minimum DC flow required in MW for the rescaling to happen. |
| dc-fallback-enabled-after-ac-divergence | boolean | true | Defines the fallback behavior after an AC divergence Use True to run DC loadflow if an AC loadflow diverges (default). Use False to throw an exception if an AC loadflow diverges. |
| sensitivity-variable-batch-size | int | 15000 | When set to a lower value, this parameter will reduce memory usage, but it might increase computation time |

## Impact of existing parameters

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
/**
* @author Sebastien Murgey {@literal <sebastien.murgey at rte-france.com>}
* @author Hugo Schindler {@literal <hugo.schindler at rte-france.com>}
* @author Caio Luke {@literal <caio.luke at artelys.com>}
*/
public class DecomposedFlow {
private final String branchId;
Expand All @@ -26,6 +27,8 @@ public class DecomposedFlow {
private final double xNodeFlow;
private final double pstFlow;
private final double internalFlow;
private final double acTerminal1Current;
private final double acTerminal2Current;
private final Map<String, Double> loopFlowsMap = new TreeMap<>();
static final double NO_FLOW = 0.;
static final String AC_REFERENCE_FLOW_1_COLUMN_NAME = "Reference AC Flow 1";
Expand All @@ -49,6 +52,8 @@ protected DecomposedFlow(DecomposedFlowBuilder builder) {
this.pstFlow = builder.pstFlow;
this.internalFlow = builder.internalFlow;
this.loopFlowsMap.putAll(Objects.requireNonNull(builder.loopFlowsMap));
this.acTerminal1Current = builder.acCurrentTerminal1;
this.acTerminal2Current = builder.acCurrentTerminal2;
}

public String getBranchId() {
Expand Down Expand Up @@ -123,6 +128,14 @@ public double getMaxAbsAcFlow() {
return Math.max(Math.abs(acTerminal1ReferenceFlow), Math.abs(acTerminal2ReferenceFlow));
}

public double getAcTerminal1Current() {
return acTerminal1Current;
}

public double getAcTerminal2Current() {
return acTerminal2Current;
}

@Override
public String toString() {
return String.format("branchId: %s, contingencyId: %s, decomposition: %s", branchId, contingencyId, getAllKeyMap());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public class DecomposedFlowBuilder {
protected double pstFlow;
protected double internalFlow;
protected Map<String, Double> loopFlowsMap;
protected double acCurrentTerminal1;
protected double acCurrentTerminal2;

public DecomposedFlowBuilder() {
// empty constructor
Expand Down Expand Up @@ -93,6 +95,16 @@ public DecomposedFlowBuilder withLoopFlowsMap(Map<String, Double> loopFlowsMap)
return this;
}

public DecomposedFlowBuilder withAcCurrentTerminal1(double acCurrentTerminal1) {
this.acCurrentTerminal1 = acCurrentTerminal1;
return this;
}

public DecomposedFlowBuilder withAcCurrentTerminal2(double acCurrentTerminal2) {
this.acCurrentTerminal2 = acCurrentTerminal2;
return this;
}

public DecomposedFlow build() {
return new DecomposedFlow(this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,19 @@ public static Map<String, Double> getTerminalReferenceFlow(Collection<Branch> xn
branch -> branch.getTerminal(side).getP()
));
}

public static Map<String, Double> calculateAcTerminalCurrents(Collection<Branch> xnecList, LoadFlowRunningService.Result loadFlowServiceAcResult, TwoSides side) {
if (loadFlowServiceAcResult.fallbackHasBeenActivated()) {
return xnecList.stream().collect(Collectors.toMap(Identifiable::getId, branch -> Double.NaN));
}
return getTerminalCurrent(xnecList, side);
}

public static Map<String, Double> getTerminalCurrent(Collection<Branch> xnecList, TwoSides side) {
return xnecList.stream()
.collect(Collectors.toMap(
Identifiable::getId,
branch -> branch.getTerminal(side).getI()
));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@

import com.powsybl.commons.PowsyblException;
import com.powsybl.flow_decomposition.glsk_provider.AutoGlskProvider;
import com.powsybl.flow_decomposition.rescaler.DecomposedFlowRescaler;
import com.powsybl.flow_decomposition.rescaler.DecomposedFlowRescalerAcerMethodology;
import com.powsybl.flow_decomposition.rescaler.DecomposedFlowRescalerNoOp;
import com.powsybl.flow_decomposition.rescaler.DecomposedFlowRescalerProportional;
import com.powsybl.flow_decomposition.rescaler.*;
import com.powsybl.iidm.network.Branch;
import com.powsybl.iidm.network.Country;
import com.powsybl.iidm.network.Network;
Expand Down Expand Up @@ -143,6 +140,7 @@ private void decomposeFlowForState(Network network,
LoadFlowRunningService.Result loadFlowServiceAcResult) {
// AC load flow
saveAcReferenceFlows(flowDecompositionResultsBuilder, network, xnecList, loadFlowServiceAcResult);
saveAcCurrents(flowDecompositionResultsBuilder, network, xnecList, loadFlowServiceAcResult);

// Losses compensation
compensateLosses(network);
Expand All @@ -165,7 +163,7 @@ private void decomposeFlowForState(Network network,
computeAllocatedAndLoopFlows(flowDecompositionResultsBuilder, nodalInjectionsMatrix, ptdfMatrix);
computePstFlows(network, flowDecompositionResultsBuilder, networkMatrixIndexes, psdfMatrix);

flowDecompositionResultsBuilder.build(decomposedFlowRescaler);
flowDecompositionResultsBuilder.build(decomposedFlowRescaler, network);
}

public void addObserver(FlowDecompositionObserver observer) {
Expand All @@ -189,6 +187,14 @@ private void saveAcReferenceFlows(FlowDecompositionResults.PerStateBuilder flowD
observers.computedAcNodalInjections(network, loadFlowServiceAcResult.fallbackHasBeenActivated());
}

private void saveAcCurrents(FlowDecompositionResults.PerStateBuilder flowDecompositionResultBuilder, Network network, Set<Branch> xnecList, LoadFlowRunningService.Result loadFlowServiceAcResult) {
Map<String, Double> acTerminal1Currents = FlowComputerUtils.calculateAcTerminalCurrents(xnecList, loadFlowServiceAcResult, TwoSides.ONE);
Map<String, Double> acTerminal2Currents = FlowComputerUtils.calculateAcTerminalCurrents(xnecList, loadFlowServiceAcResult, TwoSides.TWO);
flowDecompositionResultBuilder.saveAcCurrentTerminal1(acTerminal1Currents);
flowDecompositionResultBuilder.saveAcCurrentTerminal2(acTerminal2Currents);
observers.computedAcCurrents(network, loadFlowServiceAcResult);
}

private Map<Country, Double> getZonesNetPosition(Network network) {
NetPositionComputer netPositionComputer = new NetPositionComputer();
return netPositionComputer.run(network);
Expand All @@ -205,6 +211,7 @@ private DecomposedFlowRescaler getDecomposedFlowRescaler() {
case NONE -> new DecomposedFlowRescalerNoOp();
case ACER_METHODOLOGY -> new DecomposedFlowRescalerAcerMethodology();
case PROPORTIONAL -> new DecomposedFlowRescalerProportional(parameters.getProportionalRescalerMinFlowTolerance());
case MAX_CURRENT_OVERLOAD -> new DecomposedFlowRescalerMaxCurrentOverload(parameters.getProportionalRescalerMinFlowTolerance());
default -> throw new PowsyblException("DecomposedFlowRescaler not defined for mode: " + parameters.getRescaleMode());
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,35 @@ public interface FlowDecompositionObserver {
/**
* Called when the AC loadflow is computed (for base case or contingency)
*
* @param flows the flows for all branches
* @param flows the terminal 1 flow for all branches
*/
void computedAcFlowsTerminal1(Map<String, Double> flows);

/**
* Called when the AC loadflow is computed (for base case or contingency)
*
* @param flows the terminal 2 flow for all branches
*/
void computedAcFlows(Map<String, Double> flows);
void computedAcFlowsTerminal2(Map<String, Double> flows);

/**
* Called when the DC loadflow is computed (for base case or contingency)
*
* @param flows the flows for all branches
*/
void computedDcFlows(Map<String, Double> flows);

/**
* Called when the AC loadflow is computed (for base case or contingency)
*
* @param currents the terminal 1 current for all branches
*/
void computedAcCurrentsTerminal1(Map<String, Double> currents);

/**
* Called when the AC loadflow is computed (for base case or contingency)
*
* @param currents the terminal 1 current for all branches
*/
void computedAcCurrentsTerminal2(Map<String, Double> currents);
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,9 @@ public void computedAcFlows(Network network, Result loadFlowServiceAcResult) {
return;
}

Map<String, Double> acFlows = FlowComputerUtils.calculateAcTerminalReferenceFlows(network.getBranchStream().toList(), loadFlowServiceAcResult, TwoSides.ONE);

for (FlowDecompositionObserver o : observers) {
o.computedAcFlows(acFlows);
o.computedAcFlowsTerminal1(FlowComputerUtils.calculateAcTerminalReferenceFlows(network.getBranchStream().toList(), loadFlowServiceAcResult, TwoSides.ONE));
o.computedAcFlowsTerminal2(FlowComputerUtils.calculateAcTerminalReferenceFlows(network.getBranchStream().toList(), loadFlowServiceAcResult, TwoSides.TWO));
}
}

Expand All @@ -100,10 +99,19 @@ public void computedDcFlows(Network network) {
return;
}

Map<String, Double> dcFlows = FlowComputerUtils.getTerminalReferenceFlow(network.getBranchStream().toList(), TwoSides.ONE);
for (FlowDecompositionObserver o : observers) {
o.computedDcFlows(FlowComputerUtils.getTerminalReferenceFlow(network.getBranchStream().toList(), TwoSides.ONE));
}
}

public void computedAcCurrents(Network network, Result loadFlowServiceAcResult) {
if (observers.isEmpty()) {
return;
}

for (FlowDecompositionObserver o : observers) {
o.computedDcFlows(dcFlows);
o.computedAcCurrentsTerminal1(FlowComputerUtils.calculateAcTerminalCurrents(network.getBranchStream().toList(), loadFlowServiceAcResult, TwoSides.ONE));
o.computedAcCurrentsTerminal2(FlowComputerUtils.calculateAcTerminalCurrents(network.getBranchStream().toList(), loadFlowServiceAcResult, TwoSides.TWO));
}
}

Expand Down
Loading

0 comments on commit da53ae2

Please sign in to comment.