Skip to content
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion docs/loadflow/loadflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ $\sum_{i} I_i + \frac{V_1 - V_2}{R}= 0$ for dcBus1

$\sum_{i} I_i - \frac{V_1 - V_2}{R}= 0$ for dcBus2

If a DC line is disconnected on any side, no current can pass through it.

### Line Commutated Converter

Expand All @@ -377,9 +378,12 @@ The voltage source converter is the link between AC and DC networks, it is linke
DC buses at the other side.<br>
Please note that converters with a second optional AC terminal are not supported by Open Load Flow.

If a terminal of the converter is disconnected, the converter is not included in the load flow, and none of the equations below is added.
Comment thread
SGI-Landry marked this conversation as resolved.

The converter can control either the power received by the AC network (`P_PCC` control mode)
or the voltage between its two DC buses (`V_DC` control mode).
At least one of the voltage source converters of the DC network must be in `V_DC` mode. Otherwise, an exception will be thrown.
At least one of the voltage source converters of the DC network must control the voltage (i.e. be in `V_DC` or `P_PCC_DROOP` mode).
If a DC network has only converters in `P_PCC` mode, they will be automatically set in `V_DC` mode with the DC nominal voltage as target voltage.

In addition to the control modes `P_PCC` and `V_DC`, the voltage source converter can be set in two modes :
- Reactive power control mode, in which it imposes the reactive power received from AC to DC, which is 0 by default.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -805,11 +805,16 @@ protected void createDcLineEquations(LfDcLine dcLine, LfDcBus dcBus1, LfDcBus dc
SingleEquationTerm<AcVariableType, AcEquationType> closedP2 = null;
SingleEquationTerm<AcVariableType, AcEquationType> closedI2 = null;

// open equations, only created when the line is (or becomes) open; null while it stays closed
SingleEquationTerm<AcVariableType, AcEquationType> openP1 = null;
SingleEquationTerm<AcVariableType, AcEquationType> openI1 = null;
SingleEquationTerm<AcVariableType, AcEquationType> openP2 = null;
SingleEquationTerm<AcVariableType, AcEquationType> openI2 = null;

if (dcBus1 != null && dcBus2 != null) {
if (!dcBus1.isGrounded()) {
closedP1 = new ClosedDcLineSide1PowerEquationTerm(dcLine, dcBus1, dcBus2, equationSystem.getVariableSet());
closedI1 = new ClosedDcLineSide1CurrentEquationTerm(dcLine, dcBus1, dcBus2, equationSystem.getVariableSet());

}
if (!dcBus2.isGrounded()) {
closedP2 = new ClosedDcLineSide2PowerEquationTerm(dcLine, dcBus1, dcBus2, equationSystem.getVariableSet());
Expand All @@ -819,13 +824,27 @@ protected void createDcLineEquations(LfDcLine dcLine, LfDcBus dcBus1, LfDcBus dc
i1 = closedI1;
p2 = closedP2;
i2 = closedI2;
} else if (dcBus1 != null) {
openP1 = new OpenDcLineEquationTerm(dcLine);
openI1 = new OpenDcLineEquationTerm(dcLine);
p1 = openP1;
i1 = openI1;
p2 = EvaluableConstants.ZERO;
i2 = EvaluableConstants.ZERO;
} else if (dcBus2 != null) {
openP2 = new OpenDcLineEquationTerm(dcLine);
openI2 = new OpenDcLineEquationTerm(dcLine);
p1 = EvaluableConstants.ZERO;
i1 = EvaluableConstants.ZERO;
p2 = openP2;
i2 = openI2;
}

createDcLineEquations(dcLine, dcBus1, dcBus2, equationSystem,
p1, i1,
p2, i2,
closedP1, closedI1,
closedP2, closedI2);
p1, i1, p2, i2,
closedP1, closedI1, closedP2, closedI2,
openP1, openI1, openP2, openI2
);
}

protected EquationTerm<AcVariableType, AcEquationType> createClosedBranchSide1ActiveFlowEquationTerm(LfBranch branch, LfBus bus1, LfBus bus2,
Expand Down Expand Up @@ -957,33 +976,48 @@ protected static void createDcLineEquations(LfDcLine dcLine, LfDcBus dcBus1, LfD
Evaluable p1, Evaluable i1,
Evaluable p2, Evaluable i2,
SingleEquationTerm<AcVariableType, AcEquationType> closedP1, SingleEquationTerm<AcVariableType, AcEquationType> closedI1,
SingleEquationTerm<AcVariableType, AcEquationType> closedP2, SingleEquationTerm<AcVariableType, AcEquationType> closedI2) {

SingleEquationTerm<AcVariableType, AcEquationType> closedP2, SingleEquationTerm<AcVariableType, AcEquationType> closedI2,
SingleEquationTerm<AcVariableType, AcEquationType> openP1, SingleEquationTerm<AcVariableType, AcEquationType> openI1,
SingleEquationTerm<AcVariableType, AcEquationType> openP2, SingleEquationTerm<AcVariableType, AcEquationType> openI2) {
if (closedI1 != null) {
equationSystem.getEquation(dcBus1.getNum(), AcEquationType.DC_BUS_TARGET_I).orElseThrow()
.addTerm(closedI1);
}
if (openI1 != null) {
equationSystem.getEquation(dcBus1.getNum(), AcEquationType.DC_BUS_TARGET_I).orElseThrow()
.addTerm(openI1);
}
if (i1 != null) {
dcLine.setI1(i1);
}
if (closedI2 != null) {
equationSystem.getEquation(dcBus2.getNum(), AcEquationType.DC_BUS_TARGET_I).orElseThrow()
.addTerm(closedI2);
}
if (openI2 != null) {
equationSystem.getEquation(dcBus2.getNum(), AcEquationType.DC_BUS_TARGET_I).orElseThrow()
.addTerm(openI2);
}
if (i2 != null) {
dcLine.setI2(i2);
}

if (closedP1 != null) {
equationSystem.attach(closedP1);
}
if (openP1 != null) {
equationSystem.attach(openP1);
}
if (p1 != null) {
dcLine.setP1(p1);
}

if (closedP2 != null) {
equationSystem.attach(closedP2);
}
if (openP2 != null) {
equationSystem.attach(openP2);
}
if (p2 != null) {
dcLine.setP2(p2);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* Copyright (c) 2026, SuperGrid Institute (http://www.supergrid-institute.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.ac.equations.dcnetwork;

import com.powsybl.openloadflow.ac.equations.AcEquationType;
import com.powsybl.openloadflow.ac.equations.AcVariableType;
import com.powsybl.openloadflow.equations.AbstractElementEquationTerm;
import com.powsybl.openloadflow.equations.Variable;
import com.powsybl.openloadflow.network.LfDcLine;

import java.util.List;
import java.util.Objects;

/**
* Equation term returning 0 for the current in an open DC line.
*
* @author Baptiste Perreyon {@literal <baptiste.perreyon at supergrid-institute.com>}
*/
public class OpenDcLineEquationTerm extends AbstractElementEquationTerm<LfDcLine, AcVariableType, AcEquationType> {

public OpenDcLineEquationTerm(LfDcLine dcLine) {
super(dcLine);
}

@Override
public double eval() {
return 0.0;
}

@Override
public double der(Variable<AcVariableType> variable) {
Objects.requireNonNull(variable);
throw new IllegalStateException("Unknown variable: " + variable);
}

@Override
public String getName() {
return "dc_open_line";
}

@Override
public List<Variable<AcVariableType>> getVariables() {
return List.of();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import com.powsybl.openloadflow.util.Evaluable;
import com.powsybl.openloadflow.util.PerUnit;

import java.util.Optional;

/**
* @author Denis Bonnand {@literal <denis.bonnand at supergrid-institute.com>}
*/
Expand Down Expand Up @@ -43,16 +45,20 @@ public abstract class AbstractLfAcDcConverter extends AbstractElement implements

protected final LfBus bus1;

protected AbstractLfAcDcConverter(AcDcConverter<?> converter, LfNetwork network, LfDcBus dcBus1, LfDcBus dcBus2, LfBus bus1) {
protected AbstractLfAcDcConverter(AcDcConverter<?> converter, LfNetwork network, LfDcBus dcBus1, LfDcBus dcBus2, LfBus bus1,
Optional<Double> vdcOverride) {
super(network);

this.dcBus1 = dcBus1;
this.dcBus2 = dcBus2;
this.bus1 = bus1;
this.lossFactors = new LossFactors(converter.getIdleLoss(), converter.getSwitchingLoss(), converter.getResistiveLoss());
this.controlMode = converter.getControlMode();
// vdcOverride is set when this converter has been automatically promoted to V_DC control because its DC
// island had no other element imposing the DC voltage (see DcComponentValidator.resolveDcComponent)
this.controlMode = vdcOverride.isPresent() ? AcDcConverter.ControlMode.V_DC : converter.getControlMode();
this.targetP = converter.getTargetP() / PerUnit.SB;
targetVdc = dcBus1.isGrounded() ? converter.getTargetVdc() / dcBus2.getNominalV() : converter.getTargetVdc() / dcBus1.getNominalV();
double rawTargetVdc = vdcOverride.orElseGet(converter::getTargetVdc);
targetVdc = dcBus1.isGrounded() ? rawTargetVdc / dcBus2.getNominalV() : rawTargetVdc / dcBus1.getNominalV();
this.pAc = converter.getTerminal1().getP();
this.qAc = converter.getTerminal1().getQ();
}
Expand Down
Loading
Loading