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

DcValueVoltageInitializer fails in presence of resistive only branches #683

Merged
merged 9 commits into from
Jan 6, 2023
20 changes: 10 additions & 10 deletions src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@
import com.powsybl.math.matrix.MatrixFactory;
import com.powsybl.math.matrix.SparseMatrixFactory;
import com.powsybl.openloadflow.ac.nr.NewtonRaphsonStatus;
import com.powsybl.openloadflow.ac.outerloop.*;
import com.powsybl.openloadflow.ac.outerloop.AcLoadFlowParameters;
import com.powsybl.openloadflow.ac.outerloop.AcLoadFlowResult;
import com.powsybl.openloadflow.ac.outerloop.AcloadFlowEngine;
import com.powsybl.openloadflow.ac.outerloop.OuterLoop;
import com.powsybl.openloadflow.dc.DcLoadFlowEngine;
import com.powsybl.openloadflow.dc.DcLoadFlowResult;
import com.powsybl.openloadflow.graph.EvenShiloachGraphDecrementalConnectivityFactory;
Expand All @@ -38,7 +41,6 @@
import com.powsybl.tools.PowsyblCoreVersion;
import org.jgrapht.Graph;
import org.jgrapht.alg.interfaces.SpanningTreeAlgorithm;
import org.jgrapht.alg.spanning.KruskalMinimumSpanningTree;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -127,7 +129,7 @@ private LoadFlowResult runAc(Network network, LoadFlowParameters parameters, Rep
result.getNetwork().updateState(updateParameters);

// zero or low impedance branch flows computation
computeZeroImpedanceFlows(result.getNetwork());
computeZeroImpedanceFlows(result.getNetwork(), false);
}

LoadFlowResult.ComponentResult.Status status;
Expand Down Expand Up @@ -159,12 +161,10 @@ private LoadFlowResult runAc(Network network, LoadFlowParameters parameters, Rep
return new LoadFlowResultImpl(ok, Collections.emptyMap(), null, componentResults);
}

private void computeZeroImpedanceFlows(LfNetwork network) {
Graph<LfBus, LfBranch> zeroImpedanceSubGraph = network.createZeroImpedanceSubGraph();
if (!zeroImpedanceSubGraph.vertexSet().isEmpty()) {
SpanningTreeAlgorithm.SpanningTree<LfBranch> spanningTree = new KruskalMinimumSpanningTree<>(zeroImpedanceSubGraph).getSpanningTree();
new ZeroImpedanceFlows(zeroImpedanceSubGraph, spanningTree).compute();
}
private void computeZeroImpedanceFlows(LfNetwork network, boolean dc) {
Graph<LfBus, LfBranch> zeroImpedanceSubGraph = network.getZeroImpedanceSubGraph(dc);
SpanningTreeAlgorithm.SpanningTree<LfBranch> spanningTree = network.getZeroImpedanceSpanningTree(dc);
new ZeroImpedanceFlows(zeroImpedanceSubGraph, spanningTree, dc).compute();
}

private LoadFlowResult runDc(Network network, LoadFlowParameters parameters, Reporter reporter) {
Expand Down Expand Up @@ -197,7 +197,7 @@ private LoadFlowResult.ComponentResult processResult(Network network, DcLoadFlow
result.getNetwork().updateState(updateParameters);

// zero or low impedance branch flows computation
computeZeroImpedanceFlows(result.getNetwork());
computeZeroImpedanceFlows(result.getNetwork(), true);
}

return new LoadFlowResultImpl.ComponentResultImpl(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,8 @@ private List<EquationTerm<AcVariableType, AcEquationType>> createReactiveTerms(L
List<EquationTerm<AcVariableType, AcEquationType>> terms = new ArrayList<>();
for (LfBranch branch : controllerBus.getBranches()) {
EquationTerm<AcVariableType, AcEquationType> q;
if (branch.isZeroImpedance()) {
if (!branch.isSpanningTreeEdge()) {
if (branch.isZeroImpedance(false)) {
if (!branch.isSpanningTreeEdge(false)) {
continue;
}
if (branch.getBus1() == controllerBus) {
Expand Down Expand Up @@ -739,8 +739,8 @@ private static void createHvdcAcEmulationEquations(LfHvdc hvdc, EquationSystem<A
private void createBranchEquations(LfBranch branch,
EquationSystem<AcVariableType, AcEquationType> equationSystem) {
// create zero and non zero impedance branch equations
if (branch.isZeroImpedance()) {
if (branch.isSpanningTreeEdge()) {
if (branch.isZeroImpedance(false)) {
if (branch.isSpanningTreeEdge(false)) {
createNonImpedantBranch(branch, branch.getBus1(), branch.getBus2(), equationSystem);
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
public class AcEquationSystemUpdater extends AbstractEquationSystemUpdater<AcVariableType, AcEquationType> {

public AcEquationSystemUpdater(EquationSystem<AcVariableType, AcEquationType> equationSystem) {
super(equationSystem);
super(equationSystem, false);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ private void createBranches(EquationSystem<DcVariableType, DcEquationType> equat
for (LfBranch branch : network.getBranches()) {
LfBus bus1 = branch.getBus1();
LfBus bus2 = branch.getBus2();
if (branch.isZeroImpedance()) {
if (branch.isSpanningTreeEdge()) {
if (branch.isZeroImpedance(true)) {
if (branch.isSpanningTreeEdge(true)) {
createNonImpedantBranch(equationSystem, branch, bus1, bus2);
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
public class DcEquationSystemUpdater extends AbstractEquationSystemUpdater<DcVariableType, DcEquationType> {

public DcEquationSystemUpdater(EquationSystem<DcVariableType, DcEquationType> equationSystem) {
super(equationSystem);
super(equationSystem, true);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ public abstract class AbstractEquationSystemUpdater<V extends Enum<V> & Quantity

protected final EquationSystem<V, E> equationSystem;

protected AbstractEquationSystemUpdater(EquationSystem<V, E> equationSystem) {
protected final boolean dc;

protected AbstractEquationSystemUpdater(EquationSystem<V, E> equationSystem, boolean dc) {
this.equationSystem = equationSystem;
this.dc = dc;
}

protected static void checkSlackBus(LfBus bus, boolean disabled) {
Expand All @@ -35,7 +38,7 @@ protected static void checkSlackBus(LfBus bus, boolean disabled) {
protected abstract void updateNonImpedantBranchEquations(LfBranch branch, boolean enable);

protected void updateElementEquations(LfElement element, boolean enable) {
if (element instanceof LfBranch && ((LfBranch) element).isZeroImpedance() && ((LfBranch) element).isSpanningTreeEdge()) {
if (element instanceof LfBranch && ((LfBranch) element).isZeroImpedance(dc) && ((LfBranch) element).isSpanningTreeEdge(dc)) {
updateNonImpedantBranchEquations((LfBranch) element, enable);
} else {
// update all equations related to the element
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/com/powsybl/openloadflow/network/LfBranch.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,11 @@ default List<LfLimit> getLimits2(LimitType type) {

double computeApparentPower2();

boolean isZeroImpedance();
boolean isZeroImpedance(boolean dc);

void setSpanningTreeEdge(boolean spanningTreeEdge);
void setSpanningTreeEdge(boolean dc, boolean spanningTreeEdge);

boolean isSpanningTreeEdge();
boolean isSpanningTreeEdge(boolean dc);

Evaluable getA1();

Expand Down Expand Up @@ -174,5 +174,5 @@ static double getDiscretePhaseControlTarget(LfBranch branch, DiscretePhaseContro

boolean isConnectedAtBothSides();

void setMinZ(boolean dc, double lowImpedanceThreshold);
void setMinZ(double lowImpedanceThreshold);
}
73 changes: 63 additions & 10 deletions src/main/java/com/powsybl/openloadflow/network/LfNetwork.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import com.powsybl.openloadflow.util.PerUnit;
import com.powsybl.openloadflow.util.Reports;
import org.jgrapht.Graph;
import org.jgrapht.alg.interfaces.SpanningTreeAlgorithm;
import org.jgrapht.alg.spanning.KruskalMinimumSpanningTree;
import org.jgrapht.graph.Pseudograph;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -75,6 +77,14 @@ public class LfNetwork extends AbstractPropertyBag implements PropertyBag {

private GraphConnectivity<LfBus, LfBranch> connectivity;

private Graph<LfBus, LfBranch> dcZeroImpedanceSubGraph;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe zeroImpedanceSubGraph and zeroImpedanceSpanningTree could be grouped in another object.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it could be a good idea.


private Graph<LfBus, LfBranch> acZeroImpedanceSubGraph;

private SpanningTreeAlgorithm.SpanningTree<LfBranch> dcZeroImpedanceSpanningTree;

private SpanningTreeAlgorithm.SpanningTree<LfBranch> acZeroImpedanceSpanningTree;

private Reporter reporter;

public LfNetwork(int numCC, int numSC, SlackBusSelector slackBusSelector,
Expand Down Expand Up @@ -120,13 +130,21 @@ public void updateSlack() {
}
}

private void invalidateZeroImpedanceSubGraphs() {
dcZeroImpedanceSubGraph = null;
acZeroImpedanceSubGraph = null;
dcZeroImpedanceSpanningTree = null;
acZeroImpedanceSpanningTree = null;
}

public void addBranch(LfBranch branch) {
Objects.requireNonNull(branch);
branch.setNum(branches.size());
branches.add(branch);
branchesById.put(branch.getId(), branch);
invalidateSlack();
connectivity = null;
invalidateZeroImpedanceSubGraphs();

// create bus -> branches link
if (branch.getBus1() != null) {
Expand Down Expand Up @@ -447,10 +465,10 @@ public void reportBalance(Reporter reporter) {
this, activeGeneration, activeLoad, reactiveGeneration, reactiveLoad);
}

public void fix(boolean minImpedance, boolean dc, double lowImpedanceThreshold) {
public void fix(boolean minImpedance, double lowImpedanceThreshold) {
if (minImpedance) {
for (LfBranch branch : branches) {
branch.setMinZ(dc, lowImpedanceThreshold);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should not do this here at a post loading fix. z cut could be done in a cleaner way at branch creation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has been designed like that because min z what dependent of the AC or DC context. Now, as we store both, we can do that at branch creation. Do you want me to do this?

branch.setMinZ(lowImpedanceThreshold);
}
}
}
Expand Down Expand Up @@ -496,7 +514,7 @@ public static <T> List<LfNetwork> load(T network, LfNetworkLoader<T> networkLoad
List<LfNetwork> lfNetworks = networkLoader.load(network, parameters, reporter);
for (LfNetwork lfNetwork : lfNetworks) {
Reporter reporterNetwork = Reports.createPostLoadingProcessingReporter(lfNetwork.getReporter());
lfNetwork.fix(parameters.isMinImpedance(), parameters.isDc(), parameters.getLowImpedanceThreshold());
lfNetwork.fix(parameters.isMinImpedance(), parameters.getLowImpedanceThreshold());
lfNetwork.validate(parameters.isDc(), reporterNetwork);
if (lfNetwork.isValid()) {
lfNetwork.reportSize(reporterNetwork);
Expand All @@ -508,25 +526,60 @@ public static <T> List<LfNetwork> load(T network, LfNetworkLoader<T> networkLoad
return lfNetworks;
}

private static SpanningTreeAlgorithm.SpanningTree<LfBranch> createZeroImpedanceSpanningTree(Graph<LfBus, LfBranch> zeroImpedanceSubGraph, boolean dc) {
if (!zeroImpedanceSubGraph.vertexSet().isEmpty()) {
SpanningTreeAlgorithm.SpanningTree<LfBranch> spanningTree = new KruskalMinimumSpanningTree<>(zeroImpedanceSubGraph).getSpanningTree();
for (LfBranch branch : spanningTree.getEdges()) {
branch.setSpanningTreeEdge(dc, true);
}
return spanningTree;
}
return null;
}

public void updateZeroImpedanceCache(boolean dc) {
if (dc) {
if (dcZeroImpedanceSubGraph == null) {
dcZeroImpedanceSubGraph = createZeroImpedanceSubGraph(true);
dcZeroImpedanceSpanningTree = createZeroImpedanceSpanningTree(dcZeroImpedanceSubGraph, true);
}
} else {
if (acZeroImpedanceSubGraph == null) {
acZeroImpedanceSubGraph = createZeroImpedanceSubGraph(false);
acZeroImpedanceSpanningTree = createZeroImpedanceSpanningTree(acZeroImpedanceSubGraph, false);
}
}
}

public Graph<LfBus, LfBranch> getZeroImpedanceSubGraph(boolean dc) {
updateZeroImpedanceCache(dc);
return dc ? dcZeroImpedanceSubGraph : acZeroImpedanceSubGraph;
}

public SpanningTreeAlgorithm.SpanningTree<LfBranch> getZeroImpedanceSpanningTree(boolean dc) {
updateZeroImpedanceCache(dc);
return dc ? dcZeroImpedanceSpanningTree : acZeroImpedanceSpanningTree;
}

/**
* Create the subgraph of zero-impedance LfBranches and their corresponding LfBuses
* The graph is intentionally not cached as a parameter so far, to avoid the complexity of invalidating it if changes occur
* Create the subgraph of zero-impedance LfBranches and their corresponding LfBuses.
*
* @return the zero-impedance subgraph
*/
public Graph<LfBus, LfBranch> createZeroImpedanceSubGraph() {
return createSubGraph(branch -> branch.isZeroImpedance()
private Graph<LfBus, LfBranch> createZeroImpedanceSubGraph(boolean dc) {
return createSubGraph(branch -> branch.isZeroImpedance(dc)
&& branch.getBus1() != null && branch.getBus2() != null);
}

public Graph<LfBus, LfBranch> createSubGraph(Predicate<LfBranch> branchFilter) {
private Graph<LfBus, LfBranch> createSubGraph(Predicate<LfBranch> branchFilter) {
Objects.requireNonNull(branchFilter);

List<LfBranch> zeroImpedanceBranches = getBranches().stream()
List<LfBranch> filteredBranches = getBranches().stream()
.filter(branchFilter)
.collect(Collectors.toList());

Graph<LfBus, LfBranch> subGraph = new Pseudograph<>(LfBranch.class);
for (LfBranch branch : zeroImpedanceBranches) {
for (LfBranch branch : filteredBranches) {
subGraph.addVertex(branch.getBus1());
subGraph.addVertex(branch.getBus2());
subGraph.addEdge(branch.getBus1(), branch.getBus2(), branch);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,28 @@ public abstract class AbstractLfBranch extends AbstractElement implements LfBran

protected boolean voltageControlEnabled = false;

protected boolean spanningTreeEdge = false;
protected boolean dcSpanningTreeEdge = false;

protected boolean acSpanningTreeEdge = false;

protected Evaluable a1;

private ReactivePowerControl reactivePowerControl;

protected boolean zeroImpedance;
protected boolean dcZeroImpedance = false;

protected boolean acZeroImpedance = false;

protected AbstractLfBranch(LfNetwork network, LfBus bus1, LfBus bus2, PiModel piModel, LfNetworkParameters parameters) {
super(network);
this.bus1 = bus1;
this.bus2 = bus2;
this.piModel = Objects.requireNonNull(piModel);
this.piModel.setBranch(this);
zeroImpedance = isZeroImpedanceBranch(piModel, parameters);
if (!parameters.isMinImpedance()) {
dcZeroImpedance = isZeroImpedanceBranch(piModel, true, parameters.getLowImpedanceThreshold());
acZeroImpedance = isZeroImpedanceBranch(piModel, false, parameters.getLowImpedanceThreshold());
}
}

protected static List<LfLimit> createSortedLimitsList(LoadingLimits loadingLimits, LfBus bus) {
Expand Down Expand Up @@ -247,18 +254,23 @@ public double computeApparentPower2() {
}

@Override
public boolean isZeroImpedance() {
return this.zeroImpedance;
public boolean isZeroImpedance(boolean dc) {
return dc ? dcZeroImpedance : acZeroImpedance;
}

@Override
public void setSpanningTreeEdge(boolean spanningTreeEdge) {
this.spanningTreeEdge = spanningTreeEdge;
public void setSpanningTreeEdge(boolean dc, boolean spanningTreeEdge) {
if (dc) {
dcSpanningTreeEdge = spanningTreeEdge;
} else {
acSpanningTreeEdge = spanningTreeEdge;
}
}

@Override
public boolean isSpanningTreeEdge() {
return this.spanningTreeEdge;
public boolean isSpanningTreeEdge(boolean dc) {
network.updateZeroImpedanceCache(dc);
return dc ? dcSpanningTreeEdge : acSpanningTreeEdge;
}

@Override
Expand Down Expand Up @@ -286,18 +298,24 @@ public boolean isConnectedAtBothSides() {
}

@Override
public void setMinZ(boolean dc, double lowImpedanceThreshold) {
if (piModel.setMinZ(lowImpedanceThreshold, dc)) {
LOGGER.trace("Branch {} has a low impedance, set to min {}", getId(), lowImpedanceThreshold);
public void setMinZ(double lowImpedanceThreshold) {
if (piModel.setMinZ(lowImpedanceThreshold, true)) {
LOGGER.trace("Branch {} has a low impedance (dc = true), set to min {}",
getId(), lowImpedanceThreshold);
dcZeroImpedance = false;
}
if (piModel.setMinZ(lowImpedanceThreshold, false)) {
LOGGER.trace("Branch {} has a low impedance (dc = false), set to min {}",
getId(), lowImpedanceThreshold);
acZeroImpedance = false;
}
this.zeroImpedance = false;
}

private static boolean isZeroImpedanceBranch(PiModel piModel, LfNetworkParameters parameters) {
if (parameters.isDc()) {
return FastMath.abs(piModel.getX()) < parameters.getLowImpedanceThreshold();
private static boolean isZeroImpedanceBranch(PiModel piModel, boolean dc, double lowImpedanceThreshold) {
if (dc) {
return FastMath.abs(piModel.getX()) < lowImpedanceThreshold;
} else {
return piModel.getZ() < parameters.getLowImpedanceThreshold();
return piModel.getZ() < lowImpedanceThreshold;
}
}
}
Loading