diff --git a/docs/loadflow/parameters.md b/docs/loadflow/parameters.md index adefc66f00..0980a43978 100644 --- a/docs/loadflow/parameters.md +++ b/docs/loadflow/parameters.md @@ -140,6 +140,12 @@ If set to false, any existing voltage remote control is converted to a local con according to the nominal voltage ratio between the remote regulated bus and the equipment terminal bus. The default value is `true`. +**maxGeneratorVoltageRemoteControlDistance** +Defines the maximum distance allowed between the remote regulated bus and the voltage controller generator (requires `voltageRemoteControl` to be set to `true`). +This distance is measured in number of branches separating the controlled bus and the generator. If the distance is higher than this parameter, then the voltage remote control is converted to a local control, rescaling the target voltage according to the nominal voltage ratio between the remote regulated bus and the equipment terminal bus. (This criteria covers also remote voltage control of static variable compensators, VSC converters and batteries) +If `maxGeneratorVoltageRemoteControlDistance` is set to `0` (or a negative value), there is no distance checking. +The default value is `2`. + **voltagePerReactivePowerControl** Whether simulation of static VAR compensators with voltage control enabled and a slope defined should be enabled (See [voltage per reactive power control extension](inv:powsyblcore:*:*:#voltage-per-reactive-power-control-extension)). diff --git a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java index e4b3e2d50b..702b54588d 100644 --- a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java +++ b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java @@ -276,6 +276,8 @@ public enum FictitiousGeneratorVoltageControlCheckMode { public static final String AREA_INTERCHANGE_P_MAX_MISMATCH_PARAM_NAME = "areaInterchangePMaxMismatch"; + public static final String MAX_GENERATOR_VOLTAGE_REMOTE_CONTROL_DISTANCE_PARAM_NAME = "maxGeneratorVoltageRemoteControlDistance"; + public static > List getEnumPossibleValues(Class enumClass) { return EnumSet.allOf(enumClass).stream().map(Enum::name).collect(Collectors.toList()); } @@ -413,7 +415,8 @@ public static > List getEnumPossibleValues(Class en 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(MAX_GENERATOR_VOLTAGE_REMOTE_CONTROL_DISTANCE_PARAM_NAME, ParameterType.INTEGER, "Maximum voltage remote control distance", LfNetworkParameters.MAX_GENERATOR_VOLTAGE_REMOTE_CONTROL_DISTANCE_DEFAULT_VALUE, ParameterScope.FUNCTIONAL, GENERATOR_VOLTAGE_CONTROL_CATEGORY_KEY) ); public enum VoltageInitModeOverride { @@ -597,6 +600,8 @@ public enum ReactiveRangeCheckMode { private double areaInterchangePMaxMismatch = AREA_INTERCHANGE_P_MAX_MISMATCH_DEFAULT_VALUE; + private int maxGeneratorVoltageRemoteControlDistance = LfNetworkParameters.MAX_GENERATOR_VOLTAGE_REMOTE_CONTROL_DISTANCE_DEFAULT_VALUE; + public static double checkParameterValue(double parameterValue, boolean condition, String parameterName) { if (!condition) { throw new IllegalArgumentException("Invalid value for parameter " + parameterName + ": " + parameterValue); @@ -1322,6 +1327,15 @@ public OpenLoadFlowParameters setAreaInterchangePMaxMismatch(double areaIntercha return this; } + public int getMaxGeneratorVoltageRemoteControlDistance() { + return maxGeneratorVoltageRemoteControlDistance; + } + + public OpenLoadFlowParameters setMaxGeneratorVoltageRemoteControlDistance(int maxGeneratorVoltageRemoteControlDistance) { + this.maxGeneratorVoltageRemoteControlDistance = maxGeneratorVoltageRemoteControlDistance; + return this; + } + public static OpenLoadFlowParameters load() { return load(PlatformConfig.defaultConfig()); } @@ -1400,7 +1414,8 @@ public static OpenLoadFlowParameters load(PlatformConfig platformConfig) { .setGeneratorVoltageControlMinNominalVoltage(config.getDoubleProperty(GENERATOR_VOLTAGE_CONTROL_MIN_NOMINAL_VOLTAGE_PARAM_NAME, GENERATOR_VOLTAGE_CONTROL_MIN_NOMINAL_VOLTAGE_DEFAULT_VALUE)) .setAreaInterchangeControl(config.getBooleanProperty(AREA_INTERCHANGE_CONTROL_PARAM_NAME, AREA_INTERCHANGE_CONTROL_DEFAULT_VALUE)) .setAreaInterchangeControlAreaType(config.getStringProperty(AREA_INTERCHANGE_CONTROL_AREA_TYPE_PARAM_NAME, LfNetworkParameters.AREA_INTERCHANGE_CONTROL_AREA_TYPE_DEFAULT_VALUE)) - .setAreaInterchangePMaxMismatch(config.getDoubleProperty(AREA_INTERCHANGE_P_MAX_MISMATCH_PARAM_NAME, AREA_INTERCHANGE_P_MAX_MISMATCH_DEFAULT_VALUE))); + .setAreaInterchangePMaxMismatch(config.getDoubleProperty(AREA_INTERCHANGE_P_MAX_MISMATCH_PARAM_NAME, AREA_INTERCHANGE_P_MAX_MISMATCH_DEFAULT_VALUE)) + .setMaxGeneratorVoltageRemoteControlDistance(config.getIntProperty(MAX_GENERATOR_VOLTAGE_REMOTE_CONTROL_DISTANCE_PARAM_NAME, LfNetworkParameters.MAX_GENERATOR_VOLTAGE_REMOTE_CONTROL_DISTANCE_DEFAULT_VALUE))); return parameters; } @@ -1561,6 +1576,8 @@ public OpenLoadFlowParameters update(Map 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(MAX_GENERATOR_VOLTAGE_REMOTE_CONTROL_DISTANCE_PARAM_NAME)) + .ifPresent(prop -> this.setMaxGeneratorVoltageRemoteControlDistance(Integer.parseInt(prop))); return this; } @@ -1637,6 +1654,7 @@ public Map 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(MAX_GENERATOR_VOLTAGE_REMOTE_CONTROL_DISTANCE_PARAM_NAME, maxGeneratorVoltageRemoteControlDistance); return map; } @@ -1793,7 +1811,8 @@ static LfNetworkParameters getNetworkParameters(LoadFlowParameters parameters, O .setVoltageTargetPriorities(parametersExt.getVoltageTargetPriorities()) .setFictitiousGeneratorVoltageControlCheckMode(parametersExt.getFictitiousGeneratorVoltageControlCheckMode()) .setAreaInterchangeControl(parametersExt.isAreaInterchangeControl()) - .setAreaInterchangeControlAreaType(parametersExt.getAreaInterchangeControlAreaType()); + .setAreaInterchangeControlAreaType(parametersExt.getAreaInterchangeControlAreaType()) + .setMaxGeneratorVoltageRemoteControlDistance(parametersExt.getMaxGeneratorVoltageRemoteControlDistance()); } public static AcLoadFlowParameters createAcParameters(Network network, LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt, @@ -2046,7 +2065,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.getMaxGeneratorVoltageRemoteControlDistance() == extension2.getMaxGeneratorVoltageRemoteControlDistance(); } public static LoadFlowParameters clone(LoadFlowParameters parameters) { @@ -2142,7 +2162,8 @@ public static LoadFlowParameters clone(LoadFlowParameters parameters) { .setFictitiousGeneratorVoltageControlCheckMode(extension.getFictitiousGeneratorVoltageControlCheckMode()) .setAreaInterchangeControl(extension.isAreaInterchangeControl()) .setAreaInterchangeControlAreaType(extension.getAreaInterchangeControlAreaType()) - .setAreaInterchangePMaxMismatch(extension.getAreaInterchangePMaxMismatch()); + .setAreaInterchangePMaxMismatch(extension.getAreaInterchangePMaxMismatch()) + .setMaxGeneratorVoltageRemoteControlDistance(extension.getMaxGeneratorVoltageRemoteControlDistance()); if (extension2 != null) { parameters2.addExtension(OpenLoadFlowParameters.class, extension2); diff --git a/src/main/java/com/powsybl/openloadflow/network/LfNetworkParameters.java b/src/main/java/com/powsybl/openloadflow/network/LfNetworkParameters.java index 6d80e48fe3..b01f1943fb 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfNetworkParameters.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfNetworkParameters.java @@ -58,6 +58,8 @@ public class LfNetworkParameters { public static final String AREA_INTERCHANGE_CONTROL_AREA_TYPE_DEFAULT_VALUE = "ControlArea"; + public static final int MAX_GENERATOR_VOLTAGE_REMOTE_CONTROL_DISTANCE_DEFAULT_VALUE = 2; + private SlackBusSelector slackBusSelector = new FirstSlackBusSelector(SLACK_BUS_COUNTRY_FILTER_DEFAULT_VALUE); private GraphConnectivityFactory connectivityFactory = new EvenShiloachGraphDecrementalConnectivityFactory<>(); @@ -148,6 +150,8 @@ public class LfNetworkParameters { private String areaInterchangeControlAreaType = AREA_INTERCHANGE_CONTROL_AREA_TYPE_DEFAULT_VALUE; + private int maxGeneratorVoltageRemoteControlDistance = MAX_GENERATOR_VOLTAGE_REMOTE_CONTROL_DISTANCE_DEFAULT_VALUE; + public LfNetworkParameters() { } @@ -194,6 +198,7 @@ public LfNetworkParameters(LfNetworkParameters other) { this.fictitiousGeneratorVoltageControlCheckMode = other.fictitiousGeneratorVoltageControlCheckMode; this.areaInterchangeControl = other.areaInterchangeControl; this.areaInterchangeControlAreaType = other.areaInterchangeControlAreaType; + this.maxGeneratorVoltageRemoteControlDistance = other.maxGeneratorVoltageRemoteControlDistance; } public SlackBusSelector getSlackBusSelector() { @@ -597,6 +602,15 @@ public LfNetworkParameters setAreaInterchangeControlAreaType(String areaIntercha return this; } + public int getMaxGeneratorVoltageRemoteControlDistance() { + return maxGeneratorVoltageRemoteControlDistance; + } + + public LfNetworkParameters setMaxGeneratorVoltageRemoteControlDistance(int maxGeneratorVoltageRemoteControlDistance) { + this.maxGeneratorVoltageRemoteControlDistance = maxGeneratorVoltageRemoteControlDistance; + return this; + } + @Override public String toString() { return "LfNetworkParameters(" + @@ -638,6 +652,7 @@ public String toString() { ", fictitiousGeneratorVoltageControlCheckMode=" + fictitiousGeneratorVoltageControlCheckMode + ", areaInterchangeControl=" + areaInterchangeControl + ", areaInterchangeControlAreaType=" + areaInterchangeControlAreaType + + ", maxGeneratorVoltageRemoteControlDistance=" + maxGeneratorVoltageRemoteControlDistance + ')'; } } diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java index 3df28cb263..173d9d38d6 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfNetworkLoaderImpl.java @@ -30,6 +30,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static com.powsybl.openloadflow.util.BusDistance.distanceBetweenBuses; import static com.powsybl.openloadflow.util.DebugUtil.DATE_TIME_FORMAT; import static com.powsybl.openloadflow.util.Markers.PERFORMANCE_MARKER; @@ -127,14 +128,24 @@ private static void createVoltageControls(List lfBuses, LfNetworkParamete } }); - if (parameters.isGeneratorVoltageRemoteControl() || controlledBus == controllerBus) { + boolean keepVoltageRemoteControl = false; + if (!parameters.isGeneratorVoltageRemoteControl() && controlledBus != controllerBus) { + LOGGER.warn("Remote voltage control is not activated. The voltage target of {} with remote control is rescaled from {} to {}", + controllerBus.getId(), controllerTargetV, controllerTargetV * controllerBus.getNominalV() / controlledBus.getNominalV()); + } else if (parameters.getMaxGeneratorVoltageRemoteControlDistance() > 0 && distanceBetweenBuses(controlledBus, controllerBus, parameters.getMaxGeneratorVoltageRemoteControlDistance()) > parameters.getMaxGeneratorVoltageRemoteControlDistance()) { + LOGGER.warn("Voltage controlled bus '{}' is too far from controller bus '{}' (maxGeneratorVoltageRemoteControlDistance is set to {}). The bus switches to local voltage control and target voltage is rescaled from {} to {}", + controlledBus.getId(), controllerBus.getId(), parameters.getMaxGeneratorVoltageRemoteControlDistance(), controllerTargetV, controllerTargetV * controllerBus.getNominalV() / controlledBus.getNominalV()); + Reports.reportTooFarControlledBus(controlledBus.getNetwork().getReportNode(), controllerBus.getId(), controlledBus.getId(), parameters.getMaxGeneratorVoltageRemoteControlDistance()); + } else { + keepVoltageRemoteControl = true; + } + + if (keepVoltageRemoteControl) { controlledBus.getGeneratorVoltageControl().ifPresentOrElse( vc -> updateGeneratorVoltageControl(vc, controllerBus, controllerTargetV), () -> createGeneratorVoltageControl(controlledBus, controllerBus, controllerTargetV, voltageControls, parameters)); } else { // if voltage remote control deactivated and remote control, set local control instead - LOGGER.warn("Remote voltage control is not activated. The voltage target of {} with remote control is rescaled from {} to {}", - controllerBus.getId(), controllerTargetV, controllerTargetV * controllerBus.getNominalV() / controlledBus.getNominalV()); controlledBus.getGeneratorVoltageControl().ifPresentOrElse( vc -> updateGeneratorVoltageControl(vc, controllerBus, controllerTargetV), // updating only to check targetV uniqueness () -> createGeneratorVoltageControl(controllerBus, controllerBus, controllerTargetV, voltageControls, parameters)); diff --git a/src/main/java/com/powsybl/openloadflow/util/BusDistance.java b/src/main/java/com/powsybl/openloadflow/util/BusDistance.java new file mode 100644 index 0000000000..86d1970432 --- /dev/null +++ b/src/main/java/com/powsybl/openloadflow/util/BusDistance.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2024, RTE (http://www.rte-france.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.util; + +import com.powsybl.openloadflow.network.LfBus; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author Sylvestre Prabakaran {@literal } + */ +public final class BusDistance { + + private BusDistance() { + } + + /** + * Breadth first search algorithm to compute distance between two LfBus in a network + * @param bus1 first LfBus (from which the breadth first search starts) + * @param bus2 second LfBus (searched bus) + * @param maxDistanceSearch the algorithm searches until this range and stops after this limit (or if every bus have been checked) + * @return measured distance (number of branches) or Integer.MAX_VALUE if bus2 is not found + */ + public static int distanceBetweenBuses(LfBus bus1, LfBus bus2, int maxDistanceSearch) { + Objects.requireNonNull(bus1); + Objects.requireNonNull(bus2); + if (bus1.equals(bus2)) { + return 0; + } + Set busesToCheck = new HashSet<>(); + Set checkedBuses = new HashSet<>(); + busesToCheck.add(bus1); + checkedBuses.add(bus1); + for (int distance = 1; distance <= maxDistanceSearch; distance++) { + busesToCheck = busesToCheck.stream() + .flatMap(bus -> bus.findNeighbors().keySet().stream()) + .collect(Collectors.toSet()); + busesToCheck.removeAll(checkedBuses); + if (busesToCheck.contains(bus2)) { + return distance; + } else if (busesToCheck.isEmpty()) { + return Integer.MAX_VALUE; + } + checkedBuses.addAll(busesToCheck); + } + return Integer.MAX_VALUE; + } +} diff --git a/src/main/java/com/powsybl/openloadflow/util/Reports.java b/src/main/java/com/powsybl/openloadflow/util/Reports.java index b35dcdf485..03d7c5f0fb 100644 --- a/src/main/java/com/powsybl/openloadflow/util/Reports.java +++ b/src/main/java/com/powsybl/openloadflow/util/Reports.java @@ -71,6 +71,16 @@ public static void reportNotUniqueControlledBus(ReportNode reportNode, String ge .add(); } + public static void reportTooFarControlledBus(ReportNode reportNode, String controllerBusId, String controlledBusId, int maxGeneratorVoltageRemoteControlDistance) { + reportNode.newReportNode() + .withMessageTemplate("tooFarControllerBus", "Remote voltage controlled bus ${controlledBusId} is too far from controller bus ${controllerBusId} (maxGeneratorVoltageRemoteControlDistance is set to ${maxGeneratorVoltageRemoteControlDistance}). Switching to local voltage control") + .withUntypedValue(CONTROLLED_BUS_ID, controlledBusId) + .withUntypedValue(CONTROLLER_BUS_ID, controllerBusId) + .withUntypedValue("maxGeneratorVoltageRemoteControlDistance", maxGeneratorVoltageRemoteControlDistance) + .withSeverity(TypedValue.WARN_SEVERITY) + .add(); + } + public static void reportNotUniqueTargetVControllerBus(ReportNode reportNode, String generatorIds, String controllerBusId, Double keptTargetV, Double rejectedTargetV) { reportNode.newReportNode() .withMessageTemplate("notUniqueTargetVControllerBus", "Generators [${generatorIds}] are connected to the same bus ${controllerBusId} with different target voltages: ${keptTargetV} kV (kept) and ${rejectedTargetV} kV (rejected)") diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java index e0743a0126..0192689946 100644 --- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java +++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java @@ -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, maxGeneratorVoltageRemoteControlDistance=2)", parameters.toString()); } diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java index 0b2c1a31b4..9fdc9ca2d3 100644 --- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java +++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java @@ -51,7 +51,7 @@ void test() { void testDcParameters() { Network network = Mockito.mock(Network.class); DcLoadFlowParameters dcParameters = OpenLoadFlowParameters.createDcParameters(network, new LoadFlowParameters().setReadSlackBus(true), new OpenLoadFlowParameters(), new DenseMatrixFactory(), new EvenShiloachGraphDecrementalConnectivityFactory<>(), true); - assertEquals("DcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=false, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, generatorReactivePowerRemoteControl=false, transformerReactivePowerControl=false, loadFlowModel=DC, reactiveLimits=false, hvdcAcEmulation=true, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=false, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, linePerUnitMode=IMPEDANCE, useLoadModel=false, simulateAutomationSystems=false, referenceBusSelector=ReferenceBusFirstSlackSelector, voltageTargetPriorities=[GENERATOR, TRANSFORMER, SHUNT], fictitiousGeneratorVoltageControlCheckMode=FORCED, areaInterchangeControl=false, areaInterchangeControlAreaType=ControlArea), equationSystemCreationParameters=DcEquationSystemCreationParameters(updateFlows=true, forcePhaseControlOffAndAddAngle1Var=true, useTransformerRatio=true, dcApproximationType=IGNORE_R), matrixFactory=DenseMatrixFactory, distributedSlack=true, balanceType=PROPORTIONAL_TO_GENERATION_P_MAX, setVToNan=true, maxOuterLoopIterations=20)", + assertEquals("DcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=false, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, generatorReactivePowerRemoteControl=false, transformerReactivePowerControl=false, loadFlowModel=DC, reactiveLimits=false, hvdcAcEmulation=true, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=false, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, linePerUnitMode=IMPEDANCE, useLoadModel=false, simulateAutomationSystems=false, referenceBusSelector=ReferenceBusFirstSlackSelector, voltageTargetPriorities=[GENERATOR, TRANSFORMER, SHUNT], fictitiousGeneratorVoltageControlCheckMode=FORCED, areaInterchangeControl=false, areaInterchangeControlAreaType=ControlArea, maxGeneratorVoltageRemoteControlDistance=2), equationSystemCreationParameters=DcEquationSystemCreationParameters(updateFlows=true, forcePhaseControlOffAndAddAngle1Var=true, useTransformerRatio=true, dcApproximationType=IGNORE_R), matrixFactory=DenseMatrixFactory, distributedSlack=true, balanceType=PROPORTIONAL_TO_GENERATION_P_MAX, setVToNan=true, maxOuterLoopIterations=20)", dcParameters.toString()); } @@ -59,7 +59,7 @@ void testDcParameters() { void testAcParameters() { Network network = Mockito.mock(Network.class); AcLoadFlowParameters acParameters = OpenLoadFlowParameters.createAcParameters(network, new LoadFlowParameters().setReadSlackBus(true), new OpenLoadFlowParameters(), new DenseMatrixFactory(), new EvenShiloachGraphDecrementalConnectivityFactory<>(), false, false); - assertEquals("AcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=true, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, generatorReactivePowerRemoteControl=false, transformerReactivePowerControl=false, loadFlowModel=AC, reactiveLimits=true, hvdcAcEmulation=true, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=true, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, linePerUnitMode=IMPEDANCE, useLoadModel=false, simulateAutomationSystems=false, referenceBusSelector=ReferenceBusFirstSlackSelector, voltageTargetPriorities=[GENERATOR, TRANSFORMER, SHUNT], fictitiousGeneratorVoltageControlCheckMode=FORCED, areaInterchangeControl=false, areaInterchangeControlAreaType=ControlArea), equationSystemCreationParameters=AcEquationSystemCreationParameters(forceA1Var=false), newtonRaphsonParameters=NewtonRaphsonParameters(maxIterations=15, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, stoppingCriteria=DefaultNewtonRaphsonStoppingCriteria, stateVectorScalingMode=NONE, alwaysUpdateNetwork=false, lineSearchStateVectorScalingMaxIteration=10, lineSearchStateVectorScalingStepFold=1.3333333333333333, maxVoltageChangeStateVectorScalingMaxDv=0.1, maxVoltageChangeStateVectorScalingMaxDphi=0.17453292519943295), newtonKrylovParameters=NewtonKrylovParameters(maxIterations=100, lineSearch=false), outerLoops=[DistributedSlackOuterLoop, MonitoringVoltageOuterLoop, ReactiveLimitsOuterLoop], maxOuterLoopIterations=20, matrixFactory=DenseMatrixFactory, voltageInitializer=UniformValueVoltageInitializer, asymmetrical=false, slackDistributionFailureBehavior=LEAVE_ON_SLACK_BUS, solverFactory=NewtonRaphsonFactory, detailedReport=false)", + assertEquals("AcLoadFlowParameters(networkParameters=LfNetworkParameters(slackBusSelector=NetworkSlackBusSelector, connectivityFactory=EvenShiloachGraphDecrementalConnectivityFactory, generatorVoltageRemoteControl=true, minImpedance=false, twtSplitShuntAdmittance=false, breakers=false, plausibleActivePowerLimit=5000.0, computeMainConnectedComponentOnly=true, countriesToBalance=[], distributedOnConformLoad=false, phaseControl=false, transformerVoltageControl=false, voltagePerReactivePowerControl=false, generatorReactivePowerRemoteControl=false, transformerReactivePowerControl=false, loadFlowModel=AC, reactiveLimits=true, hvdcAcEmulation=true, minPlausibleTargetVoltage=0.8, maxPlausibleTargetVoltage=1.2, loaderPostProcessorSelection=[], reactiveRangeCheckMode=MAX, lowImpedanceThreshold=1.0E-8, svcVoltageMonitoring=true, maxSlackBusCount=1, debugDir=null, secondaryVoltageControl=false, cacheEnabled=false, asymmetrical=false, minNominalVoltageTargetVoltageCheck=20.0, linePerUnitMode=IMPEDANCE, useLoadModel=false, simulateAutomationSystems=false, referenceBusSelector=ReferenceBusFirstSlackSelector, voltageTargetPriorities=[GENERATOR, TRANSFORMER, SHUNT], fictitiousGeneratorVoltageControlCheckMode=FORCED, areaInterchangeControl=false, areaInterchangeControlAreaType=ControlArea, maxGeneratorVoltageRemoteControlDistance=2), equationSystemCreationParameters=AcEquationSystemCreationParameters(forceA1Var=false), newtonRaphsonParameters=NewtonRaphsonParameters(maxIterations=15, minRealisticVoltage=0.5, maxRealisticVoltage=2.0, stoppingCriteria=DefaultNewtonRaphsonStoppingCriteria, stateVectorScalingMode=NONE, alwaysUpdateNetwork=false, lineSearchStateVectorScalingMaxIteration=10, lineSearchStateVectorScalingStepFold=1.3333333333333333, maxVoltageChangeStateVectorScalingMaxDv=0.1, maxVoltageChangeStateVectorScalingMaxDphi=0.17453292519943295), newtonKrylovParameters=NewtonKrylovParameters(maxIterations=100, lineSearch=false), outerLoops=[DistributedSlackOuterLoop, MonitoringVoltageOuterLoop, ReactiveLimitsOuterLoop], maxOuterLoopIterations=20, matrixFactory=DenseMatrixFactory, voltageInitializer=UniformValueVoltageInitializer, asymmetrical=false, slackDistributionFailureBehavior=LEAVE_ON_SLACK_BUS, solverFactory=NewtonRaphsonFactory, detailedReport=false)", acParameters.toString()); } @@ -87,7 +87,7 @@ void testGetExtendedVoltageInitializer() { @Test void specificParametersTest() { OpenLoadFlowProvider provider = new OpenLoadFlowProvider(); - assertEquals(71, provider.getSpecificParameters().size()); + assertEquals(72, provider.getSpecificParameters().size()); LoadFlowParameters parameters = new LoadFlowParameters(); provider.loadSpecificParameters(Collections.emptyMap()) @@ -110,7 +110,7 @@ void testCreateMapFromSpecificParameters() { OpenLoadFlowParameters parametersExt = new OpenLoadFlowParameters(); OpenLoadFlowProvider provider = new OpenLoadFlowProvider(); Map map = provider.createMapFromSpecificParameters(parametersExt); - assertEquals(71, map.size()); + assertEquals(72, map.size()); assertEquals(provider.getSpecificParameters().size(), map.size()); } diff --git a/src/test/java/com/powsybl/openloadflow/ac/GeneratorRemoteControlTest.java b/src/test/java/com/powsybl/openloadflow/ac/GeneratorRemoteControlTest.java index 94687673f4..61fb9bd701 100644 --- a/src/test/java/com/powsybl/openloadflow/ac/GeneratorRemoteControlTest.java +++ b/src/test/java/com/powsybl/openloadflow/ac/GeneratorRemoteControlTest.java @@ -975,4 +975,55 @@ void testGeneratorRemoteReactivePowerControlOutsideReactiveLimits() { assertReactivePowerEquals(2.031, l34.getTerminal2()); assertEquals(0.0, Math.abs(network.getBusView().getBus("b4_vl_0").getConnectedTerminalStream().mapToDouble(Terminal::getQ).sum()), 1E-2); } + + @Test + void testTooFarRemoteVoltageControl() throws IOException { + // create a network with the controlled bus located 3 branches far from the controller buses + network = VoltageControlNetworkFactory.createWithGeneratorFarFromRemoteControl(); + g1 = network.getGenerator("g1"); + g2 = network.getGenerator("g2"); + g3 = network.getGenerator("g3"); + b1 = network.getBusBreakerView().getBus("b1"); + b2 = network.getBusBreakerView().getBus("b2"); + b3 = network.getBusBreakerView().getBus("b3"); + Bus b6 = network.getBusBreakerView().getBus("b6"); + ReportNode reportNode = ReportNode.newRootReportNode() + .withMessageTemplate("testReport", "Test Report") + .build(); + + // First check with low maxRemoteVoltageControlDistance that detects too far controller buses + parametersExt.setMaxGeneratorVoltageRemoteControlDistance(2); + LoadFlowResult result1 = loadFlowRunner.run(network, VariantManagerConstants.INITIAL_VARIANT_ID, LocalComputationManager.getDefault(), parameters, reportNode); + assertTrue(result1.isFullyConverged()); + + // Bus b6 remote control is disabled + assertVoltageEquals(375.09, b6); + + // Switched to local voltage control for groups g1, g2 , g3 : targetV = 413.4kV * 20/400 = 20.65 kV + assertVoltageEquals(20.669, b1); + assertVoltageEquals(20.669, b2); + assertVoltageEquals(20.669, b3); + + assertReactivePowerEquals(-157.5988, g1.getTerminal()); + assertReactivePowerEquals(-189.2926, g2.getTerminal()); + assertReactivePowerEquals(41.6880, g3.getTerminal()); + LoadFlowAssert.assertReportEquals("/tooFarVoltageRemoteControlReport.txt", reportNode); + + // Second check with maxRemoteVoltageControlDistance=3 which allows the remote control + parametersExt.setMaxGeneratorVoltageRemoteControlDistance(3); + LoadFlowResult result2 = loadFlowRunner.run(network, parameters); + assertTrue(result2.isFullyConverged()); + + // Bus b6 remote control is kept : targetV = 413.4 kV + assertVoltageEquals(413.4, b6); + + // No local voltage control at buses b1, b2, b3 + assertVoltageEquals(22.338, b1); + assertVoltageEquals(22.135, b2); + assertVoltageEquals(23.576, b3); + + assertReactivePowerEquals(-100.4356, g1.getTerminal()); + assertReactivePowerEquals(-100.4356, g2.getTerminal()); + assertReactivePowerEquals(-100.4356, g3.getTerminal()); + } } diff --git a/src/test/java/com/powsybl/openloadflow/ac/NotSameNumberVariableEquationIssueTest.java b/src/test/java/com/powsybl/openloadflow/ac/NotSameNumberVariableEquationIssueTest.java index 0b72f905be..b5858326b6 100644 --- a/src/test/java/com/powsybl/openloadflow/ac/NotSameNumberVariableEquationIssueTest.java +++ b/src/test/java/com/powsybl/openloadflow/ac/NotSameNumberVariableEquationIssueTest.java @@ -87,7 +87,7 @@ void test() { .setB2(0) .add(); loadFlowRunner.run(network); - assertVoltageEquals(24.554, network.getBusBreakerView().getBus("NGEN")); - assertVoltageEquals(148.0, network.getBusBreakerView().getBus("NLOAD")); + assertVoltageEquals(24.5, network.getBusBreakerView().getBus("NGEN")); + assertVoltageEquals(147.58, network.getBusBreakerView().getBus("NLOAD")); } } diff --git a/src/test/java/com/powsybl/openloadflow/network/VoltageControlNetworkFactory.java b/src/test/java/com/powsybl/openloadflow/network/VoltageControlNetworkFactory.java index 04ab3d39cc..a8c47fa837 100644 --- a/src/test/java/com/powsybl/openloadflow/network/VoltageControlNetworkFactory.java +++ b/src/test/java/com/powsybl/openloadflow/network/VoltageControlNetworkFactory.java @@ -1411,4 +1411,59 @@ public static Network createFourBusNetworkWithSharedVoltageControl() { .setTargetV(1.2); return network; } + + /** + * g1 g2 g3 + * | | | + * b1 b2 b3 + * | | | + * 8 tr1 8 tr2 8 tr3 + * | | | + * +------ b4 -----+ + * | + * b5 + * | + * b6 + * | + * l6 + */ + public static Network createWithGeneratorFarFromRemoteControl() { + Network network = createWithGeneratorRemoteControl(); + VoltageLevel vl4 = network.getVoltageLevel("vl4"); + vl4.getBusBreakerView().newBus() + .setId("b5") + .add(); + vl4.getBusBreakerView().newBus() + .setId("b6") + .add(); + Load l6 = vl4.newLoad() + .setId("l6") + .setBus("b6") + .setConnectableBus("b6") + .setP0(299.6) + .setQ0(200) + .add(); + network.newLine() + .setId("line45") + .setBus1("b4") + .setBus2("b5") + .setR(1.0) + .setX(10.0) + .setG1(0.005) + .add(); + network.newLine() + .setId("line56") + .setBus1("b5") + .setBus2("b6") + .setR(1.0) + .setX(10.0) + .setG1(0.005) + .add(); + network.getGenerator("g1").setRegulatingTerminal(l6.getTerminal()).setVoltageRegulatorOn(true); + network.getGenerator("g2").setRegulatingTerminal(l6.getTerminal()).setVoltageRegulatorOn(true); + network.getGenerator("g3").setRegulatingTerminal(l6.getTerminal()).setVoltageRegulatorOn(true); + network.getLoad("l4").remove(); + return network; + } + } diff --git a/src/test/java/com/powsybl/openloadflow/util/BusDistanceTest.java b/src/test/java/com/powsybl/openloadflow/util/BusDistanceTest.java new file mode 100644 index 0000000000..4bded69e7b --- /dev/null +++ b/src/test/java/com/powsybl/openloadflow/util/BusDistanceTest.java @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2024, RTE (http://www.rte-france.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.util; + +import com.powsybl.openloadflow.network.LfBus; +import com.powsybl.openloadflow.network.LfNetwork; +import com.powsybl.openloadflow.network.LfNetworkParameters; +import com.powsybl.openloadflow.network.VoltageControlNetworkFactory; +import com.powsybl.openloadflow.network.impl.LfNetworkLoaderImpl; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author Sylvestre Prabakaran {@literal } + */ +class BusDistanceTest { + + private LfNetwork network; + + private LfBus bus1; + private LfBus bus2; + + @BeforeEach + void setUp() { + network = LfNetwork.load(VoltageControlNetworkFactory.createWithGeneratorFarFromRemoteControl(), + new LfNetworkLoaderImpl(), + new LfNetworkParameters()).get(0); + } + + @Test + void testBusDistance() { + bus1 = network.getBusById("vl1_0"); // Bus "b1" + bus2 = network.getBusById("vl4_0"); // Bus "b4" + assertEquals(0, BusDistance.distanceBetweenBuses(bus1, bus1, 4)); + assertEquals(1, BusDistance.distanceBetweenBuses(bus1, bus2, 4)); + + bus1 = network.getBusById("vl1_0"); // Bus "b1" + bus2 = network.getBusById("vl2_0"); // Bus "b2" + assertEquals(2, BusDistance.distanceBetweenBuses(bus1, bus2, 4)); + + bus1 = network.getBusById("vl1_0"); // Bus "b1" + bus2 = network.getBusById("vl4_2"); // Bus "b6" + assertEquals(3, BusDistance.distanceBetweenBuses(bus1, bus2, 3)); + } + + @Test + void testFartherThanMaxDistance() { + bus1 = network.getBusById("vl1_0"); // Bus "b1" + bus2 = network.getBusById("vl4_2"); // Bus "b6" + assertEquals(Integer.MAX_VALUE, BusDistance.distanceBetweenBuses(bus1, bus2, 2)); + } + +} diff --git a/src/test/resources/debug-parameters.json b/src/test/resources/debug-parameters.json index 4c83e814d3..e5d363f273 100644 --- a/src/test/resources/debug-parameters.json +++ b/src/test/resources/debug-parameters.json @@ -90,7 +90,8 @@ "fictitiousGeneratorVoltageControlCheckMode" : "FORCED", "areaInterchangeControl" : false, "areaInterchangeControlAreaType" : "ControlArea", - "areaInterchangePMaxMismatch" : 2.0 + "areaInterchangePMaxMismatch" : 2.0, + "maxGeneratorVoltageRemoteControlDistance" : 2 } } }, diff --git a/src/test/resources/tooFarVoltageRemoteControlReport.txt b/src/test/resources/tooFarVoltageRemoteControlReport.txt new file mode 100644 index 0000000000..16cca1d8fb --- /dev/null +++ b/src/test/resources/tooFarVoltageRemoteControlReport.txt @@ -0,0 +1,13 @@ ++ Test Report + + Load flow on network 'generator-remote-control-test' + + Network CC0 SC0 + Remote voltage controlled bus vl4_2 is too far from controller bus vl1_0 (maxGeneratorVoltageRemoteControlDistance is set to 2). Switching to local voltage control + Remote voltage controlled bus vl4_2 is too far from controller bus vl2_0 (maxGeneratorVoltageRemoteControlDistance is set to 2). Switching to local voltage control + Remote voltage controlled bus vl4_2 is too far from controller bus vl3_0 (maxGeneratorVoltageRemoteControlDistance is set to 2). Switching to local voltage control + + Network info + Network has 6 buses and 5 branches + Network balance: active generation=300.0 MW, active load=299.6 MW, reactive generation=0.0 MVar, reactive load=200.0 MVar + Angle reference bus: vl4_0 + Slack bus: vl4_0 + Outer loop VoltageMonitoring + AC load flow completed successfully (solverStatus=CONVERGED, outerloopStatus=STABLE)