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

Fictitious generators and condensers controlling voltage even if stopped #1044

Merged
merged 10 commits into from
Jun 28, 2024
4 changes: 4 additions & 0 deletions docs/loadflow/parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,10 @@ If the user specifies only a sub-list of priorities, this sub-list is completed
order defined by default. Thus, if the user specifies only `["TRANSFORMER"]`,
it will be completed to `["TRANSFORMER", "GENERATOR", "SHUNT"]`.

**fictitiousGeneratorVoltageControlMode**
Specificies how fictitious generators can voltage. Possible modes are 'always' and 'normal'. 'always', the default, means that voltage
is controlled even if targetP is outside the minP - maxP interval.

## Configuration file example
See below an extract of a config file that could help:

Expand Down
37 changes: 32 additions & 5 deletions src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,13 @@ public enum SlackDistributionFailureBehavior {

protected static final double GENERATOR_VOLTAGE_CONTROL_MIN_NOMINAL_VOLTAGE_DEFAULT_VALUE = -1d;

public enum FictitiousGeneratorVoltageControlMode {
Copy link
Member

Choose a reason for hiding this comment

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

Why do you need en enum here? What happens when the enum is NORMAL?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

You mean instead of a boolean parameter ? No "need". I just saw the fictitiousGeneratorVoltageControlMode as a string param with values ALWAYS , NORMAL. ALWAYS meaning Always maintaining voltage, and NORMAL the normal behaviour - that is maintaining Voltage in started and target P between pmin and pmax.

ALWAYS,
NORMAL
};

protected static final FictitiousGeneratorVoltageControlMode FICTITIOUS_GENERATOR_VOLTAGE_CONTROL_MODE_DEFAULT_VALUE = FictitiousGeneratorVoltageControlMode.ALWAYS;

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 @@ -252,7 +259,9 @@ public enum SlackDistributionFailureBehavior {

public static final String GENERATOR_VOLTAGE_CONTROL_MIN_NOMINAL_VOLTAGE_PARAM_NAME = "generatorVoltageControlMinNominalVoltage";

private static <E extends Enum<E>> List<Object> getEnumPossibleValues(Class<E> enumClass) {
public static final String FICTITIOUS_GENERATOR_VOLTAGE_CONTROL_MODE = "fictitiousGeneratorVoltageControlMode";

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 @@ -322,7 +331,8 @@ private static <E extends Enum<E>> List<Object> getEnumPossibleValues(Class<E> e
new Parameter(REFERENCE_BUS_SELECTION_MODE_PARAM_NAME, ParameterType.STRING, "Reference bus selection mode", ReferenceBusSelector.DEFAULT_MODE.name(), getEnumPossibleValues(ReferenceBusSelectionMode.class)),
new Parameter(WRITE_REFERENCE_TERMINALS_PARAM_NAME, ParameterType.BOOLEAN, "Write Reference Terminals", WRITE_REFERENCE_TERMINALS_DEFAULT_VALUE),
new Parameter(VOLTAGE_TARGET_PRIORITIES_PARAM_NAME, ParameterType.STRING_LIST, "Voltage target priorities for voltage controls", LfNetworkParameters.VOLTAGE_CONTROL_PRIORITIES_DEFAULT_VALUE, getEnumPossibleValues(VoltageControl.Type.class)),
new Parameter(GENERATOR_VOLTAGE_CONTROL_MIN_NOMINAL_VOLTAGE_PARAM_NAME, ParameterType.DOUBLE, "Nominal voltage under which generator voltage controls are disabled during transformer voltage control outer loop of mode AFTER_GENERATOR_VOLTAGE_CONTROL, < 0 means automatic detection", OpenLoadFlowParameters.GENERATOR_VOLTAGE_CONTROL_MIN_NOMINAL_VOLTAGE_DEFAULT_VALUE)
new Parameter(GENERATOR_VOLTAGE_CONTROL_MIN_NOMINAL_VOLTAGE_PARAM_NAME, ParameterType.DOUBLE, "Nominal voltage under which generator voltage controls are disabled during transformer voltage control outer loop of mode AFTER_GENERATOR_VOLTAGE_CONTROL, < 0 means automatic detection", OpenLoadFlowParameters.GENERATOR_VOLTAGE_CONTROL_MIN_NOMINAL_VOLTAGE_DEFAULT_VALUE),
new Parameter(FICTITIOUS_GENERATOR_VOLTAGE_CONTROL_MODE, ParameterType.STRING, "Specificies how fictitious generators can voltage. Possible modes are 'always' and 'normal'. 'always', the default, means that voltage is controlled even if targetP is outside outside the minP - maxP interval.", OpenLoadFlowParameters.FICTITIOUS_GENERATOR_VOLTAGE_CONTROL_MODE_DEFAULT_VALUE.name(), getEnumPossibleValues(FictitiousGeneratorVoltageControlMode.class))
);

public enum VoltageInitModeOverride {
Expand Down Expand Up @@ -496,6 +506,8 @@ public enum ReactiveRangeCheckMode {

private double generatorVoltageControlMinNominalVoltage = GENERATOR_VOLTAGE_CONTROL_MIN_NOMINAL_VOLTAGE_DEFAULT_VALUE;

private FictitiousGeneratorVoltageControlMode fictitiousGeneratorVoltageControlMode = FICTITIOUS_GENERATOR_VOLTAGE_CONTROL_MODE_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 @@ -1174,6 +1186,15 @@ public double getGeneratorVoltageControlMinNominalVoltage() {
return generatorVoltageControlMinNominalVoltage;
}

public FictitiousGeneratorVoltageControlMode getFictitiousGeneratorVoltageControlMode() {
return fictitiousGeneratorVoltageControlMode;
}

public OpenLoadFlowParameters setFictitiousGeneratorVoltageControlMode(FictitiousGeneratorVoltageControlMode fictitiousGeneratorVoltageControlMode) {
this.fictitiousGeneratorVoltageControlMode = Objects.requireNonNull(fictitiousGeneratorVoltageControlMode);
return this;
}

public static OpenLoadFlowParameters load() {
return load(PlatformConfig.defaultConfig());
}
Expand Down Expand Up @@ -1399,6 +1420,8 @@ public OpenLoadFlowParameters update(Map<String, String> properties) {
.ifPresent(prop -> this.setVoltageTargetPriorities(parseStringListProp(prop)));
Optional.ofNullable(properties.get(GENERATOR_VOLTAGE_CONTROL_MIN_NOMINAL_VOLTAGE_PARAM_NAME))
.ifPresent(prop -> this.setGeneratorVoltageControlMinNominalVoltage(Double.parseDouble(prop)));
Optional.ofNullable(properties.get(FICTITIOUS_GENERATOR_VOLTAGE_CONTROL_MODE))
.ifPresent(prop -> this.setFictitiousGeneratorVoltageControlMode(FictitiousGeneratorVoltageControlMode.valueOf(prop)));
return this;
}

Expand Down Expand Up @@ -1470,6 +1493,7 @@ public Map<String, Object> toMap() {
map.put(WRITE_REFERENCE_TERMINALS_PARAM_NAME, writeReferenceTerminals);
map.put(VOLTAGE_TARGET_PRIORITIES_PARAM_NAME, voltageTargetPriorities);
map.put(GENERATOR_VOLTAGE_CONTROL_MIN_NOMINAL_VOLTAGE_PARAM_NAME, generatorVoltageControlMinNominalVoltage);
map.put(FICTITIOUS_GENERATOR_VOLTAGE_CONTROL_MODE, fictitiousGeneratorVoltageControlMode);
return map;
}

Expand Down Expand Up @@ -1597,7 +1621,8 @@ static LfNetworkParameters getNetworkParameters(LoadFlowParameters parameters, O
.setUseLoadModel(parametersExt.isUseLoadModel())
.setSimulateAutomationSystems(parametersExt.isSimulateAutomationSystems())
.setReferenceBusSelector(ReferenceBusSelector.fromMode(parametersExt.getReferenceBusSelectionMode()))
.setVoltageTargetPriorities(parametersExt.getVoltageTargetPriorities());
.setVoltageTargetPriorities(parametersExt.getVoltageTargetPriorities())
.setFictitiousGeneratorVoltageControlMode(parametersExt.getFictitiousGeneratorVoltageControlMode());
}

public static AcLoadFlowParameters createAcParameters(Network network, LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt,
Expand Down Expand Up @@ -1845,7 +1870,8 @@ public static boolean equals(LoadFlowParameters parameters1, LoadFlowParameters
extension1.getMaxSusceptanceMismatch() == extension2.getMaxSusceptanceMismatch() &&
extension1.getNewtonRaphsonStoppingCriteriaType() == extension2.getNewtonRaphsonStoppingCriteriaType() &&
Objects.equals(extension1.getVoltageTargetPriorities(), extension2.getVoltageTargetPriorities()) &&
extension1.getGeneratorVoltageControlMinNominalVoltage() == extension2.getGeneratorVoltageControlMinNominalVoltage();
extension1.getGeneratorVoltageControlMinNominalVoltage() == extension2.getGeneratorVoltageControlMinNominalVoltage() &&
extension1.getFictitiousGeneratorVoltageControlMode() == extension2.getFictitiousGeneratorVoltageControlMode();
}

public static LoadFlowParameters clone(LoadFlowParameters parameters) {
Expand Down Expand Up @@ -1936,7 +1962,8 @@ public static LoadFlowParameters clone(LoadFlowParameters parameters) {
.setNewtonRaphsonStoppingCriteriaType(extension.getNewtonRaphsonStoppingCriteriaType())
.setReferenceBusSelectionMode(extension.getReferenceBusSelectionMode())
.setVoltageTargetPriorities(extension.getVoltageTargetPriorities())
.setGeneratorVoltageControlMinNominalVoltage(extension.getGeneratorVoltageControlMinNominalVoltage());
.setGeneratorVoltageControlMinNominalVoltage(extension.getGeneratorVoltageControlMinNominalVoltage())
.setFictitiousGeneratorVoltageControlMode(extension.getFictitiousGeneratorVoltageControlMode());

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

private List<String> voltageTargetPriorities = VOLTAGE_CONTROL_PRIORITIES_DEFAULT_VALUE;

private OpenLoadFlowParameters.FictitiousGeneratorVoltageControlMode fictitiousGeneratorVoltageControlMode = OpenLoadFlowParameters.FictitiousGeneratorVoltageControlMode.ALWAYS;

public LfNetworkParameters() {
}

Expand Down Expand Up @@ -181,6 +183,7 @@ public LfNetworkParameters(LfNetworkParameters other) {
this.simulateAutomationSystems = other.simulateAutomationSystems;
this.referenceBusSelector = other.referenceBusSelector;
this.voltageTargetPriorities = new ArrayList<>(other.voltageTargetPriorities);
this.fictitiousGeneratorVoltageControlMode = other.fictitiousGeneratorVoltageControlMode;
}

public SlackBusSelector getSlackBusSelector() {
Expand Down Expand Up @@ -420,6 +423,15 @@ public LfNetworkParameters setReactiveRangeCheckMode(OpenLoadFlowParameters.Reac
return this;
}

public OpenLoadFlowParameters.FictitiousGeneratorVoltageControlMode getFictitiousGeneratorVoltageControlMode() {
return fictitiousGeneratorVoltageControlMode;
}

public LfNetworkParameters setFictitiousGeneratorVoltageControlMode(OpenLoadFlowParameters.FictitiousGeneratorVoltageControlMode fictitiousGeneratorVoltageControlMode) {
this.fictitiousGeneratorVoltageControlMode = fictitiousGeneratorVoltageControlMode;
return this;
}

public boolean isSvcVoltageMonitoring() {
return svcVoltageMonitoring;
}
Expand Down Expand Up @@ -595,6 +607,7 @@ public String toString() {
", simulateAutomationSystems=" + simulateAutomationSystems +
", referenceBusSelector=" + referenceBusSelector.getClass().getSimpleName() +
", voltageTargetPriorities=" + voltageTargetPriorities +
", fictitiousGeneratorVoltageControlMode" + fictitiousGeneratorVoltageControlMode +
')';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.powsybl.iidm.network.Generator;
import com.powsybl.iidm.network.ReactiveLimits;
import com.powsybl.iidm.network.extensions.*;
import com.powsybl.openloadflow.OpenLoadFlowParameters;
import com.powsybl.openloadflow.network.LfAsymGenerator;
import com.powsybl.openloadflow.network.LfNetwork;
import com.powsybl.openloadflow.network.LfNetworkParameters;
Expand Down Expand Up @@ -40,9 +41,15 @@ public final class LfGeneratorImpl extends AbstractLfGenerator {

private Double qPercent;

private final boolean voltageControlAlways;

private LfGeneratorImpl(Generator generator, LfNetwork network, LfNetworkParameters parameters, LfNetworkLoadingReport report) {
super(network, generator.getTargetP() / PerUnit.SB);
this.generatorRef = Ref.create(generator, parameters.isCacheEnabled());
// voltageControlAlways for condensers, or for fictitious generators if FictitiousGeneratorVoltageControlMode set to ALAWYS
voltageControlAlways = generator.isCondenser() ? true // USing ? : syntax because style checker forbids parenthesis in a pure boolean equation condenser || (fictif and param)
:
generator.isFictitious() && parameters.getFictitiousGeneratorVoltageControlMode() == OpenLoadFlowParameters.FictitiousGeneratorVoltageControlMode.ALWAYS;
participating = true;
droop = DEFAULT_DROOP;

Expand Down Expand Up @@ -200,4 +207,18 @@ public void updateState(LfNetworkStateUpdateParameters parameters) {
ReferenceTerminals.addTerminal(generator.getTerminal());
}
}

@Override
protected boolean checkIfGeneratorStartedForVoltageControl(LfNetworkLoadingReport report) {
return voltageControlAlways ?
true :
super.checkIfGeneratorStartedForVoltageControl(report);
}

@Override
protected boolean checkIfGeneratorIsInsideActivePowerLimitsForVoltageControl(LfNetworkParameters parameters, LfNetworkLoadingReport report) {
return voltageControlAlways ?
true :
super.checkIfGeneratorIsInsideActivePowerLimitsForVoltageControl(parameters, report);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,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], generatorVoltageControlMinNominalVoltage=-1.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], generatorVoltageControlMinNominalVoltage=-1.0, fictitiousGeneratorVoltageControlMode=ALWAYS)",
parameters.toString());
}

Expand Down
Loading