Skip to content

Commit

Permalink
Merge branch 'main' into bugfix/pst-non-impedant-branch-bus-imbalance
Browse files Browse the repository at this point in the history
  • Loading branch information
vidaldid-rte authored Dec 11, 2024
2 parents 93bad2d + 04068b8 commit 697769a
Show file tree
Hide file tree
Showing 21 changed files with 1,612 additions and 252 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Heterogeneous voltage controls management has become a key feature. All well-mod
- Complex cases where the contingency leads to another synchronous component where a new resolution has to be performed are not supported at that stage. The loss of slack bus during a contingency is not supported yet, but the work is in progress.
- The active and reactive power flows on branches, as well as angle and voltage at buses, can be monitored and collected for later analysis after the base case and after each contingency.
- Remedial actions such as: switch action, terminal(s) connection action, re-dispatching action
- Fast DC mode available, based on Woodbury's formula for calculating post-contingency states. Note that this mode has limitations for the moment. Remedial actions are not yet taken into account, as well as contingencies on HVDC lines in AC emulation mode.
- Fast DC mode available, based on Woodbury's formula for calculating post-contingency states. Note that this mode has limitations for the moment. Only PST remedial actions are taken into account now. Contingencies on HVDC lines are not yet taken into account in AC emulation mode.

### Sensitivity analysis implementation

Expand Down
5 changes: 3 additions & 2 deletions docs/security/parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@ when DC mode is activated.
Please note that fast mode has a few limitations:
- Contingencies applied on branches opened on one side are ignored.
- Contingencies applied on HVDC lines in AC emulation mode are ignored.
- No remedial action is currently supported.
- Slack relocation following the application of a contingency is not supported.
- Only PST remedial actions are supported for now.
- Slack relocation following the application of a contingency is not supported.
As a result, security analysis is carried out only in slack component, and not necessarily in the largest one.

The default value is `false`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.powsybl.openloadflow.network.LfBranch;
import com.powsybl.openloadflow.network.LfBus;
import com.powsybl.openloadflow.network.PiModel;
import com.powsybl.openloadflow.network.PiModelArray;

import java.util.List;
import java.util.Objects;
Expand All @@ -34,7 +35,13 @@ public abstract class AbstractClosedBranchDcFlowEquationTerm extends AbstractEle

protected final List<Variable<DcVariableType>> variables;

protected final double power;
private final double power;

private final boolean isPowerPreComputed;

protected final boolean useTransformerRatio;

protected DcApproximationType dcApproximationType;

protected AbstractClosedBranchDcFlowEquationTerm(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet<DcVariableType> variableSet,
boolean deriveA1, boolean useTransformerRatio, DcApproximationType dcApproximationType) {
Expand All @@ -46,15 +53,25 @@ protected AbstractClosedBranchDcFlowEquationTerm(LfBranch branch, LfBus bus1, Lf
ph1Var = variableSet.getVariable(bus1.getNum(), DcVariableType.BUS_PHI);
ph2Var = variableSet.getVariable(bus2.getNum(), DcVariableType.BUS_PHI);
a1Var = deriveA1 ? variableSet.getVariable(branch.getNum(), DcVariableType.BRANCH_ALPHA1) : null;
power = calculatePower(useTransformerRatio, dcApproximationType, piModel);
this.useTransformerRatio = useTransformerRatio;
this.dcApproximationType = dcApproximationType;
isPowerPreComputed = !(piModel instanceof PiModelArray);
power = isPowerPreComputed ? computePower(useTransformerRatio, dcApproximationType, piModel) : Double.NaN;
if (a1Var != null) {
variables = List.of(ph1Var, ph2Var, a1Var);
} else {
variables = List.of(ph1Var, ph2Var);
}
}

public static double calculatePower(boolean useTransformerRatio, DcApproximationType dcApproximationType, PiModel piModel) {
/**
* Update power only if the branch is a PiModelArray.
*/
protected double getPower() {
return isPowerPreComputed ? power : computePower(useTransformerRatio, dcApproximationType, element.getPiModel());
}

public static double computePower(boolean useTransformerRatio, DcApproximationType dcApproximationType, PiModel piModel) {
double b = switch (dcApproximationType) {
case IGNORE_R -> 1d / piModel.getX();
case IGNORE_G -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,18 @@ public static ClosedBranchSide1DcFlowEquationTerm create(LfBranch branch, LfBus
@Override
protected double eval(double ph1, double ph2, double a1) {
double deltaPhase = ph2 - ph1 + A2 - a1;
return -power * deltaPhase;
return -getPower() * deltaPhase;
}

@Override
public double der(Variable<DcVariableType> variable) {
Objects.requireNonNull(variable);
if (variable.equals(ph1Var)) {
return power;
return getPower();
} else if (variable.equals(ph2Var)) {
return -power;
return -getPower();
} else if (variable.equals(a1Var)) {
return power;
return getPower();
} else {
throw new IllegalStateException("Unknown variable: " + variable);
}
Expand All @@ -58,9 +58,9 @@ public double der(Variable<DcVariableType> variable) {
@Override
public double rhs() {
if (a1Var != null) {
return -power * A2;
return -getPower() * A2;
} else {
return -power * (A2 - a1());
return -getPower() * (A2 - a1());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,18 @@ public static ClosedBranchSide2DcFlowEquationTerm create(LfBranch branch, LfBus
@Override
protected double eval(double ph1, double ph2, double a1) {
double deltaPhase = ph2 - ph1 + A2 - a1;
return power * deltaPhase;
return getPower() * deltaPhase;
}

@Override
public double der(Variable<DcVariableType> variable) {
Objects.requireNonNull(variable);
if (variable.equals(ph1Var)) {
return -power;
return -getPower();
} else if (variable.equals(ph2Var)) {
return power;
return getPower();
} else if (variable.equals(a1Var)) {
return -power;
return -getPower();
} else {
throw new IllegalStateException("Unknown variable: " + variable);
}
Expand All @@ -58,9 +58,9 @@ public double der(Variable<DcVariableType> variable) {
@Override
public double rhs() {
if (a1Var != null) {
return power * A2;
return getPower() * A2;
} else {
return power * (A2 - a1());
return getPower() * (A2 - a1());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,71 +24,20 @@
* @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
* @author Gaël Macherel {@literal <gael.macherel@artelys.com>}
*/
public final class ComputedContingencyElement {
public final class ComputedContingencyElement extends ComputedElement {

private int contingencyIndex = -1; // index of the element in the rhs for +1-1
private int localIndex = -1; // local index of the element : index of the element in the matrix used in the setAlphas method
private double alphaForPostContingencyState = Double.NaN;
private final ContingencyElement element;
private final LfBranch lfBranch;
private final ClosedBranchSide1DcFlowEquationTerm branchEquation;

public ComputedContingencyElement(final ContingencyElement element, LfNetwork lfNetwork, EquationSystem<DcVariableType, DcEquationType> equationSystem) {
super(lfNetwork.getBranchById(element.getId()),
equationSystem.getEquationTerm(ElementType.BRANCH, lfNetwork.getBranchById(element.getId()).getNum(), ClosedBranchSide1DcFlowEquationTerm.class));
this.element = element;
lfBranch = lfNetwork.getBranchById(element.getId());
branchEquation = equationSystem.getEquationTerm(ElementType.BRANCH, lfBranch.getNum(), ClosedBranchSide1DcFlowEquationTerm.class);
}

public int getContingencyIndex() {
return contingencyIndex;
}

public void setContingencyIndex(final int index) {
this.contingencyIndex = index;
}

public int getLocalIndex() {
return localIndex;
}

private void setLocalIndex(final int index) {
this.localIndex = index;
}

public double getAlphaForPostContingencyState() {
return alphaForPostContingencyState;
}

public void setAlphaForPostContingencyState(double alphaForPostContingencyStates) {
this.alphaForPostContingencyState = alphaForPostContingencyStates;
}

public ContingencyElement getElement() {
return element;
}

public LfBranch getLfBranch() {
return lfBranch;
}

public ClosedBranchSide1DcFlowEquationTerm getLfBranchEquation() {
return branchEquation;
}

public static void setContingencyIndexes(Collection<ComputedContingencyElement> elements) {
int index = 0;
for (ComputedContingencyElement element : elements) {
element.setContingencyIndex(index++);
}
}

public static void setLocalIndexes(Collection<ComputedContingencyElement> elements) {
int index = 0;
for (ComputedContingencyElement element : elements) {
element.setLocalIndex(index++);
}
}

public static void applyToConnectivity(LfNetwork lfNetwork, GraphConnectivity<LfBus, LfBranch> connectivity, Collection<ComputedContingencyElement> breakingConnectivityElements) {
breakingConnectivityElements.stream()
.map(ComputedContingencyElement::getElement)
Expand Down
131 changes: 131 additions & 0 deletions src/main/java/com/powsybl/openloadflow/dc/fastdc/ComputedElement.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/**
* Copyright (c) 2020, 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.openloadflow.dc.fastdc;

import com.powsybl.commons.PowsyblException;
import com.powsybl.math.matrix.DenseMatrix;
import com.powsybl.math.matrix.Matrix;
import com.powsybl.openloadflow.dc.DcLoadFlowContext;
import com.powsybl.openloadflow.dc.equations.ClosedBranchSide1DcFlowEquationTerm;
import com.powsybl.openloadflow.dc.equations.DcEquationType;
import com.powsybl.openloadflow.dc.equations.DcVariableType;
import com.powsybl.openloadflow.equations.Equation;
import com.powsybl.openloadflow.equations.EquationSystem;
import com.powsybl.openloadflow.network.LfBranch;
import com.powsybl.openloadflow.network.LfBus;

import java.util.Collection;

/**
* @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
* @author Gaël Macherel {@literal <gael.macherel@artelys.com>}
*/
public class ComputedElement {
private int computedElementIndex = -1; // index of the element in the rhs for +1-1
private int localIndex = -1; // local index of the element : index of the element in the matrix used in the setAlphas method
private double alphaForWoodburyComputation = Double.NaN;
private final LfBranch lfBranch;
private final ClosedBranchSide1DcFlowEquationTerm branchEquation;

public ComputedElement(LfBranch lfBranch, ClosedBranchSide1DcFlowEquationTerm branchEquation) {
this.lfBranch = lfBranch;
this.branchEquation = branchEquation;
}

public int getComputedElementIndex() {
return computedElementIndex;
}

public void setComputedElementIndex(final int index) {
this.computedElementIndex = index;
}

public int getLocalIndex() {
return localIndex;
}

protected void setLocalIndex(final int index) {
this.localIndex = index;
}

public double getAlphaForWoodburyComputation() {
return alphaForWoodburyComputation;
}

public void setAlphaForWoodburyComputation(double alphaForPostContingencyStates) {
this.alphaForWoodburyComputation = alphaForPostContingencyStates;
}

public LfBranch getLfBranch() {
return lfBranch;
}

public ClosedBranchSide1DcFlowEquationTerm getLfBranchEquation() {
return branchEquation;
}

public static void setComputedElementIndexes(Collection<? extends ComputedElement> elements) {
int index = 0;
for (ComputedElement element : elements) {
element.setComputedElementIndex(index++);
}
}

public static void setLocalIndexes(Collection<? extends ComputedElement> elements) {
int index = 0;
for (ComputedElement element : elements) {
element.setLocalIndex(index++);
}
}

/**
* Fills the right hand side with +1/-1 to model a branch contingency or action.
*/
private static void fillRhs(EquationSystem<DcVariableType, DcEquationType> equationSystem, Collection<? extends ComputedElement> computedElements, Matrix rhs) {
for (ComputedElement element : computedElements) {
LfBranch lfBranch = element.getLfBranch();
if (lfBranch.getBus1() == null || lfBranch.getBus2() == null) {
continue;
}
LfBus bus1 = lfBranch.getBus1();
LfBus bus2 = lfBranch.getBus2();
if (bus1.isSlack()) {
Equation<DcVariableType, DcEquationType> p = equationSystem.getEquation(bus2.getNum(), DcEquationType.BUS_TARGET_P).orElseThrow(IllegalStateException::new);
rhs.set(p.getColumn(), element.getComputedElementIndex(), -1);
} else if (bus2.isSlack()) {
Equation<DcVariableType, DcEquationType> p = equationSystem.getEquation(bus1.getNum(), DcEquationType.BUS_TARGET_P).orElseThrow(IllegalStateException::new);
rhs.set(p.getColumn(), element.getComputedElementIndex(), 1);
} else {
Equation<DcVariableType, DcEquationType> p1 = equationSystem.getEquation(bus1.getNum(), DcEquationType.BUS_TARGET_P).orElseThrow(IllegalStateException::new);
Equation<DcVariableType, DcEquationType> p2 = equationSystem.getEquation(bus2.getNum(), DcEquationType.BUS_TARGET_P).orElseThrow(IllegalStateException::new);
rhs.set(p1.getColumn(), element.getComputedElementIndex(), 1);
rhs.set(p2.getColumn(), element.getComputedElementIndex(), -1);
}
}
}

public static DenseMatrix initRhs(EquationSystem<DcVariableType, DcEquationType> equationSystem, Collection<? extends ComputedElement> elements) {
// otherwise, defining the rhs matrix will result in integer overflow
int equationCount = equationSystem.getIndex().getSortedEquationsToSolve().size();
int maxElements = Integer.MAX_VALUE / (equationCount * Double.BYTES);
if (elements.size() > maxElements) {
throw new PowsyblException("Too many elements " + elements.size()
+ ", maximum is " + maxElements + " for a system with " + equationCount + " equations");
}

DenseMatrix rhs = new DenseMatrix(equationCount, elements.size());
fillRhs(equationSystem, elements, rhs);
return rhs;
}

public static DenseMatrix calculateElementsStates(DcLoadFlowContext loadFlowContext, Collection<? extends ComputedElement> computedElements) {
DenseMatrix elementsStates = initRhs(loadFlowContext.getEquationSystem(), computedElements); // rhs with +1 -1 on computed elements
loadFlowContext.getJacobianMatrix().solveTransposed(elementsStates);
return elementsStates;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Copyright (c) 2024, Coreso SA (https://www.coreso.eu/) and TSCNET Services GmbH (https://www.tscnet.eu/)
* 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.openloadflow.dc.fastdc;

import com.powsybl.openloadflow.dc.equations.ClosedBranchSide1DcFlowEquationTerm;
import com.powsybl.openloadflow.dc.equations.DcEquationType;
import com.powsybl.openloadflow.dc.equations.DcVariableType;
import com.powsybl.openloadflow.equations.EquationSystem;
import com.powsybl.openloadflow.network.ElementType;
import com.powsybl.openloadflow.network.TapPositionChange;

/**
* @author Pierre Arvy {@literal <pierre.arvy@artelys.com>}
*/
public final class ComputedTapPositionChangeElement extends ComputedElement {

private final TapPositionChange tapPositionChange;

public ComputedTapPositionChangeElement(TapPositionChange tapPositionChange, EquationSystem<DcVariableType, DcEquationType> equationSystem) {
super(tapPositionChange.getBranch(), equationSystem.getEquationTerm(ElementType.BRANCH, tapPositionChange.getBranch().getNum(), ClosedBranchSide1DcFlowEquationTerm.class));
this.tapPositionChange = tapPositionChange;
}

public TapPositionChange getTapPositionChange() {
return tapPositionChange;
}
}
Loading

0 comments on commit 697769a

Please sign in to comment.