diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/PropagatedContingency.java b/src/main/java/com/powsybl/openloadflow/network/impl/PropagatedContingency.java index 9f39164655..4d50702b1a 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/PropagatedContingency.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/PropagatedContingency.java @@ -41,6 +41,8 @@ public class PropagatedContingency { private final Map shuntIdsToShift; + private final Set originalPowerShiftIds; + public Contingency getContingency() { return contingency; } @@ -73,9 +75,14 @@ public Map getShuntIdsToShift() { return shuntIdsToShift; } + public Set getOriginalPowerShiftIds() { + return originalPowerShiftIds; + } + public PropagatedContingency(Contingency contingency, int index, Set branchIdsToOpen, Set hvdcIdsToOpen, Set switchesToOpen, Set generatorIdsToLose, - Map loadIdsToShift, Map shuntIdsToShift) { + Map loadIdsToShift, Map shuntIdsToShift, + Set originalPowerShiftIds) { this.contingency = Objects.requireNonNull(contingency); this.index = index; this.branchIdsToOpen = Objects.requireNonNull(branchIdsToOpen); @@ -84,6 +91,7 @@ public PropagatedContingency(Contingency contingency, int index, Set bra this.generatorIdsToLose = Objects.requireNonNull(generatorIdsToLose); this.loadIdsToShift = Objects.requireNonNull(loadIdsToShift); this.shuntIdsToShift = Objects.requireNonNull(shuntIdsToShift); + this.originalPowerShiftIds = Objects.requireNonNull(originalPowerShiftIds); for (Switch sw : switchesToOpen) { branchIdsToOpen.add(sw.getId()); @@ -142,6 +150,7 @@ private static PropagatedContingency create(Network network, Contingency conting Set generatorIdsToLose = new HashSet<>(); Map loadIdsToShift = new HashMap<>(); Map shuntIdsToShift = new HashMap<>(); + Set originalPowerShiftIds = new LinkedHashSet<>(); // process terminals disconnected, in particular process injection power shift for (Terminal terminal : terminalsToDisconnect) { @@ -159,6 +168,7 @@ private static PropagatedContingency create(Network network, Contingency conting case LOAD: Load load = (Load) connectable; + originalPowerShiftIds.add(load.getId()); addPowerShift(load.getTerminal(), loadIdsToShift, getLoadPowerShift(load, slackDistributionOnConformLoad), breakers); break; @@ -184,6 +194,7 @@ private static PropagatedContingency create(Network network, Contingency conting LccConverterStation lcc = (LccConverterStation) connectable; PowerShift lccPowerShift = new PowerShift(HvdcConverterStations.getConverterStationTargetP(lcc) / PerUnit.SB, 0, HvdcConverterStations.getLccConverterStationLoadTargetQ(lcc) / PerUnit.SB); + originalPowerShiftIds.add(lcc.getId()); addPowerShift(lcc.getTerminal(), loadIdsToShift, lccPowerShift, breakers); } break; @@ -205,7 +216,7 @@ private static PropagatedContingency create(Network network, Contingency conting } return new PropagatedContingency(contingency, index, branchIdsToOpen, hvdcIdsToOpen, switchesToOpen, - generatorIdsToLose, loadIdsToShift, shuntIdsToShift); + generatorIdsToLose, loadIdsToShift, shuntIdsToShift, originalPowerShiftIds); } private static void addPowerShift(Terminal terminal, Map loadIdsToShift, PowerShift powerShift, boolean breakers) { diff --git a/src/main/java/com/powsybl/openloadflow/sensi/AbstractSensitivityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sensi/AbstractSensitivityAnalysis.java index eff12df7ae..89006bf0de 100644 --- a/src/main/java/com/powsybl/openloadflow/sensi/AbstractSensitivityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sensi/AbstractSensitivityAnalysis.java @@ -20,10 +20,7 @@ import com.powsybl.openloadflow.equations.EquationTerm; import com.powsybl.openloadflow.equations.Quantity; import com.powsybl.openloadflow.graph.GraphConnectivityFactory; -import com.powsybl.openloadflow.network.LfBranch; -import com.powsybl.openloadflow.network.LfBus; -import com.powsybl.openloadflow.network.LfElement; -import com.powsybl.openloadflow.network.LfNetwork; +import com.powsybl.openloadflow.network.*; import com.powsybl.openloadflow.network.impl.HvdcConverterStations; import com.powsybl.openloadflow.network.impl.LfDanglingLineBus; import com.powsybl.openloadflow.network.impl.PropagatedContingency; @@ -143,6 +140,8 @@ enum Status { boolean isFunctionConnectedToSlackComponent(Set lostBuses, Set lostBranches); + boolean isVariableInContingency(PropagatedContingency propagatedContingency); + SensitivityFactorGroup getGroup(); void setGroup(SensitivityFactorGroup group); @@ -152,7 +151,7 @@ abstract static class AbstractLfSensitivityFactor & Quantity, private final int index; - private final String variableId; + protected final String variableId; private final String functionId; @@ -357,21 +356,48 @@ public boolean isVariableConnectedToSlackComponent(Set disabledBuses, Set public boolean isFunctionConnectedToSlackComponent(Set disabledBuses, Set disabledBranches) { return isElementConnectedToSlackComponent(functionElement, disabledBuses, disabledBranches); } + + @Override + public boolean isVariableInContingency(PropagatedContingency contingency) { + if (contingency != null) { + switch (variableType) { + case INJECTION_ACTIVE_POWER: + case HVDC_LINE_ACTIVE_POWER: + // a load, a generator, a dangling line, an LCC or a VSC converter station. + return contingency.getGeneratorIdsToLose().contains(variableId) || contingency.getOriginalPowerShiftIds().contains(variableId); + case BUS_TARGET_VOLTAGE: + // a generator or a two windings transformer. + // shunt contingency not supported yet. + // phase shifter in a three windings transformer not supported yet. + return contingency.getGeneratorIdsToLose().contains(variableId) || contingency.getBranchIdsToOpen().contains(variableId); + case TRANSFORMER_PHASE: + // a phase shifter on a two windings transformer. + return contingency.getBranchIdsToOpen().contains(variableId); + default: + return false; + } + } else { + return false; + } + } } static class MultiVariablesLfSensitivityFactor & Quantity, E extends Enum & Quantity> extends AbstractLfSensitivityFactor { private final Map weightedVariableElements; + private final Set originalVariableSetIds; + MultiVariablesLfSensitivityFactor(int index, String variableId, String functionId, LfElement functionElement, SensitivityFunctionType functionType, Map weightedVariableElements, SensitivityVariableType variableType, - ContingencyContext contingencyContext) { + ContingencyContext contingencyContext, Set originalVariableSetIds) { super(index, variableId, functionId, functionElement, functionType, variableType, contingencyContext); this.weightedVariableElements = weightedVariableElements; if (weightedVariableElements.isEmpty()) { status = functionElement == null ? Status.SKIP : Status.VALID_ONLY_FOR_FUNCTION; } + this.originalVariableSetIds = originalVariableSetIds; } public Map getWeightedVariableElements() { @@ -384,9 +410,6 @@ public Collection getVariableElements() { @Override public boolean isVariableConnectedToSlackComponent(Set disabledBuses, Set disabledBranches) { - if (!isElementConnectedToSlackComponent(functionElement, disabledBuses, disabledBranches)) { - return false; - } for (LfElement lfElement : getVariableElements()) { if (isElementConnectedToSlackComponent(lfElement, disabledBuses, disabledBranches)) { return true; @@ -399,6 +422,19 @@ public boolean isVariableConnectedToSlackComponent(Set disabledBuses, Set public boolean isFunctionConnectedToSlackComponent(Set disabledBuses, Set disabledBranches) { return isElementConnectedToSlackComponent(functionElement, disabledBuses, disabledBranches); } + + @Override + public boolean isVariableInContingency(PropagatedContingency contingency) { + if (contingency != null) { + int sizeCommonIds = (int) Stream.concat(contingency.getGeneratorIdsToLose().stream(), contingency.getOriginalPowerShiftIds().stream()) + .distinct() + .filter(originalVariableSetIds::contains) + .count(); + return sizeCommonIds == originalVariableSetIds.size(); + } else { + return false; + } + } } interface SensitivityFactorGroup & Quantity, E extends Enum & Quantity> { @@ -623,33 +659,49 @@ protected void fillRhsSensitivityVariable(SensitivityFactorGroupList facto } } - protected void setPredefinedResults(Collection> lfFactors, Set disabledBuses, Set disabledBranches) { + protected void setPredefinedResults(Collection> lfFactors, Set disabledBuses, + Set disabledBranches, PropagatedContingency propagatedContingency) { for (LfSensitivityFactor factor : lfFactors) { - if (factor.getStatus() == LfSensitivityFactor.Status.VALID) { - // after a contingency, we check if the factor function and the variable are in different connected components - boolean variableConnected = factor.isVariableConnectedToSlackComponent(disabledBuses, disabledBranches); - boolean functionConnected = factor.isFunctionConnectedToSlackComponent(disabledBuses, disabledBranches); - if (!variableConnected && functionConnected) { - // VALID_ONLY_FOR_FUNCTION status - factor.setSensitivityValuePredefinedResult(0d); - } else if (!variableConnected && !functionConnected) { - // SKIP status - factor.setSensitivityValuePredefinedResult(Double.NaN); - factor.setFunctionPredefinedResult(Double.NaN); - } else if (variableConnected && !functionConnected) { + Pair, Optional> predefinedResults = getPredefinedResults(factor, disabledBuses, disabledBranches, propagatedContingency); + predefinedResults.getLeft().ifPresent(factor::setSensitivityValuePredefinedResult); + predefinedResults.getRight().ifPresent(factor::setFunctionPredefinedResult); + } + } + + protected Pair, Optional> getPredefinedResults(LfSensitivityFactor factor, Set disabledBuses, + Set disabledBranches, PropagatedContingency propagatedContingency) { + Double sensitivityValuePredefinedResult = null; + Double functionPredefinedResult = null; + if (factor.getStatus() == LfSensitivityFactor.Status.VALID) { + // after a contingency, we check if the factor function and the variable are in different connected components + // or if the variable is in contingency. Note that a branch in contingency is considered as not connected to the slack component. + boolean variableConnected = factor.isVariableConnectedToSlackComponent(disabledBuses, disabledBranches) && !factor.isVariableInContingency(propagatedContingency); + boolean functionConnectedToSlackComponent = factor.isFunctionConnectedToSlackComponent(disabledBuses, disabledBranches); + if (variableConnected) { + if (!functionConnectedToSlackComponent) { // ZERO status - factor.setSensitivityValuePredefinedResult(0d); - factor.setFunctionPredefinedResult(Double.NaN); - } - } else if (factor.getStatus() == LfSensitivityFactor.Status.VALID_ONLY_FOR_FUNCTION) { - factor.setSensitivityValuePredefinedResult(0d); - if (!factor.isFunctionConnectedToSlackComponent(disabledBuses, disabledBranches)) { - factor.setFunctionPredefinedResult(Double.NaN); + sensitivityValuePredefinedResult = 0d; + functionPredefinedResult = Double.NaN; } } else { - throw new IllegalStateException("Unexpected factor status: " + factor.getStatus()); + if (functionConnectedToSlackComponent) { + // VALID_ONLY_FOR_FUNCTION status + sensitivityValuePredefinedResult = 0d; + } else { + // SKIP status + sensitivityValuePredefinedResult = Double.NaN; + functionPredefinedResult = Double.NaN; + } + } + } else if (factor.getStatus() == LfSensitivityFactor.Status.VALID_ONLY_FOR_FUNCTION) { + sensitivityValuePredefinedResult = 0d; + if (!factor.isFunctionConnectedToSlackComponent(disabledBuses, disabledBranches)) { + functionPredefinedResult = Double.NaN; } + } else { + throw new IllegalStateException("Unexpected factor status: " + factor.getStatus()); } + return Pair.of(Optional.ofNullable(sensitivityValuePredefinedResult), Optional.ofNullable(functionPredefinedResult)); } protected boolean rescaleGlsk(SensitivityFactorGroupList factorGroups, Set nonConnectedBuses) { @@ -905,6 +957,7 @@ public SensitivityFactorHolder readAndCheckFactors(Network network, Map factorHolder = new SensitivityFactorHolder<>(); final Map> injectionBusesByVariableId = new LinkedHashMap<>(); + final Map> originalVariableSetIdsByVariableId = new LinkedHashMap<>(); final Map busCache = new HashMap<>(); int[] factorIndex = new int[1]; factorReader.read((functionType, functionId, variableType, variableId, variableSet, contingencyContext) -> { @@ -917,9 +970,12 @@ public SensitivityFactorHolder readAndCheckFactors(Network network, Map injectionLfBuses = injectionBusesByVariableId.get(variableId); - if (injectionLfBuses == null) { + Set originalVariableSetIds = originalVariableSetIdsByVariableId.get(variableId); + if (injectionLfBuses == null && originalVariableSetIds == null) { injectionLfBuses = new LinkedHashMap<>(); + originalVariableSetIds = new HashSet<>(); injectionBusesByVariableId.put(variableId, injectionLfBuses); + originalVariableSetIdsByVariableId.put(variableId, originalVariableSetIds); SensitivityVariableSet set = variableSetsById.get(variableId); if (set == null) { throw new PowsyblException("Variable set '" + variableId + "' not found"); @@ -933,6 +989,7 @@ public SensitivityFactorHolder readAndCheckFactors(Network network, Map readAndCheckFactors(Network network, Map(factorIndex[0], variableId, functionId, functionElement, functionType, - injectionLfBuses, variableType, contingencyContext)); + injectionLfBuses, variableType, contingencyContext, originalVariableSetIds)); } else { throw createVariableTypeNotSupportedWithFunctionTypeException(variableType, functionType); } @@ -968,17 +1025,20 @@ public SensitivityFactorHolder readAndCheckFactors(Network network, Map we create a multi (bi) variables factor Map injectionLfBuses = new HashMap<>(2); + Set originalVariableSetIds = new HashSet<>(2); if (bus1 != null) { // FIXME: for LCC, Q changes when P changes injectionLfBuses.put(bus1, HvdcConverterStations.getActivePowerSetpointMultiplier(hvdcLine.getConverterStation1())); + originalVariableSetIds.add(hvdcLine.getConverterStation1().getId()); } if (bus2 != null) { // FIXME: for LCC, Q changes when P changes injectionLfBuses.put(bus2, HvdcConverterStations.getActivePowerSetpointMultiplier(hvdcLine.getConverterStation2())); + originalVariableSetIds.add(hvdcLine.getConverterStation2().getId()); } factorHolder.addFactor(new MultiVariablesLfSensitivityFactor<>(factorIndex[0], variableId, - functionId, functionElement, functionType, injectionLfBuses, variableType, contingencyContext)); + functionId, functionElement, functionType, injectionLfBuses, variableType, contingencyContext, originalVariableSetIds)); } else { LfElement functionElement; LfElement variableElement; diff --git a/src/main/java/com/powsybl/openloadflow/sensi/AcSensitivityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sensi/AcSensitivityAnalysis.java index 0dcb7c48d6..c229994504 100644 --- a/src/main/java/com/powsybl/openloadflow/sensi/AcSensitivityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sensi/AcSensitivityAnalysis.java @@ -318,33 +318,19 @@ public void analyse(Network network, List contingencies, lfContingency.apply(lfParameters.getBalanceType()); + setPredefinedResults(contingencyFactors, lfContingency.getDisabledBuses(), lfContingency.getDisabledBranches(), contingency); + Map postContingencySlackParticipationByBus; Set slackConnectedComponent; if (lfContingency.getDisabledBuses().isEmpty()) { // contingency not breaking connectivity LOGGER.debug("Contingency '{}' without loss of connectivity", lfContingency.getId()); slackConnectedComponent = new HashSet<>(lfNetwork.getBuses()); - - // Sensitivity values 0 and function reference NaN in case of a sensitivity on a disabled branch - contingencyFactors.stream() - .filter(lfFactor -> lfFactor.getFunctionElement() instanceof LfBranch) - .filter(lfFactor -> lfContingency.getDisabledBranches().contains(lfFactor.getFunctionElement())) - .forEach(lfFactor -> { - lfFactor.setSensitivityValuePredefinedResult(0d); - lfFactor.setFunctionPredefinedResult(Double.NaN); - }); - - // Sensitivity values 0 in case of a sensitivity from the transformer phase of a disabled transformer - contingencyFactors.stream() - .filter(lfFactor -> lfFactor.getVariableType().equals(SensitivityVariableType.TRANSFORMER_PHASE)) - .filter(lfFactor -> lfContingency.getDisabledBranches().contains(lfNetwork.getBranchById(lfFactor.getVariableId()))) - .forEach(lfFactor -> lfFactor.setSensitivityValuePredefinedResult(0d)); } else { // contingency breaking connectivity - LOGGER.debug("Contingency {} with loss of connectivity", lfContingency.getId()); + LOGGER.debug("Contingency '{}' with loss of connectivity", lfContingency.getId()); // we check if factors are still in the main component slackConnectedComponent = new HashSet<>(lfNetwork.getBuses()).stream().filter(Predicate.not(lfContingency.getDisabledBuses()::contains)).collect(Collectors.toSet()); - setPredefinedResults(contingencyFactors, lfContingency.getDisabledBuses(), lfContingency.getDisabledBranches()); // we recompute GLSK weights if needed rescaleGlsk(factorGroups, lfContingency.getDisabledBuses()); } diff --git a/src/main/java/com/powsybl/openloadflow/sensi/DcSensitivityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sensi/DcSensitivityAnalysis.java index e232b7d75f..172f5148dd 100644 --- a/src/main/java/com/powsybl/openloadflow/sensi/DcSensitivityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sensi/DcSensitivityAnalysis.java @@ -37,6 +37,7 @@ import com.powsybl.openloadflow.network.util.UniformValueVoltageInitializer; import com.powsybl.openloadflow.network.util.VoltageInitializer; import com.powsybl.sensitivity.*; +import org.apache.commons.lang3.tuple.Pair; import java.util.*; import java.util.concurrent.TimeUnit; @@ -163,10 +164,6 @@ public Map, Collection> getContingenciesInd static class ConnectivityAnalysisResult { - private final Map, Double> predefinedResultsSensi = new HashMap<>(); - - private final Map, Double> predefinedResultsRef = new HashMap<>(); - private final Collection contingencies = new HashSet<>(); private final Set elementsToReconnect; @@ -175,56 +172,14 @@ static class ConnectivityAnalysisResult { private final Set slackConnectedComponent; + private final Set partialDisabledBranches; // branches disabled because of connectivity loss. + protected ConnectivityAnalysisResult(Set elementsToReconnect, Collection> factors, GraphConnectivity connectivity, LfNetwork lfNetwork) { this.elementsToReconnect = elementsToReconnect; slackConnectedComponent = connectivity.getConnectedComponent(lfNetwork.getSlackBus()); disabledBuses = connectivity.getVerticesRemovedFromMainComponent(); - fillPredefinedResults(factors, connectivity); - } - - private void fillPredefinedResults(Collection> factors, - GraphConnectivity connectivity) { - Set disabledBranches = connectivity.getEdgesRemovedFromMainComponent(); - for (LfSensitivityFactor factor : factors) { - if (factor.getStatus() == LfSensitivityFactor.Status.VALID) { - // after a contingency, we check if the factor function and the variable are in different connected components - boolean variableConnected = factor.isVariableConnectedToSlackComponent(disabledBuses, disabledBranches); - boolean functionConnected = factor.isFunctionConnectedToSlackComponent(disabledBuses, disabledBranches); - if (!variableConnected && functionConnected) { - // VALID_ONLY_FOR_FUNCTION status - predefinedResultsSensi.put(factor, 0d); - } - if (!variableConnected && !functionConnected) { - // SKIP status - predefinedResultsSensi.put(factor, Double.NaN); - predefinedResultsRef.put(factor, Double.NaN); - } - if (variableConnected && !functionConnected) { - // ZERO status - predefinedResultsSensi.put(factor, 0d); - predefinedResultsRef.put(factor, Double.NaN); - } - } else if (factor.getStatus() == LfSensitivityFactor.Status.VALID_ONLY_FOR_FUNCTION) { - // Sensitivity equals 0 for VALID_REFERENCE factors - predefinedResultsSensi.put(factor, 0d); - if (!factor.isFunctionConnectedToSlackComponent(disabledBuses, disabledBranches)) { - // The reference is not in the main componant of the post contingency network. - // Therefore, its value cannot be computed. - predefinedResultsRef.put(factor, Double.NaN); - } - } else { - throw new IllegalStateException("Unexpected factor status: " + factor.getStatus()); - } - } - } - - void setSensitivityValuePredefinedResults() { - predefinedResultsSensi.forEach(LfSensitivityFactor::setSensitivityValuePredefinedResult); - } - - void setFunctionPredefinedResults() { - predefinedResultsRef.forEach(LfSensitivityFactor::setFunctionPredefinedResult); + partialDisabledBranches = connectivity.getEdgesRemovedFromMainComponent(); } public Collection getContingencies() { @@ -242,6 +197,10 @@ public Set getDisabledBuses() { public Set getSlackConnectedComponent() { return slackConnectedComponent; } + + public Set getPartialDisabledBranches() { + return partialDisabledBranches; + } } public DcSensitivityAnalysis(MatrixFactory matrixFactory, GraphConnectivityFactory connectivityFactory) { @@ -307,46 +266,28 @@ protected DenseMatrix calculateActivePowerFlows(LfNetwork network, DcLoadFlowPar */ private void createBranchSensitivityValue(LfSensitivityFactor factor, DenseMatrix contingenciesStates, Collection contingencyElements, - PropagatedContingency contingency, SensitivityResultWriter resultWriter) { - boolean predefSensiValue = factor.getSensitivityValuePredefinedResult() != null; - boolean predefFlowValue = factor.getFunctionPredefinedResult() != null; + PropagatedContingency contingency, SensitivityResultWriter resultWriter, + Set disabledBuses, Set disabledBranches) { + Pair, Optional> predefinedResults = getPredefinedResults(factor, disabledBuses, disabledBranches, contingency); + Optional sensitivityValuePredefinedResult = predefinedResults.getLeft(); + Optional functionPredefinedResults = predefinedResults.getRight(); + double sensitivityValue = sensitivityValuePredefinedResult.orElseGet(factor::getBaseSensitivityValue); + double functionValue = functionPredefinedResults.orElseGet(factor::getFunctionReference); EquationTerm p1 = factor.getFunctionEquationTerm(); - String functionBranchId = factor.getFunctionElement().getId(); - double sensiValue = predefSensiValue ? factor.getSensitivityValuePredefinedResult() : factor.getBaseSensitivityValue(); - double flowValue = predefFlowValue ? factor.getFunctionPredefinedResult() : factor.getFunctionReference(); - - if (factor.getStatus() == LfSensitivityFactor.Status.VALID_ONLY_FOR_FUNCTION) { - sensiValue = 0d; - predefSensiValue = true; - } - if (contingency != null && contingency.getBranchIdsToOpen().stream().anyMatch(id -> id.equals(functionBranchId))) { - // the monitored branch is in contingency, sensitivity equals 0 and post-contingency flow equals NaN in any case. - flowValue = Double.NaN; - sensiValue = 0d; - predefFlowValue = true; - predefSensiValue = true; - } - - boolean zeroSensiValue = false; - if (!(predefFlowValue && predefSensiValue)) { + if (!(functionPredefinedResults.isPresent() && sensitivityValuePredefinedResult.isPresent())) { for (ComputedContingencyElement contingencyElement : contingencyElements) { double contingencySensitivity = p1.calculateSensi(contingenciesStates, contingencyElement.getContingencyIndex()); - if (!predefFlowValue) { - flowValue += contingencyElement.getAlphaForFunctionReference() * contingencySensitivity; - } - if (!predefSensiValue) { - sensiValue += contingencyElement.getAlphaForSensitivityValue() * contingencySensitivity; + if (functionPredefinedResults.isEmpty()) { + functionValue += contingencyElement.getAlphaForFunctionReference() * contingencySensitivity; } - if (contingencyElement.getElement().getId().equals(factor.getVariableId())) { - // the equipment responsible for the variable is indeed in contingency, the sensitivity value equals zero. - // No assumption about the reference flow on the monitored branch. - zeroSensiValue = true; + if (sensitivityValuePredefinedResult.isEmpty()) { + sensitivityValue += contingencyElement.getAlphaForSensitivityValue() * contingencySensitivity; } } } - resultWriter.writeSensitivityValue(factor.getIndex(), contingency != null ? contingency.getIndex() : -1, unscaleSensitivity(factor, zeroSensiValue ? 0d : sensiValue), unscaleFunction(factor, flowValue)); + resultWriter.writeSensitivityValue(factor.getIndex(), contingency != null ? contingency.getIndex() : -1, unscaleSensitivity(factor, sensitivityValue), unscaleFunction(factor, functionValue)); } /** @@ -390,7 +331,8 @@ private DenseMatrix calculateFactorStates(LfNetwork lfNetwork, */ protected void calculateSensitivityValues(List> lfFactors, DenseMatrix factorStates, DenseMatrix contingenciesStates, DenseMatrix flowStates, Collection contingencyElements, - PropagatedContingency contingency, SensitivityResultWriter resultWriter) { + PropagatedContingency contingency, SensitivityResultWriter resultWriter, Set disabledBuses, + Set disabledBranches) { if (lfFactors.isEmpty()) { return; } @@ -398,7 +340,7 @@ protected void calculateSensitivityValues(List factor.getStatus() == LfSensitivityFactor.Status.VALID_ONLY_FOR_FUNCTION) - .forEach(factor -> createBranchSensitivityValue(factor, contingenciesStates, contingencyElements, contingency, resultWriter)); + .forEach(factor -> createBranchSensitivityValue(factor, contingenciesStates, contingencyElements, contingency, resultWriter, disabledBuses, disabledBranches)); Map, List>> factorsByGroup = lfFactors.stream() .filter(factor -> factor.getStatus() == LfSensitivityFactor.Status.VALID) @@ -408,7 +350,7 @@ protected void calculateSensitivityValues(List> factorsForThisGroup = e.getValue(); setAlphas(contingencyElements, factorStates, contingenciesStates, factorGroup.getIndex(), ComputedContingencyElement::setAlphaForSensitivityValue); for (LfSensitivityFactor factor : factorsForThisGroup) { - createBranchSensitivityValue(factor, contingenciesStates, contingencyElements, contingency, resultWriter); + createBranchSensitivityValue(factor, contingenciesStates, contingencyElements, contingency, resultWriter, disabledBuses, disabledBranches); } } } @@ -640,11 +582,11 @@ public void calculateContingencySensitivityValues(PropagatedContingency continge DenseMatrix flowStates, Collection contingencyElements, SensitivityResultWriter resultWriter, LfNetwork lfNetwork, DcLoadFlowParameters lfParameters, OpenLoadFlowParameters lfParametersExt, JacobianMatrix j, EquationSystem equationSystem, SensitivityFactorHolder factorHolder, List participatingElements, - Collection disabledBuses, Collection disabledBranches, Reporter reporter) { + Set disabledBuses, Set disabledBranches, Reporter reporter) { List> factors = factorHolder.getFactorsForContingency(contingency.getContingency().getId()); if (contingency.getGeneratorIdsToLose().isEmpty() && contingency.getLoadIdsToShift().isEmpty()) { calculateSensitivityValues(factors, factorStates, contingenciesStates, flowStates, contingencyElements, - contingency, resultWriter); + contingency, resultWriter, disabledBuses, disabledBranches); // write contingency status resultWriter.writeContingencyStatus(contingency.getIndex(), SensitivityAnalysisResult.Status.SUCCESS); } else { @@ -690,7 +632,8 @@ public void calculateContingencySensitivityValues(PropagatedContingency continge DenseMatrix newFlowStates = calculateActivePowerFlows(lfNetwork, lfParameters, equationSystem, j, factors, newParticipatingElements, disabledBuses, disabledBranches, reporter); - calculateSensitivityValues(factors, newFactorStates, contingenciesStates, newFlowStates, contingencyElements, contingency, resultWriter); + calculateSensitivityValues(factors, newFactorStates, contingenciesStates, newFlowStates, contingencyElements, + contingency, resultWriter, disabledBuses, disabledBranches); networkState.restore(); if (participatingElementsChanged || rhsChanged) { @@ -704,7 +647,7 @@ private void calculateSensitivityValuesForContingencyList(LfNetwork lfNetwork, O SensitivityFactorGroupList factorGroups, JacobianMatrix j, DenseMatrix factorState, DenseMatrix contingenciesStates, DenseMatrix flowStates, Collection contingencies, Map contingencyElementByBranch, Set disabledBuses, List participatingElements, Set elementsToReconnect, - SensitivityResultWriter resultWriter, Reporter reporter) { + SensitivityResultWriter resultWriter, Reporter reporter, Set partialDisabledBranches) { DenseMatrix modifiedFlowStates = flowStates; PhaseTapChangerContingenciesIndexing phaseTapChangerContingenciesIndexing = new PhaseTapChangerContingenciesIndexing(contingencies, contingencyElementByBranch, elementsToReconnect); @@ -717,9 +660,12 @@ private void calculateSensitivityValuesForContingencyList(LfNetwork lfNetwork, O .map(contingencyElementByBranch::get) .collect(Collectors.toList()); + Set disabledBranches = contingency.getBranchIdsToOpen().stream().map(lfNetwork::getBranchById).collect(Collectors.toSet()); + disabledBranches.addAll(partialDisabledBranches); + calculateContingencySensitivityValues(contingency, factorGroups, factorState, contingenciesStates, modifiedFlowStates, contingencyElements, resultWriter, lfNetwork, dcLoadFlowParameters, lfParametersExt, j, equationSystem, validFactorHolder, participatingElements, - disabledBuses, Collections.emptyList(), reporter); + disabledBuses, disabledBranches, reporter); } // then we compute the ones involving the loss of a phase tap changer (because we need to recompute the load flows) @@ -739,9 +685,12 @@ private void calculateSensitivityValuesForContingencyList(LfNetwork lfNetwork, O .map(contingencyElementByBranch::get) .collect(Collectors.toList()); + Set disabledBranches = contingency.getBranchIdsToOpen().stream().map(lfNetwork::getBranchById).collect(Collectors.toSet()); + disabledBranches.addAll(partialDisabledBranches); + calculateContingencySensitivityValues(contingency, factorGroups, factorState, contingenciesStates, modifiedFlowStates, contingencyElements, resultWriter, lfNetwork, dcLoadFlowParameters, lfParametersExt, j, equationSystem, validFactorHolder, participatingElements, - disabledBuses, disabledPhaseTapChangers, reporter); + disabledBuses, disabledBranches, reporter); } } } @@ -762,16 +711,8 @@ private void processContingenciesBreakingConnectivity(ConnectivityAnalysisResult List contingenciesIds = connectivityAnalysisResult.getContingencies().stream().map(c -> c.getContingency().getId()).collect(Collectors.toList()); List> lfFactorsForContingencies = validFactorHolder.getFactorsForContingencies(contingenciesIds); - // we need to reset predefined values for factor that need to be calculated for this set of contingency - // predefined may have be set by a previous set of contingency with loss of connectivity - // note that if a factor changes its status after contingency, we rely on predefined results only, and we - // will output a factor that becomes ZERO or SKIP through its predefined results. - lfFactorsForContingencies.forEach(factor -> factor.setSensitivityValuePredefinedResult(null)); - lfFactorsForContingencies.forEach(factor -> factor.setFunctionPredefinedResult(null)); - connectivityAnalysisResult.setSensitivityValuePredefinedResults(); - connectivityAnalysisResult.setFunctionPredefinedResults(); - Set disabledBuses = connectivityAnalysisResult.getDisabledBuses(); + Set partialDisabledBranches = connectivityAnalysisResult.getPartialDisabledBranches(); // null and unused if slack bus is not distributed List participatingElementsForThisConnectivity = participatingElements; @@ -800,9 +741,9 @@ private void processContingenciesBreakingConnectivity(ConnectivityAnalysisResult } calculateSensitivityValuesForContingencyList(lfNetwork, lfParametersExt, dcLoadFlowParameters, equationSystem, - validFactorHolder, factorGroups, j, factorStateForThisConnectivity, contingenciesStates, - modifiedFlowStates, connectivityAnalysisResult.getContingencies(), contingencyElementByBranch, disabledBuses, - participatingElementsForThisConnectivity, connectivityAnalysisResult.getElementsToReconnect(), resultWriter, reporter); + validFactorHolder, factorGroups, j, factorStateForThisConnectivity, contingenciesStates, modifiedFlowStates, + connectivityAnalysisResult.getContingencies(), contingencyElementByBranch, disabledBuses, participatingElementsForThisConnectivity, + connectivityAnalysisResult.getElementsToReconnect(), resultWriter, reporter, partialDisabledBranches); if (rhsChanged) { setBaseCaseSensitivityValues(factorGroups, factorsStates); // we modified the rhs, we need to restore previous state @@ -926,7 +867,7 @@ public void analyse(Network network, List contingencies, // calculate sensitivity values for pre-contingency network calculateSensitivityValues(validFactorHolder.getFactorsForBaseNetwork(), factorsStates, null, flowStates, - Collections.emptyList(), null, resultWriter); + Collections.emptySet(), null, resultWriter, Collections.emptySet(), Collections.emptySet()); // compute states with +1 -1 to model the contingencies DenseMatrix contingenciesStates = calculateContingenciesStates(lfNetwork, equationSystem, contingencyElementByBranch, j); @@ -959,7 +900,7 @@ public void analyse(Network network, List contingencies, // process contingencies with no connectivity break calculateSensitivityValuesForContingencyList(lfNetwork, lfParametersExt, dcLoadFlowParameters, equationSystem, validFactorHolder, factorGroups, j, factorsStates, contingenciesStates, flowStates, nonBreakingConnectivityContingencies, contingencyElementByBranch, - Collections.emptySet(), participatingElements, Collections.emptySet(), resultWriter, reporter); + Collections.emptySet(), participatingElements, Collections.emptySet(), resultWriter, reporter, Collections.emptySet()); LOGGER.info("Processing contingencies with connectivity break"); diff --git a/src/test/java/com/powsybl/openloadflow/sensi/ac/AcSensitivityAnalysisContingenciesTest.java b/src/test/java/com/powsybl/openloadflow/sensi/ac/AcSensitivityAnalysisContingenciesTest.java index 058cdbef00..5fbee8f393 100644 --- a/src/test/java/com/powsybl/openloadflow/sensi/ac/AcSensitivityAnalysisContingenciesTest.java +++ b/src/test/java/com/powsybl/openloadflow/sensi/ac/AcSensitivityAnalysisContingenciesTest.java @@ -441,10 +441,10 @@ void testGlskRescale() { assertEquals(-0.5d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l12"), LoadFlowAssert.DELTA_POWER); assertEquals(0.5d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l23"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l13"), LoadFlowAssert.DELTA_POWER); - assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "glsk", "l34"), LoadFlowAssert.DELTA_POWER); - assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "glsk", "l45"), LoadFlowAssert.DELTA_POWER); - assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "glsk", "l46"), LoadFlowAssert.DELTA_POWER); - assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "glsk", "l56"), LoadFlowAssert.DELTA_POWER); + assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l34"), LoadFlowAssert.DELTA_POWER); + assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l45"), LoadFlowAssert.DELTA_POWER); + assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l46"), LoadFlowAssert.DELTA_POWER); + assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l56"), LoadFlowAssert.DELTA_POWER); } @Test @@ -470,10 +470,10 @@ void testGlskRescaleAdditionalFactor() { assertEquals(-0.5d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l12"), LoadFlowAssert.DELTA_POWER); assertEquals(0.5d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l23"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l13"), LoadFlowAssert.DELTA_POWER); - assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "glsk", "l34"), LoadFlowAssert.DELTA_POWER); - assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "glsk", "l45"), LoadFlowAssert.DELTA_POWER); - assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "glsk", "l46"), LoadFlowAssert.DELTA_POWER); - assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "glsk", "l56"), LoadFlowAssert.DELTA_POWER); + assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l34"), LoadFlowAssert.DELTA_POWER); + assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l45"), LoadFlowAssert.DELTA_POWER); + assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l46"), LoadFlowAssert.DELTA_POWER); + assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l56"), LoadFlowAssert.DELTA_POWER); } @Test @@ -1125,4 +1125,63 @@ void testMaxIterationReachedAfterContingency() { SensitivityAnalysisResult result = sensiRunner.run(network, factors, contingencies, Collections.emptyList(), parameters); assertEquals(SensitivityAnalysisResult.Status.FAILURE, result.getContingencyStatus("NHV1_NHV2_2")); } + + @Test + void testPredefinedResults() { + // Load and generator in contingency + Network network = FourBusNetworkFactory.create(); + network.getGeneratorStream().forEach(gen -> gen.setMaxP(2 * gen.getMaxP())); + SensitivityAnalysisParameters sensiParameters = createParameters(false, "b1_vl_0", true); + List factors = List.of(createBranchFlowPerInjectionIncrease("l14", "g1"), + createBranchFlowPerInjectionIncrease("l14", "d2")); + List contingencies = List.of(new Contingency("g1", new GeneratorContingency("g1")), new Contingency("d2", new LoadContingency("d2"))); + SensitivityAnalysisResult result = sensiRunner.run(network, factors, contingencies, Collections.emptyList(), sensiParameters); + assertEquals(0, result.getBranchFlow1SensitivityValue("g1", "g1", "l14"), LoadFlowAssert.DELTA_POWER); + assertEquals(0, result.getBranchFlow1SensitivityValue("d2", "d2", "l14"), LoadFlowAssert.DELTA_POWER); + } + + @Test + void testPredefinedResults2() { + // LCC line in contingency + Network network = HvdcNetworkFactory.createNetworkWithGenerators(); + network.getGeneratorStream().forEach(gen -> gen.setMaxP(3 * gen.getMaxP())); + SensitivityAnalysisParameters sensiParameters = createParameters(false, "b1_vl_0", true); + sensiParameters.getLoadFlowParameters().getExtension(OpenLoadFlowParameters.class).setSlackBusPMaxMismatch(0.001); + List factors = SensitivityFactor.createMatrix(SensitivityFunctionType.BRANCH_ACTIVE_POWER_1, List.of("l12"), + SensitivityVariableType.HVDC_LINE_ACTIVE_POWER, List.of("hvdc34"), + false, ContingencyContext.all()); + List contingencies = List.of(new Contingency("hvdc34", new HvdcLineContingency("hvdc34"))); + SensitivityAnalysisResult result = sensiRunner.run(network, factors, contingencies, Collections.emptyList(), sensiParameters); + assertEquals(0, result.getBranchFlow1SensitivityValue("hvdc34", "hvdc34", "l12"), LoadFlowAssert.DELTA_POWER); + // VSC line in contingency + Network network2 = HvdcNetworkFactory.createNetworkWithGenerators2(); + network.getGeneratorStream().forEach(gen -> gen.setMaxP(2 * gen.getMaxP())); + SensitivityAnalysisResult result2 = sensiRunner.run(network2, factors, contingencies, Collections.emptyList(), sensiParameters); + assertEquals(0, result2.getBranchFlow1SensitivityValue("hvdc34", "hvdc34", "l12"), LoadFlowAssert.DELTA_POWER); + } + + @Test + void testPredefinedResults3() { + Network network = ConnectedComponentNetworkFactory.createTwoComponentWithGeneratorOnOneSide(); + SensitivityAnalysisParameters sensiParameters = createParameters(false, "b1_vl_0", true); + sensiParameters.getLoadFlowParameters().setBalanceType(LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_P_MAX); + network.getGeneratorStream().forEach(gen -> gen.setMaxP(2 * gen.getMaxP())); + List contingencies = List.of(new Contingency("g2", new GeneratorContingency("g2"))); + List factors = List.of(createBusVoltagePerTargetV("b4", "g2", "g2")); + SensitivityAnalysisResult result = sensiRunner.run(network, factors, contingencies, Collections.emptyList(), sensiParameters); + assertEquals(0, result.getBusVoltageSensitivityValue("g2", "g2", "b4"), LoadFlowAssert.DELTA_V); + } + + @Test + void testPredefinedResults4() { + SensitivityAnalysisParameters sensiParameters = createParameters(false, "b1_vl_0", true); + sensiParameters.getLoadFlowParameters().setBalanceType(LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_P_MAX); + Network network = FourBusNetworkFactory.createWithPhaseTapChangerAndGeneratorAtBus2(); + List factors = List.of(createBranchFlowPerPSTAngle("l12", "l23", "l23"), + createBranchFlowPerPSTAngle("l23", "l23", "l23")); + List contingencies = Collections.singletonList(new Contingency("l23", new BranchContingency("l23"))); + SensitivityAnalysisResult result = sensiRunner.run(network, factors, contingencies, Collections.emptyList(), sensiParameters); + assertEquals(0, result.getBranchFlow1SensitivityValue("l23", "l23", "l12"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l23", "l23", "l23"), LoadFlowAssert.DELTA_POWER); + } } diff --git a/src/test/java/com/powsybl/openloadflow/sensi/dc/DcSensitivityAnalysisContingenciesTest.java b/src/test/java/com/powsybl/openloadflow/sensi/dc/DcSensitivityAnalysisContingenciesTest.java index 0880fc780b..937e5a682b 100644 --- a/src/test/java/com/powsybl/openloadflow/sensi/dc/DcSensitivityAnalysisContingenciesTest.java +++ b/src/test/java/com/powsybl/openloadflow/sensi/dc/DcSensitivityAnalysisContingenciesTest.java @@ -244,7 +244,7 @@ void testConnectivityLossOnSingleLine() { assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "g6", "l12"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "g6", "l23"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "g6", "l13"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "g6", "l34"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "g6", "l34"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "g6", "l45"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "g6", "l46"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "g6", "l56"), LoadFlowAssert.DELTA_POWER); @@ -280,7 +280,7 @@ void testConnectivityLossOnSingleLineWithDistributedSlack() { assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "g6", "l12"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "g6", "l23"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "g6", "l13"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "g6", "l34"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "g6", "l34"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "g6", "l45"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "g6", "l46"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "g6", "l56"), LoadFlowAssert.DELTA_POWER); @@ -317,7 +317,7 @@ void slackRedistributionInAdditionalFactors() { assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "g6", "l12"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "g6", "l23"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "g6", "l13"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "g6", "l34"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "g6", "l34"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "g6", "l45"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "g6", "l46"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "g6", "l56"), LoadFlowAssert.DELTA_POWER); @@ -356,12 +356,12 @@ void testConnectivityLossOnTwoComponentAtATime() { assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l48", "g6", "l12"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l48", "g6", "l23"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l48", "g6", "l13"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l48", "g6", "l34"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l48", "g6", "l34"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l48", "g6", "l45"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l48", "g6", "l56"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l48", "g6", "l57"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l48", "g6", "l67"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l48", "g6", "l48"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l48", "g6", "l48"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l48", "g6", "l89"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l48", "g6", "l810"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l48", "g6", "l910"), LoadFlowAssert.DELTA_POWER); @@ -369,13 +369,13 @@ void testConnectivityLossOnTwoComponentAtATime() { assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l48", "g10", "l12"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l48", "g10", "l23"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l48", "g10", "l13"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l48", "g10", "l34"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l48", "g10", "l34"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l48", "g10", "l45"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l48", "g10", "l56"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l48", "g10", "l57"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l48", "g10", "l67"), LoadFlowAssert.DELTA_POWER); // FIXME: Next line is not working with EvenShiloach, it feels like the connectivity check is wrong (in the predefinedResults definition) - assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l48", "g10", "l48"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l48", "g10", "l48"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l48", "g10", "l89"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l48", "g10", "l810"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l48", "g10", "l910"), LoadFlowAssert.DELTA_POWER); @@ -410,8 +410,8 @@ void testLosingTheSameConnectivityTwice() { assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l45", "g6", "l12"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l45", "g6", "l23"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l45", "g6", "l13"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l45", "g6", "l34"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l45", "g6", "l45"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l45", "g6", "l34"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l45", "g6", "l45"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l45", "g6", "l56"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l45", "g6", "l57"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l45", "g6", "l67"), LoadFlowAssert.DELTA_POWER); @@ -448,7 +448,7 @@ void testLosingConnectivityOnTwoBranches() { assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l47", "g6", "l12"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l47", "g6", "l13"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l47", "g6", "l23"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l47", "g6", "l34"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l47", "g6", "l34"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l47", "g6", "l45"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l47", "g6", "l46"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l47", "g6", "l56"), LoadFlowAssert.DELTA_POWER); @@ -459,7 +459,7 @@ void testLosingConnectivityOnTwoBranches() { assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l47", "g9", "l12"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l47", "g9", "l13"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l47", "g9", "l23"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l34+l47", "g9", "l34"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l47", "g9", "l34"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l47", "g9", "l45"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l47", "g9", "l46"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34+l47", "g9", "l56"), LoadFlowAssert.DELTA_POWER); @@ -543,7 +543,7 @@ void testPhaseShifterConnectivityLoss() { assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "l56", "l12"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "l56", "l13"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "l56", "l23"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "l56", "l34"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "l56", "l34"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "l56", "l45"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "l56", "l46"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "l56", "l56"), LoadFlowAssert.DELTA_POWER); @@ -570,7 +570,7 @@ void testContingencyOnTransformer() { assertEquals(0d, result.getBranchFlow1SensitivityValue("l56", "l56", "l34"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l56", "l56", "l45"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l56", "l56", "l46"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l56", "l56", "l56"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l56", "l56", "l56"), LoadFlowAssert.DELTA_POWER); } @Test @@ -861,8 +861,8 @@ void testContingencyMultipleLinesBreaksOneContingency() { assertEquals(0d, result.getBranchFlow1SensitivityValue("l24+l35", "g6", "l12"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l24+l35", "g6", "l23"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l24+l35", "g6", "l13"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l24+l35", "g6", "l24"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l24+l35", "g6", "l35"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l24+l35", "g6", "l24"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l24+l35", "g6", "l35"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l24+l35", "g6", "l45"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l24+l35", "g6", "l46"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l24+l35", "g6", "l56"), LoadFlowAssert.DELTA_POWER); @@ -932,11 +932,11 @@ void testAsymetricLossOnMultipleComponents() { assertEquals(0d, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g6", "l12"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g6", "l13"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g6", "l14"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g6", "l18"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g6", "l14"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g6", "l18"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g6", "l23"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g6", "l27"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g6", "l39"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g6", "l27"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g6", "l39"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g6", "l45"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g6", "l46"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g6", "l56"), LoadFlowAssert.DELTA_POWER); @@ -946,11 +946,11 @@ void testAsymetricLossOnMultipleComponents() { assertEquals(0d, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g9", "l12"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g9", "l13"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g9", "l14"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g9", "l18"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g9", "l14"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g9", "l18"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g9", "l23"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g9", "l27"), LoadFlowAssert.DELTA_POWER); - assertEquals(0d, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g9", "l39"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g9", "l27"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g9", "l39"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g9", "l45"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g9", "l46"), LoadFlowAssert.DELTA_POWER); assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l27+l18+l39+l14", "g9", "l56"), LoadFlowAssert.DELTA_POWER); @@ -982,9 +982,9 @@ void testRemainingGlskFactors() { assertEquals(-1d / 18d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l23"), LoadFlowAssert.DELTA_POWER); assertEquals(-19d / 36d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l13"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l34"), LoadFlowAssert.DELTA_POWER); - assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "glsk", "l45"), LoadFlowAssert.DELTA_POWER); - assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "glsk", "l46"), LoadFlowAssert.DELTA_POWER); - assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "glsk", "l56"), LoadFlowAssert.DELTA_POWER); + assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l45"), LoadFlowAssert.DELTA_POWER); + assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l46"), LoadFlowAssert.DELTA_POWER); + assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l56"), LoadFlowAssert.DELTA_POWER); } @Test @@ -1047,9 +1047,9 @@ void testRemainingGlskFactorsAdditionalFactors() { assertEquals(-1d / 18d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l23"), LoadFlowAssert.DELTA_POWER); assertEquals(-19d / 36d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l13"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l34"), LoadFlowAssert.DELTA_POWER); - assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "glsk", "l45"), LoadFlowAssert.DELTA_POWER); - assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "glsk", "l46"), LoadFlowAssert.DELTA_POWER); - assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l34", "glsk", "l56"), LoadFlowAssert.DELTA_POWER); + assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l45"), LoadFlowAssert.DELTA_POWER); + assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l46"), LoadFlowAssert.DELTA_POWER); + assertEquals(0d, result.getBranchFlow1SensitivityValue("l34", "glsk", "l56"), LoadFlowAssert.DELTA_POWER); } @Test @@ -1088,9 +1088,9 @@ void testHvdcSensiRescale() { assertEquals(loadFlowDiff.get("l13"), result.getBranchFlow1SensitivityValue("l25", "hvdc34", "l13"), LoadFlowAssert.DELTA_POWER); assertEquals(loadFlowDiff.get("l23"), result.getBranchFlow1SensitivityValue("l25", "hvdc34", "l23"), LoadFlowAssert.DELTA_POWER); assertEquals(0d, result.getBranchFlow1SensitivityValue("l25", "hvdc34", "l25"), LoadFlowAssert.DELTA_POWER); - assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l25", "hvdc34", "l45"), LoadFlowAssert.DELTA_POWER); - assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l25", "hvdc34", "l46"), LoadFlowAssert.DELTA_POWER); - assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l25", "hvdc34", "l56"), LoadFlowAssert.DELTA_POWER); + assertEquals(0d, result.getBranchFlow1SensitivityValue("l25", "hvdc34", "l45"), LoadFlowAssert.DELTA_POWER); + assertEquals(0d, result.getBranchFlow1SensitivityValue("l25", "hvdc34", "l46"), LoadFlowAssert.DELTA_POWER); + assertEquals(0d, result.getBranchFlow1SensitivityValue("l25", "hvdc34", "l56"), LoadFlowAssert.DELTA_POWER); } @Test @@ -1208,7 +1208,7 @@ void testContingencyAllLines() { assertEquals(11, result.getValues(contingency1Id).size()); for (Line line : network.getLines()) { - assertEquals(0, result.getBranchFlow1SensitivityValue(contingency1Id, variableId, line.getId()), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue(contingency1Id, variableId, line.getId()), LoadFlowAssert.DELTA_POWER); } } @@ -2201,4 +2201,52 @@ void testFunctionDisconnectedBranchBothSidesWithContingency() { SensitivityAnalysisResult result = sensiRunner.run(network, factors, contingencies, Collections.emptyList(), sensiParameters); assertEquals(SensitivityAnalysisResult.Status.SUCCESS, result.getContingencyStatus("C")); } + + @Test + void testPredefinedResults() { + // Load and generator in contingency + Network network = FourBusNetworkFactory.create(); + network.getGeneratorStream().forEach(gen -> gen.setMaxP(2 * gen.getMaxP())); + SensitivityAnalysisParameters sensiParameters = createParameters(true, "b1_vl_0", true); + List factors = List.of(createBranchFlowPerInjectionIncrease("l14", "g1"), + createBranchFlowPerInjectionIncrease("l14", "d2")); + List contingencies = List.of(new Contingency("g1", new GeneratorContingency("g1")), new Contingency("d2", new LoadContingency("d2"))); + SensitivityAnalysisResult result = sensiRunner.run(network, factors, contingencies, Collections.emptyList(), sensiParameters); + assertEquals(0, result.getBranchFlow1SensitivityValue("g1", "g1", "l14"), LoadFlowAssert.DELTA_POWER); + assertEquals(0, result.getBranchFlow1SensitivityValue("d2", "d2", "l14"), LoadFlowAssert.DELTA_POWER); + } + + @Test + void testPredefinedResults2() { + // LCC line in contingency + Network network = HvdcNetworkFactory.createNetworkWithGenerators(); + network.getGeneratorStream().forEach(gen -> gen.setMaxP(3 * gen.getMaxP())); + SensitivityAnalysisParameters sensiParameters = createParameters(true, "b1_vl_0", true); + sensiParameters.getLoadFlowParameters().getExtension(OpenLoadFlowParameters.class).setSlackBusPMaxMismatch(0.001); + List factors = SensitivityFactor.createMatrix(SensitivityFunctionType.BRANCH_ACTIVE_POWER_1, List.of("l25"), + SensitivityVariableType.HVDC_LINE_ACTIVE_POWER, List.of("hvdc34"), + false, ContingencyContext.all()); + List contingencies = List.of(new Contingency("hvdc34", new HvdcLineContingency("hvdc34"))); + SensitivityAnalysisResult result = sensiRunner.run(network, factors, contingencies, Collections.emptyList(), sensiParameters); + assertEquals(0.9889, result.getBranchFlow1SensitivityValue("hvdc34", "l25"), LoadFlowAssert.DELTA_POWER); + assertEquals(0, result.getBranchFlow1SensitivityValue("hvdc34", "hvdc34", "l25"), LoadFlowAssert.DELTA_POWER); + // VSC line in contingency + Network network2 = HvdcNetworkFactory.createNetworkWithGenerators2(); + network.getGeneratorStream().forEach(gen -> gen.setMaxP(2 * gen.getMaxP())); + SensitivityAnalysisResult result2 = sensiRunner.run(network2, factors, contingencies, Collections.emptyList(), sensiParameters); + assertEquals(0, result2.getBranchFlow1SensitivityValue("hvdc34", "hvdc34", "l25"), LoadFlowAssert.DELTA_POWER); + } + + @Test + void testPredefinedResults3() { + SensitivityAnalysisParameters sensiParameters = createParameters(true, "b1_vl_0", true); + sensiParameters.getLoadFlowParameters().setBalanceType(LoadFlowParameters.BalanceType.PROPORTIONAL_TO_GENERATION_P_MAX); + Network network = FourBusNetworkFactory.createWithPhaseTapChangerAndGeneratorAtBus2(); + List factors = List.of(createBranchFlowPerPSTAngle("l12", "l23", "l23"), + createBranchFlowPerPSTAngle("l23", "l23", "l23")); + List contingencies = Collections.singletonList(new Contingency("l23", new BranchContingency("l23"))); + SensitivityAnalysisResult result = sensiRunner.run(network, factors, contingencies, Collections.emptyList(), sensiParameters); + assertEquals(0, result.getBranchFlow1SensitivityValue("l23", "l23", "l12"), LoadFlowAssert.DELTA_POWER); + assertEquals(Double.NaN, result.getBranchFlow1SensitivityValue("l23", "l23", "l23"), LoadFlowAssert.DELTA_POWER); + } }