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

[WIP] Add a parameter to force targetQ within reactive limits #1154

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions docs/loadflow/parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,11 @@ When `useReactiveLimits` is set to `true`, this parameter is used to limit the n
is switching from PQ to PV type. After this number of PQ/PV type switch, the equipment will not change PV/PQ type anymore.
The default value is `3` and it must be greater or equal to `0`.

**forceTargetQInReactiveLimits**
When `useReactiveLimits` is set to `true`, this parameter is used to prioritize the reactive power limits over the input target Q when target Q is
outside these limits. If set to `true`, if any generator has a target Q which is outside its reactive power limits (for its given target P), then its target Q
is overriden by the value of the exceeded limit (minQ or maxQ). The default value is `false`.

**phaseShifterControlMode**
- `CONTINUOUS_WITH_DISCRETISATION`: phase shifter control is solved by the Newton-Raphson inner-loop.
- `INCREMENTAL`: phase shifter control is solved in the outer-loop
Expand Down
30 changes: 26 additions & 4 deletions src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ public enum FictitiousGeneratorVoltageControlCheckMode {

public static final double AREA_INTERCHANGE_P_MAX_MISMATCH_DEFAULT_VALUE = 2.0;

public static final boolean FORCE_TARGET_Q_IN_REACTIVE_LIMITS_DEFAULT_VALUE = false;

public static final String SLACK_BUS_SELECTION_MODE_PARAM_NAME = "slackBusSelectionMode";

public static final String SLACK_BUSES_IDS_PARAM_NAME = "slackBusesIds";
Expand Down Expand Up @@ -276,6 +278,8 @@ public enum FictitiousGeneratorVoltageControlCheckMode {

public static final String AREA_INTERCHANGE_P_MAX_MISMATCH_PARAM_NAME = "areaInterchangePMaxMismatch";

public static final String FORCE_TARGET_Q_IN_REACTIVE_LIMITS_PARAM_NAME = "forceTargetQInReactiveLimits";

public static <E extends Enum<E>> List<Object> getEnumPossibleValues(Class<E> enumClass) {
return EnumSet.allOf(enumClass).stream().map(Enum::name).collect(Collectors.toList());
}
Expand Down Expand Up @@ -417,7 +421,8 @@ public static List<Object> getAcSolverTypePossibleValues() {
new Parameter(FICTITIOUS_GENERATOR_VOLTAGE_CONTROL_CHECK_MODE, ParameterType.STRING, "Specifies fictitious generators active power checks exemption for voltage control", OpenLoadFlowParameters.FICTITIOUS_GENERATOR_VOLTAGE_CONTROL_CHECK_MODE_DEFAULT_VALUE.name(), getEnumPossibleValues(FictitiousGeneratorVoltageControlCheckMode.class), ParameterScope.FUNCTIONAL, GENERATOR_VOLTAGE_CONTROL_CATEGORY_KEY),
new Parameter(AREA_INTERCHANGE_CONTROL_PARAM_NAME, ParameterType.BOOLEAN, "Area interchange control", AREA_INTERCHANGE_CONTROL_DEFAULT_VALUE, ParameterScope.FUNCTIONAL, SLACK_DISTRIBUTION_CATEGORY_KEY),
new Parameter(AREA_INTERCHANGE_CONTROL_AREA_TYPE_PARAM_NAME, ParameterType.STRING, "Area type for area interchange control", LfNetworkParameters.AREA_INTERCHANGE_CONTROL_AREA_TYPE_DEFAULT_VALUE, ParameterScope.FUNCTIONAL, SLACK_DISTRIBUTION_CATEGORY_KEY),
new Parameter(AREA_INTERCHANGE_P_MAX_MISMATCH_PARAM_NAME, ParameterType.DOUBLE, "Area interchange max active power mismatch", AREA_INTERCHANGE_P_MAX_MISMATCH_DEFAULT_VALUE, ParameterScope.FUNCTIONAL, SLACK_DISTRIBUTION_CATEGORY_KEY)
new Parameter(AREA_INTERCHANGE_P_MAX_MISMATCH_PARAM_NAME, ParameterType.DOUBLE, "Area interchange max active power mismatch", AREA_INTERCHANGE_P_MAX_MISMATCH_DEFAULT_VALUE, ParameterScope.FUNCTIONAL, SLACK_DISTRIBUTION_CATEGORY_KEY),
new Parameter(FORCE_TARGET_Q_IN_REACTIVE_LIMITS_PARAM_NAME, ParameterType.BOOLEAN, "Force targetQ in the reactive limit diagram", FORCE_TARGET_Q_IN_REACTIVE_LIMITS_DEFAULT_VALUE, ParameterScope.FUNCTIONAL, REACTIVE_POWER_CONTROL_CATEGORY_KEY)
);

public enum VoltageInitModeOverride {
Expand Down Expand Up @@ -601,6 +606,8 @@ public enum ReactiveRangeCheckMode {

private double areaInterchangePMaxMismatch = AREA_INTERCHANGE_P_MAX_MISMATCH_DEFAULT_VALUE;

private boolean forceTargetQInReactiveLimits = FORCE_TARGET_Q_IN_REACTIVE_LIMITS_DEFAULT_VALUE;

public static double checkParameterValue(double parameterValue, boolean condition, String parameterName) {
if (!condition) {
throw new IllegalArgumentException("Invalid value for parameter " + parameterName + ": " + parameterValue);
Expand Down Expand Up @@ -1326,6 +1333,15 @@ public OpenLoadFlowParameters setAreaInterchangePMaxMismatch(double areaIntercha
return this;
}

public boolean isForceTargetQInReactiveLimits() {
return forceTargetQInReactiveLimits;
}

public OpenLoadFlowParameters setForceTargetQInReactiveLimits(boolean forceTargetQInReactiveLimits) {
this.forceTargetQInReactiveLimits = forceTargetQInReactiveLimits;
return this;
}

public static OpenLoadFlowParameters load() {
return load(PlatformConfig.defaultConfig());
}
Expand Down Expand Up @@ -1565,6 +1581,8 @@ public OpenLoadFlowParameters update(Map<String, String> properties) {
.ifPresent(this::setAreaInterchangeControlAreaType);
Optional.ofNullable(properties.get(AREA_INTERCHANGE_P_MAX_MISMATCH_PARAM_NAME))
.ifPresent(prop -> this.setAreaInterchangePMaxMismatch(Double.parseDouble(prop)));
Optional.ofNullable(properties.get(FORCE_TARGET_Q_IN_REACTIVE_LIMITS_PARAM_NAME))
.ifPresent(prop -> this.setForceTargetQInReactiveLimits(Boolean.parseBoolean(prop)));
return this;
}

Expand Down Expand Up @@ -1641,6 +1659,7 @@ public Map<String, Object> toMap() {
map.put(AREA_INTERCHANGE_CONTROL_PARAM_NAME, areaInterchangeControl);
map.put(AREA_INTERCHANGE_CONTROL_AREA_TYPE_PARAM_NAME, areaInterchangeControlAreaType);
map.put(AREA_INTERCHANGE_P_MAX_MISMATCH_PARAM_NAME, areaInterchangePMaxMismatch);
map.put(FORCE_TARGET_Q_IN_REACTIVE_LIMITS_PARAM_NAME, forceTargetQInReactiveLimits);
return map;
}

Expand Down Expand Up @@ -1797,7 +1816,8 @@ static LfNetworkParameters getNetworkParameters(LoadFlowParameters parameters, O
.setVoltageTargetPriorities(parametersExt.getVoltageTargetPriorities())
.setFictitiousGeneratorVoltageControlCheckMode(parametersExt.getFictitiousGeneratorVoltageControlCheckMode())
.setAreaInterchangeControl(parametersExt.isAreaInterchangeControl())
.setAreaInterchangeControlAreaType(parametersExt.getAreaInterchangeControlAreaType());
.setAreaInterchangeControlAreaType(parametersExt.getAreaInterchangeControlAreaType())
.setForceTargetQInReactiveLimits(parametersExt.isForceTargetQInReactiveLimits());
}

public static AcLoadFlowParameters createAcParameters(Network network, LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt,
Expand Down Expand Up @@ -2024,7 +2044,8 @@ public static boolean equals(LoadFlowParameters parameters1, LoadFlowParameters
extension1.getFictitiousGeneratorVoltageControlCheckMode() == extension2.getFictitiousGeneratorVoltageControlCheckMode() &&
extension1.isAreaInterchangeControl() == extension2.isAreaInterchangeControl() &&
Objects.equals(extension1.getAreaInterchangeControlAreaType(), extension2.getAreaInterchangeControlAreaType()) &&
extension1.getAreaInterchangePMaxMismatch() == extension2.getAreaInterchangePMaxMismatch();
extension1.getAreaInterchangePMaxMismatch() == extension2.getAreaInterchangePMaxMismatch() &&
extension1.isForceTargetQInReactiveLimits() == extension2.isForceTargetQInReactiveLimits();
}

public static LoadFlowParameters clone(LoadFlowParameters parameters) {
Expand Down Expand Up @@ -2120,7 +2141,8 @@ public static LoadFlowParameters clone(LoadFlowParameters parameters) {
.setFictitiousGeneratorVoltageControlCheckMode(extension.getFictitiousGeneratorVoltageControlCheckMode())
.setAreaInterchangeControl(extension.isAreaInterchangeControl())
.setAreaInterchangeControlAreaType(extension.getAreaInterchangeControlAreaType())
.setAreaInterchangePMaxMismatch(extension.getAreaInterchangePMaxMismatch());
.setAreaInterchangePMaxMismatch(extension.getAreaInterchangePMaxMismatch())
.setForceTargetQInReactiveLimits(extension.isForceTargetQInReactiveLimits());

if (extension2 != null) {
parameters2.addExtension(OpenLoadFlowParameters.class, extension2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ public class LfNetworkParameters {

private String areaInterchangeControlAreaType = AREA_INTERCHANGE_CONTROL_AREA_TYPE_DEFAULT_VALUE;

private boolean forceTargetQInReactiveLimits = OpenLoadFlowParameters.FORCE_TARGET_Q_IN_REACTIVE_LIMITS_DEFAULT_VALUE;

public LfNetworkParameters() {
}

Expand Down Expand Up @@ -194,6 +196,7 @@ public LfNetworkParameters(LfNetworkParameters other) {
this.fictitiousGeneratorVoltageControlCheckMode = other.fictitiousGeneratorVoltageControlCheckMode;
this.areaInterchangeControl = other.areaInterchangeControl;
this.areaInterchangeControlAreaType = other.areaInterchangeControlAreaType;
this.forceTargetQInReactiveLimits = other.forceTargetQInReactiveLimits;
}

public SlackBusSelector getSlackBusSelector() {
Expand Down Expand Up @@ -597,6 +600,15 @@ public LfNetworkParameters setAreaInterchangeControlAreaType(String areaIntercha
return this;
}

public boolean isForceTargetQInReactiveLimits() {
return forceTargetQInReactiveLimits;
}

public LfNetworkParameters setForceTargetQInReactiveLimits(boolean forceTargetQInReactiveLimits) {
this.forceTargetQInReactiveLimits = forceTargetQInReactiveLimits;
return this;
}

@Override
public String toString() {
return "LfNetworkParameters(" +
Expand Down Expand Up @@ -638,6 +650,7 @@ public String toString() {
", fictitiousGeneratorVoltageControlCheckMode=" + fictitiousGeneratorVoltageControlCheckMode +
", areaInterchangeControl=" + areaInterchangeControl +
", areaInterchangeControlAreaType=" + areaInterchangeControlAreaType +
", forceTargetQInReactiveLimits=" + forceTargetQInReactiveLimits +
')';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ public final class LfGeneratorImpl extends AbstractLfGenerator {

private final double minTargetP;

private final boolean forceTargetQInReactiveLimits;

private LfGeneratorImpl(Generator generator, LfNetwork network, LfNetworkParameters parameters, LfNetworkLoadingReport report) {
super(network, generator.getTargetP() / PerUnit.SB);
this.generatorRef = Ref.create(generator, parameters.isCacheEnabled());
Expand All @@ -62,6 +64,8 @@ private LfGeneratorImpl(Generator generator, LfNetwork network, LfNetworkParamet
minTargetP = apcHelper.minTargetP();
maxTargetP = apcHelper.maxTargetP();

forceTargetQInReactiveLimits = parameters.isForceTargetQInReactiveLimits() && parameters.isReactiveLimits();

setReferencePriority(ReferencePriority.get(generator));

if (!checkActivePowerControl(generator.getId(), generator.getTargetP(), generator.getMaxP(), minTargetP, maxTargetP,
Expand Down Expand Up @@ -166,7 +170,17 @@ public OptionalDouble getRemoteControlReactiveKey() {

@Override
public double getTargetQ() {
return Networks.zeroIfNan(getGenerator().getTargetQ()) / PerUnit.SB;
double targetQ = Networks.zeroIfNan(getGenerator().getTargetQ()) / PerUnit.SB;
if (forceTargetQInReactiveLimits) {
double minQ = getMinQ();
double maxQ = getMaxQ();
if (targetQ < minQ) {
targetQ = minQ;
} else if (targetQ > maxQ) {
targetQ = maxQ;
}
}
return targetQ;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,8 @@ public void analyse(Network network, List<PropagatedContingency> contingencies,
.setSimulateAutomationSystems(false)
.setReferenceBusSelector(ReferenceBusSelector.DEFAULT_SELECTOR) // not supported yet
.setAreaInterchangeControl(lfParametersExt.isAreaInterchangeControl())
.setAreaInterchangeControlAreaType(lfParametersExt.getAreaInterchangeControlAreaType());
.setAreaInterchangeControlAreaType(lfParametersExt.getAreaInterchangeControlAreaType())
.setForceTargetQInReactiveLimits(lfParametersExt.isForceTargetQInReactiveLimits());

// create networks including all necessary switches
try (LfNetworkList lfNetworks = Networks.load(network, lfNetworkParameters, topoConfig, reportNode)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ void testCloneParameters() {
@Test
void testToString() {
OpenLoadFlowParameters parameters = new OpenLoadFlowParameters();
assertEquals("OpenLoadFlowParameters(slackBusSelectionMode=MOST_MESHED, slackBusesIds=[], slackDistributionFailureBehavior=LEAVE_ON_SLACK_BUS, voltageRemoteControl=true, lowImpedanceBranchMode=REPLACE_BY_ZERO_IMPEDANCE_LINE, loadPowerFactorConstant=false, plausibleActivePowerLimit=5000.0, newtonRaphsonStoppingCriteriaType=UNIFORM_CRITERIA, slackBusPMaxMismatch=1.0, maxActivePowerMismatch=0.01, maxReactivePowerMismatch=0.01, maxVoltageMismatch=1.0E-4, maxAngleMismatch=1.0E-5, maxRatioMismatch=1.0E-5, maxSusceptanceMismatch=1.0E-4, voltagePerReactivePowerControl=false, generatorReactivePowerRemoteControl=false, transformerReactivePowerControl=false, maxNewtonRaphsonIterations=15, maxOuterLoopIterations=20, newtonRaphsonConvEpsPerEq=1.0E-4, voltageInitModeOverride=NONE, transformerVoltageControlMode=WITH_GENERATOR_VOLTAGE_CONTROL, shuntVoltageControlMode=WITH_GENERATOR_VOLTAGE_CONTROL, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, networkCacheEnabled=false, svcVoltageMonitoring=true, stateVectorScalingMode=NONE, maxSlackBusCount=1, debugDir=null, incrementalTransformerRatioTapControlOuterLoopMaxTapShift=3, secondaryVoltageControl=false, reactiveLimitsMaxPqPvSwitch=3, phaseShifterControlMode=CONTINUOUS_WITH_DISCRETISATION, alwaysUpdateNetwork=false, mostMeshedSlackBusSelectorMaxNominalVoltagePercentile=95.0, reportedFeatures=[], slackBusCountryFilter=[], actionableSwitchesIds=[], actionableTransformersIds=[], asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, reactivePowerDispatchMode=Q_EQUAL_PROPORTION, outerLoopNames=null, useActiveLimits=true, disableVoltageControlOfGeneratorsOutsideActivePowerLimits=false, lineSearchStateVectorScalingMaxIteration=10, lineSearchStateVectorScalingStepFold=1.3333333333333333, maxVoltageChangeStateVectorScalingMaxDv=0.1, maxVoltageChangeStateVectorScalingMaxDphi=0.17453292519943295, linePerUnitMode=IMPEDANCE, useLoadModel=false, dcApproximationType=IGNORE_R, simulateAutomationSystems=false, acSolverType=NEWTON_RAPHSON, maxNewtonKrylovIterations=100, newtonKrylovLineSearch=false, referenceBusSelectionMode=FIRST_SLACK, writeReferenceTerminals=true, voltageTargetPriorities=[GENERATOR, TRANSFORMER, SHUNT], transformerVoltageControlUseInitialTapPosition=false, generatorVoltageControlMinNominalVoltage=-1.0, fictitiousGeneratorVoltageControlCheckMode=FORCED, areaInterchangeControl=false, areaInterchangeControlAreaType=ControlArea, areaInterchangePMaxMismatch=2.0)",
assertEquals("OpenLoadFlowParameters(slackBusSelectionMode=MOST_MESHED, slackBusesIds=[], slackDistributionFailureBehavior=LEAVE_ON_SLACK_BUS, voltageRemoteControl=true, lowImpedanceBranchMode=REPLACE_BY_ZERO_IMPEDANCE_LINE, loadPowerFactorConstant=false, plausibleActivePowerLimit=5000.0, newtonRaphsonStoppingCriteriaType=UNIFORM_CRITERIA, slackBusPMaxMismatch=1.0, maxActivePowerMismatch=0.01, maxReactivePowerMismatch=0.01, maxVoltageMismatch=1.0E-4, maxAngleMismatch=1.0E-5, maxRatioMismatch=1.0E-5, maxSusceptanceMismatch=1.0E-4, voltagePerReactivePowerControl=false, generatorReactivePowerRemoteControl=false, transformerReactivePowerControl=false, maxNewtonRaphsonIterations=15, maxOuterLoopIterations=20, newtonRaphsonConvEpsPerEq=1.0E-4, voltageInitModeOverride=NONE, transformerVoltageControlMode=WITH_GENERATOR_VOLTAGE_CONTROL, shuntVoltageControlMode=WITH_GENERATOR_VOLTAGE_CONTROL, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, networkCacheEnabled=false, svcVoltageMonitoring=true, stateVectorScalingMode=NONE, maxSlackBusCount=1, debugDir=null, incrementalTransformerRatioTapControlOuterLoopMaxTapShift=3, secondaryVoltageControl=false, reactiveLimitsMaxPqPvSwitch=3, phaseShifterControlMode=CONTINUOUS_WITH_DISCRETISATION, alwaysUpdateNetwork=false, mostMeshedSlackBusSelectorMaxNominalVoltagePercentile=95.0, reportedFeatures=[], slackBusCountryFilter=[], actionableSwitchesIds=[], actionableTransformersIds=[], asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, reactivePowerDispatchMode=Q_EQUAL_PROPORTION, outerLoopNames=null, useActiveLimits=true, disableVoltageControlOfGeneratorsOutsideActivePowerLimits=false, lineSearchStateVectorScalingMaxIteration=10, lineSearchStateVectorScalingStepFold=1.3333333333333333, maxVoltageChangeStateVectorScalingMaxDv=0.1, maxVoltageChangeStateVectorScalingMaxDphi=0.17453292519943295, linePerUnitMode=IMPEDANCE, useLoadModel=false, dcApproximationType=IGNORE_R, simulateAutomationSystems=false, acSolverType=NEWTON_RAPHSON, maxNewtonKrylovIterations=100, newtonKrylovLineSearch=false, referenceBusSelectionMode=FIRST_SLACK, writeReferenceTerminals=true, voltageTargetPriorities=[GENERATOR, TRANSFORMER, SHUNT], transformerVoltageControlUseInitialTapPosition=false, generatorVoltageControlMinNominalVoltage=-1.0, fictitiousGeneratorVoltageControlCheckMode=FORCED, areaInterchangeControl=false, areaInterchangeControlAreaType=ControlArea, areaInterchangePMaxMismatch=2.0, forceTargetQInReactiveLimits=false)",
parameters.toString());
}

Expand Down
Loading
Loading