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

Check target voltage plausibility on Transformers and Shunt Compensators #1030

Merged
merged 13 commits into from
May 17, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ private Optional<List<String>> processSecondaryVoltageControl(List<LfSecondaryVo
.stream()
.filter(e -> {
double newTargetV = e.getValue();
return LfGenerator.isTargetVoltageNotPlausible(newTargetV, minPlausibleTargetVoltage, maxPlausibleTargetVoltage);
return !VoltageControl.isTargetVoltagePlausible(newTargetV, minPlausibleTargetVoltage, maxPlausibleTargetVoltage);
Copy link
Member

Choose a reason for hiding this comment

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

@annetill just a note, no check on minNominalVoltageTargetVoltageCheck here, I have no idea if this is deliberate (I lack knowledge about this outerloop).

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 are going to wait for the issue @geofjamg . At RTE, we are using this outer loop on network without any generator connected to low nominal voltages, but it could arrived soon.

})
.map(e -> {
// convert target to Kv for better display
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@ static double qToK(LfGenerator generator, double q) {
return (2 * q - maxQ - minQ) / (maxQ - minQ);
}

static boolean isTargetVoltageNotPlausible(double targetV, double minPlausibleTargetVoltage, double maxPlausibleTargetVoltage) {
return targetV < minPlausibleTargetVoltage || targetV > maxPlausibleTargetVoltage;
}

String getId();

String getOriginalId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,14 @@ public Optional<LfBus> findMainVisibleControlledBus() {
}
}

public static boolean checkTargetV(double targetV, double nominalV, LfNetworkParameters parameters) {
return nominalV <= parameters.getMinNominalVoltageTargetVoltageCheck() || isTargetVoltagePlausible(targetV, parameters.getMinPlausibleTargetVoltage(), parameters.getMaxPlausibleTargetVoltage());
}

public static boolean isTargetVoltagePlausible(double targetV, double minPlausibleTargetVoltage, double maxPlausibleTargetVoltage) {
return targetV >= minPlausibleTargetVoltage && targetV <= maxPlausibleTargetVoltage;
}

@Override
public String toString() {
return "VoltageControl(type=" + type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,25 +327,45 @@ void addBattery(Battery generator, LfNetworkParameters parameters, LfNetworkLoad
add(LfBatteryImpl.create(generator, network, parameters, report));
}

void setShuntCompensators(List<ShuntCompensator> shuntCompensators, LfNetworkParameters parameters, LfTopoConfig topoConfig) {
void setShuntCompensators(List<ShuntCompensator> shuntCompensators, LfNetworkParameters parameters, LfTopoConfig topoConfig, LfNetworkLoadingReport report) {
if (!parameters.isShuntVoltageControl() && !shuntCompensators.isEmpty()) {
shunt = new LfShuntImpl(shuntCompensators, network, this, false, parameters, topoConfig);
} else {
List<ShuntCompensator> controllerShuntCompensators = shuntCompensators.stream()
.filter(ShuntCompensator::isVoltageRegulatorOn)
.toList();
List<ShuntCompensator> controllerShuntCompensators = new ArrayList<>();
List<ShuntCompensator> fixedShuntCompensators = new ArrayList<>();
shuntCompensators.forEach(sc -> {
if (checkVoltageControl(sc, parameters, report)) {
controllerShuntCompensators.add(sc);
} else {
fixedShuntCompensators.add(sc);
}
});

if (!controllerShuntCompensators.isEmpty()) {
controllerShunt = new LfShuntImpl(controllerShuntCompensators, network, this, true, parameters, topoConfig);
}
List<ShuntCompensator> fixedShuntCompensators = shuntCompensators.stream()
.filter(sc -> !sc.isVoltageRegulatorOn())
.toList();
if (!fixedShuntCompensators.isEmpty()) {
shunt = new LfShuntImpl(fixedShuntCompensators, network, this, false, parameters, topoConfig);
}
}
}

static boolean checkVoltageControl(ShuntCompensator shuntCompensator, LfNetworkParameters parameters, LfNetworkLoadingReport report) {
double nominalV = shuntCompensator.getRegulatingTerminal().getVoltageLevel().getNominalV();
double targetV = shuntCompensator.getTargetV();
if (!shuntCompensator.isVoltageRegulatorOn()) {
return false;
}
if (!VoltageControl.checkTargetV(targetV / nominalV, nominalV, parameters)) {
LOGGER.trace("Shunt compensator '{}' has an inconsistent target voltage: {} pu: shunt voltage control discarded", shuntCompensator.getId(), targetV);
if (report != null) {
report.shuntsWithInconsistentTargetVoltage++;
}
return false;
}
return true;
}

@Override
public void invalidateGenerationTargetP() {
generationTargetP = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,7 @@ protected boolean checkIfGeneratorIsInsideActivePowerLimitsForVoltageControl(LfN

public static boolean checkTargetV(String generatorId, double targetV, double nominalV, LfNetworkParameters parameters, LfNetworkLoadingReport report) {
// check that targetV has a plausible value (wrong nominal voltage issue)
if (nominalV > parameters.getMinNominalVoltageTargetVoltageCheck() &&
LfGenerator.isTargetVoltageNotPlausible(targetV, parameters.getMinPlausibleTargetVoltage(), parameters.getMaxPlausibleTargetVoltage())) {
if (!VoltageControl.checkTargetV(targetV, nominalV, parameters)) {
LOGGER.trace("Generator '{}' has an inconsistent target voltage: {} pu: generator voltage control discarded",
generatorId, targetV);
if (report != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ public void visitHvdcConverterStation(HvdcConverterStation<?> converterStation)
});

if (!shuntCompensators.isEmpty()) {
lfBus.setShuntCompensators(shuntCompensators, parameters, topoConfig);
lfBus.setShuntCompensators(shuntCompensators, parameters, topoConfig, report);
}

return lfBus;
Expand Down Expand Up @@ -627,6 +627,14 @@ private static void createTransformerVoltageControl(LfNetwork lfNetwork, RatioTa
double targetValue = rtc.getTargetV() / regulatingTerminalNominalV;
Double targetDeadband = rtc.getTargetDeadband() > 0 ? rtc.getTargetDeadband() / regulatingTerminalNominalV : null;

if (!VoltageControl.checkTargetV(targetValue, controlledBus.getNominalV(), parameters)) {
LOGGER.trace("RatioTapChanger on transformer '{}' has an inconsistent target voltage: {} pu: transformer voltage control discarded", controllerBranchId, targetValue);
if (report != null) {
report.transformersWithInconsistentTargetVoltage++;
}
return;
}

controlledBus.getTransformerVoltageControl().ifPresentOrElse(vc -> {
LOGGER.trace("Controlled bus '{}' already has a transformer voltage control: a shared control is created", controlledBus.getId());
if (FastMath.abs(vc.getTargetValue() - targetValue) > TARGET_V_EPSILON) {
Expand Down Expand Up @@ -705,54 +713,55 @@ private static void createShuntVoltageControl(LfNetwork lfNetwork, ShuntCompensa
LOGGER.warn("Voltage controller shunt {} is out of voltage: no voltage control created", shuntCompensator.getId());
return;
}
LfShunt controllerShunt = controllerBus.getControllerShunt().orElseThrow();
LfBus controlledBus = getLfBus(shuntCompensator.getRegulatingTerminal(), lfNetwork, parameters.isBreakers());
if (controlledBus == null) {
LOGGER.warn("Regulating terminal of voltage controller shunt {} is out of voltage: no voltage control created", shuntCompensator.getId());
controllerShunt.setVoltageControlCapability(false);
return;
}
if (controllerShunt.getVoltageControl().isPresent()) {
// if a controller shunt is already in a shunt voltage control, the number of equations will not equal the
// number of variables. We have only one B variable for more than one bus target V equations.
if (!controllerShunt.getVoltageControl().orElseThrow().getControlledBus().getId().equals(controlledBus.getId())) {
LOGGER.error("Controller shunt {} is already in a shunt voltage control. The second controlled bus {} is ignored", controllerShunt.getId(), controlledBus.getId());
Reports.reportControllerShuntAlreadyInVoltageControl(controllerBus.getNetwork().getReportNode(), controllerShunt.getId(), controlledBus.getId());
controllerBus.getControllerShunt().ifPresent(controllerShunt -> {
LfBus controlledBus = getLfBus(shuntCompensator.getRegulatingTerminal(), lfNetwork, parameters.isBreakers());
if (controlledBus == null) {
LOGGER.warn("Regulating terminal of voltage controller shunt {} is out of voltage: no voltage control created", shuntCompensator.getId());
controllerShunt.setVoltageControlCapability(false);
return;
}
if (controllerShunt.getVoltageControl().isPresent()) {
// if a controller shunt is already in a shunt voltage control, the number of equations will not equal the
// number of variables. We have only one B variable for more than one bus target V equations.
if (!controllerShunt.getVoltageControl().orElseThrow().getControlledBus().getId().equals(controlledBus.getId())) {
LOGGER.error("Controller shunt {} is already in a shunt voltage control. The second controlled bus {} is ignored", controllerShunt.getId(), controlledBus.getId());
Reports.reportControllerShuntAlreadyInVoltageControl(controllerBus.getNetwork().getReportNode(), controllerShunt.getId(), controlledBus.getId());
}
return;
}
return;
}

double regulatingTerminalNominalV = shuntCompensator.getRegulatingTerminal().getVoltageLevel().getNominalV();
double targetValue = shuntCompensator.getTargetV() / regulatingTerminalNominalV;
Double targetDeadband = shuntCompensator.getTargetDeadband() > 0 ? shuntCompensator.getTargetDeadband() / regulatingTerminalNominalV : null;
double regulatingTerminalNominalV = shuntCompensator.getRegulatingTerminal().getVoltageLevel().getNominalV();
double targetValue = shuntCompensator.getTargetV() / regulatingTerminalNominalV;
Double targetDeadband = shuntCompensator.getTargetDeadband() > 0 ? shuntCompensator.getTargetDeadband() / regulatingTerminalNominalV : null;

controlledBus.getShuntVoltageControl().ifPresentOrElse(voltageControl -> {
LOGGER.trace("Controlled bus {} has already a shunt voltage control: a shared control is created", controlledBus.getId());
if (FastMath.abs(voltageControl.getTargetValue() - targetValue) > TARGET_V_EPSILON) {
LOGGER.warn("Controlled bus {} already has a shunt voltage control with a different target voltage: {} and {}",
controlledBus.getId(), voltageControl.getTargetValue(), targetValue);
}
if (!voltageControl.getControllerElements().contains(controllerShunt)) {
voltageControl.addControllerElement(controllerShunt);
controllerShunt.setVoltageControl(voltageControl);
controlledBus.setShuntVoltageControl(voltageControl);
if (targetDeadband != null) {
Double oldTargetDeadband = voltageControl.getTargetDeadband().orElse(null);
if (oldTargetDeadband == null) {
voltageControl.setTargetDeadband(targetDeadband);
} else {
// merge target deadbands by taking minimum
voltageControl.setTargetDeadband(Math.min(oldTargetDeadband, targetDeadband));
controlledBus.getShuntVoltageControl().ifPresentOrElse(voltageControl -> {
LOGGER.trace("Controlled bus {} has already a shunt voltage control: a shared control is created", controlledBus.getId());
if (FastMath.abs(voltageControl.getTargetValue() - targetValue) > TARGET_V_EPSILON) {
LOGGER.warn("Controlled bus {} already has a shunt voltage control with a different target voltage: {} and {}",
controlledBus.getId(), voltageControl.getTargetValue(), targetValue);
}
if (!voltageControl.getControllerElements().contains(controllerShunt)) {
voltageControl.addControllerElement(controllerShunt);
controllerShunt.setVoltageControl(voltageControl);
controlledBus.setShuntVoltageControl(voltageControl);
if (targetDeadband != null) {
Double oldTargetDeadband = voltageControl.getTargetDeadband().orElse(null);
if (oldTargetDeadband == null) {
voltageControl.setTargetDeadband(targetDeadband);
} else {
// merge target deadbands by taking minimum
voltageControl.setTargetDeadband(Math.min(oldTargetDeadband, targetDeadband));
}
}
}
}
}, () -> {
}, () -> {
// we create a new shunt voltage control.
ShuntVoltageControl voltageControl = new ShuntVoltageControl(controlledBus, parameters.getVoltageTargetPriority(VoltageControl.Type.SHUNT), targetValue, targetDeadband);
voltageControl.addControllerElement(controllerShunt);
controllerShunt.setVoltageControl(voltageControl);
controlledBus.setShuntVoltageControl(voltageControl);
});
});
}

private static LfBus getLfBus(Terminal terminal, LfNetwork lfNetwork, boolean breakers) {
Expand Down Expand Up @@ -843,15 +852,12 @@ private LfNetwork create(int numCC, int numSC, Network network, List<Bus> buses,
LOGGER.warn("Network {}: {} branches have been discarded because connected to same bus at both ends",
lfNetwork, report.branchesDiscardedBecauseConnectedToSameBusAtBothEnds);
}
if (report.linesWithDifferentNominalVoltageAtBothEnds > 0) {
Copy link
Member

Choose a reason for hiding this comment

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

why it is removed?

Copy link
Member

Choose a reason for hiding this comment

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

this is dead code ... See #1030 (comment)

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 it is a mistake @geofjamg what's happen here?

Copy link
Member

Choose a reason for hiding this comment

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

LOGGER.warn("Network {}: {} lines have a different nominal voltage at both ends: a ratio has been added",
lfNetwork, report.linesWithDifferentNominalVoltageAtBothEnds);
}
if (report.nonImpedantBranches > 0) {
LOGGER.warn("Network {}: {} branches are non impedant", lfNetwork, report.nonImpedantBranches);
}

if (report.generatorsWithInconsistentTargetVoltage > 0) {
Reports.reportGeneratorsDiscardedFromVoltageControlBecauseTargetVIsInconsistent(reportNode, report.generatorsWithInconsistentTargetVoltage);
LOGGER.warn("Network {}: {} generators have an inconsistent target voltage and have been discarded from voltage control",
lfNetwork, report.generatorsWithInconsistentTargetVoltage);
}
Expand All @@ -867,10 +873,22 @@ private LfNetwork create(int numCC, int numSC, Network network, List<Bus> buses,
}

if (report.transformerReactivePowerControlDiscardedBecauseControllerBranchIsOpen > 0) {
LOGGER.warn("Network {}: {} ratio tap changer reactive power controls have been discarded because controller branch is open",
LOGGER.warn("Network {}: {} transformer reactive power controls have been discarded because controller branch is open",
lfNetwork, report.transformerReactivePowerControlDiscardedBecauseControllerBranchIsOpen);
}

if (report.transformersWithInconsistentTargetVoltage > 0) {
Reports.reportTransformersDiscardedFromVoltageControlBecauseTargetVIsInconsistent(reportNode, report.transformersWithInconsistentTargetVoltage);
LOGGER.warn("Network {}: {} transformer voltage controls have an inconsistent target voltage and have been discarded from voltage control",
lfNetwork, report.transformersWithInconsistentTargetVoltage);
}

if (report.shuntsWithInconsistentTargetVoltage > 0) {
Reports.reportShuntsDiscardedFromVoltageControlBecauseTargetVIsInconsistent(reportNode, report.shuntsWithInconsistentTargetVoltage);
LOGGER.warn("Network {}: {} shunt voltage controls have an inconsistent target voltage and have been discarded from voltage control",
lfNetwork, report.shuntsWithInconsistentTargetVoltage);
}

if (parameters.getDebugDir() != null) {
Path debugDir = DebugUtil.getDebugDir(parameters.getDebugDir());
String dateStr = ZonedDateTime.now().format(DATE_TIME_FORMAT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ public class LfNetworkLoadingReport {

int branchesDiscardedBecauseConnectedToSameBusAtBothEnds = 0;

int linesWithDifferentNominalVoltageAtBothEnds = 0;
Copy link
Member

Choose a reason for hiding this comment

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

Same question.


int nonImpedantBranches = 0;

int generatorsWithInconsistentTargetVoltage = 0;
Expand All @@ -41,4 +39,8 @@ public class LfNetworkLoadingReport {
int transformerVoltageControlDiscardedBecauseControllerBranchIsOpen = 0;

int transformerReactivePowerControlDiscardedBecauseControllerBranchIsOpen = 0;

int transformersWithInconsistentTargetVoltage = 0;

int shuntsWithInconsistentTargetVoltage = 0;
}
28 changes: 28 additions & 0 deletions src/main/java/com/powsybl/openloadflow/util/Reports.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ public final class Reports {
private static final String ITERATION = "iteration";
private static final String NETWORK_ID = "networkId";
private static final String IMPACTED_GENERATOR_COUNT = "impactedGeneratorCount";

private static final String IMPACTED_TRANSFORMER_COUNT = "impactedTransformerCount";

private static final String IMPACTED_SHUNT_COUNT = "impactedShuntCount";
private static final String BUS_ID = "busId";
private static final String CONTROLLER_BUS_ID = "controllerBusId";
private static final String CONTROLLED_BUS_ID = "controlledBusId";
Expand Down Expand Up @@ -294,6 +298,30 @@ public static void reportGeneratorsDiscardedFromVoltageControlBecauseTargetPIsOu
.add();
}

public static void reportGeneratorsDiscardedFromVoltageControlBecauseTargetVIsInconsistent(ReportNode reportNode, int impactedGeneratorCount) {
reportNode.newReportNode()
.withMessageTemplate("generatorsDiscardedFromVoltageControlBecauseTargetVIsInconsistent", "${impactedGeneratorCount} generators have been discarded from voltage control because targetV is inconsistent")
.withUntypedValue(IMPACTED_GENERATOR_COUNT, impactedGeneratorCount)
.withSeverity(TypedValue.WARN_SEVERITY)
.add();
}

public static void reportTransformersDiscardedFromVoltageControlBecauseTargetVIsInconsistent(ReportNode reportNode, int impactedTransformerCount) {
reportNode.newReportNode()
.withMessageTemplate("transformersDiscardedFromVoltageControlBecauseTargetVIsInconsistent", "${impactedTransformerCount} transformers have been discarded from voltage control because targetV is inconsistent")
.withUntypedValue(IMPACTED_TRANSFORMER_COUNT, impactedTransformerCount)
.withSeverity(TypedValue.WARN_SEVERITY)
.add();
}

public static void reportShuntsDiscardedFromVoltageControlBecauseTargetVIsInconsistent(ReportNode reportNode, int impactedShuntCount) {
reportNode.newReportNode()
.withMessageTemplate("shuntsDiscardedFromVoltageControlBecauseTargetVIsInconsistent", "${impactedShuntCount} shunt compensators have been discarded from voltage control because targetV is inconsistent")
.withUntypedValue(IMPACTED_SHUNT_COUNT, impactedShuntCount)
.withSeverity(TypedValue.WARN_SEVERITY)
.add();
}

public static void reportAcLfComplete(ReportNode reportNode, boolean success, String solverStatus, String outerloopStatus) {
TypedValue severity = success ? TypedValue.INFO_SEVERITY : TypedValue.ERROR_SEVERITY;
String successText = success ? "successfully" : "with error";
Expand Down
Loading