From 40146949cba36c5c72b34acb179ea0127b0e970c Mon Sep 17 00:00:00 2001 From: Hadrien Date: Fri, 3 Jun 2022 13:47:36 +0200 Subject: [PATCH 01/15] Unit test and beginning Signed-off-by: Hadrien --- .../openloadflow/sa/DcSecurityAnalysis.java | 13 ++++++++ .../sa/OpenSecurityAnalysisTest.java | 32 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java index dd39206686..06d06762c7 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java @@ -71,6 +71,7 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete preContingencyBranchResults.put(branchId, new BranchResult(branchId, sensValue.getFunctionReference(), Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN)); detector.checkActivePower(branch, Branch.Side.ONE, Math.abs(sensValue.getFunctionReference()), violation -> preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); + checkDcCurrent(branch, Math.abs(sensValue.getFunctionReference())); } LimitViolationsResult preContingencyResult = new LimitViolationsResult(true, @@ -110,4 +111,16 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete return new SecurityAnalysisReport(new SecurityAnalysisResult(preContingencyResult, postContingencyResults, new ArrayList<>(preContingencyBranchResults.values()), Collections.emptyList(), Collections.emptyList())); } + + private void checkDcCurrent(Branch branch, double activePower) { + // Check side 1 + // TODO: get cosphi from parameters + double branchCurrent = currentFromAdnActivePower(activePower, branch.getTerminal1().getVoltageLevel().getNominalV(), 0.4); + + // Check side 2 + } + + public static double currentFromAdnActivePower(double activePower, double dcVoltage, double cosPhi) { + return 1000 * activePower / (Math.sqrt(3) * cosPhi * dcVoltage); + } } diff --git a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java index 4d511377ef..34b2452c58 100644 --- a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java +++ b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java @@ -1519,4 +1519,36 @@ void testSwitchLoopIssue() { assertEquals(-599.882, postContingencyResult.getBranchResult("L2").getP1(), LoadFlowAssert.DELTA_POWER); assertEquals(608.214, postContingencyResult.getBranchResult("L2").getP2(), LoadFlowAssert.DELTA_POWER); } + + @Test + void testDcCurrentLimitViolations() { + Network fourBusNetwork = FourBusNetworkFactory.create(); + SecurityAnalysisParameters securityAnalysisParameters = new SecurityAnalysisParameters(); + LoadFlowParameters lfParameters = new LoadFlowParameters() + .setDc(true); + setSlackBusId(lfParameters, "b1_vl_0"); + securityAnalysisParameters.setLoadFlowParameters(lfParameters); + + List contingencies = allBranches(fourBusNetwork); + + fourBusNetwork.getLine("l14").newCurrentLimits1().setPermanentLimit(0.1).add(); + fourBusNetwork.getLine("l12").newCurrentLimits1().setPermanentLimit(0.2).add(); + fourBusNetwork.getLine("l23").newCurrentLimits2().setPermanentLimit(0.25).add(); + fourBusNetwork.getLine("l34").newCurrentLimits1().setPermanentLimit(0.15).add(); + fourBusNetwork.getLine("l13").newCurrentLimits2().setPermanentLimit(0.1).add(); + + List monitors = List.of(new StateMonitor(ContingencyContext.all(), Set.of("l14", "l12", "l23", "l34", "l13"), Collections.emptySet(), Collections.emptySet())); + + SecurityAnalysisResult result = runSecurityAnalysis(fourBusNetwork, contingencies, monitors, securityAnalysisParameters); + + assertTrue(result.getPreContingencyResult().getLimitViolationsResult().isComputationOk()); + assertEquals(5, result.getPreContingencyResult().getLimitViolationsResult().getLimitViolations().size()); + assertEquals(5, result.getPostContingencyResults().size()); + assertEquals(2, result.getPostContingencyResults().get(0).getLimitViolationsResult().getLimitViolations().size()); + assertEquals(2, result.getPostContingencyResults().get(1).getLimitViolationsResult().getLimitViolations().size()); + assertEquals(4, result.getPostContingencyResults().get(2).getLimitViolationsResult().getLimitViolations().size()); + assertEquals(4, result.getPostContingencyResults().get(3).getLimitViolationsResult().getLimitViolations().size()); + assertEquals(4, result.getPostContingencyResults().get(4).getLimitViolationsResult().getLimitViolations().size()); + } + } From ce774dec5d1d951225ba56e39b3e1beb32d3cf05 Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Fri, 3 Jun 2022 15:34:18 +0200 Subject: [PATCH 02/15] Equation system index optimization (#435) Signed-off-by: Geoffroy Jamgotchian --- .../ac/VoltageMagnitudeInitializer.java | 2 +- .../openloadflow/ac/nr/NewtonRaphson.java | 6 +- .../openloadflow/dc/DcLoadFlowEngine.java | 6 +- .../equations/EquationSystem.java | 165 ++------------- .../equations/EquationSystemIndex.java | 193 ++++++++++++++++++ .../EquationSystemIndexListener.java | 33 +++ .../equations/JacobianMatrix.java | 128 ++++++------ .../openloadflow/equations/TargetVector.java | 25 ++- .../sensi/AbstractSensitivityAnalysis.java | 2 +- .../sensi/AcSensitivityAnalysis.java | 2 +- .../sensi/DcSensitivityAnalysis.java | 2 +- .../ac/NonImpedantBranchDisablingTest.java | 4 +- .../equations/EquationSystemIndexTest.java | 193 ++++++++++++++++++ .../equations/EquationSystemTest.java | 8 +- .../sa/OpenSecurityAnalysisTest.java | 8 +- 15 files changed, 537 insertions(+), 240 deletions(-) create mode 100644 src/main/java/com/powsybl/openloadflow/equations/EquationSystemIndex.java create mode 100644 src/main/java/com/powsybl/openloadflow/equations/EquationSystemIndexListener.java create mode 100644 src/test/java/com/powsybl/openloadflow/equations/EquationSystemIndexTest.java diff --git a/src/main/java/com/powsybl/openloadflow/ac/VoltageMagnitudeInitializer.java b/src/main/java/com/powsybl/openloadflow/ac/VoltageMagnitudeInitializer.java index d4c3c54ace..9310c597ca 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/VoltageMagnitudeInitializer.java +++ b/src/main/java/com/powsybl/openloadflow/ac/VoltageMagnitudeInitializer.java @@ -212,7 +212,7 @@ public void prepare(LfNetwork network) { j.solveTransposed(targets); - for (Variable variable : equationSystem.getSortedVariablesToFind()) { + for (Variable variable : equationSystem.getIndex().getSortedVariablesToFind()) { LfBus bus = network.getBus(variable.getElementNum()); bus.setV(targets[variable.getRow()]); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/nr/NewtonRaphson.java b/src/main/java/com/powsybl/openloadflow/ac/nr/NewtonRaphson.java index c1d0dc2f9a..e17e026734 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/nr/NewtonRaphson.java +++ b/src/main/java/com/powsybl/openloadflow/ac/nr/NewtonRaphson.java @@ -93,8 +93,8 @@ private NewtonRaphsonStatus runIteration(double[] fx) { } public static void initStateVector(LfNetwork network, EquationSystem equationSystem, VoltageInitializer initializer) { - double[] x = new double[equationSystem.getSortedVariablesToFind().size()]; - for (Variable v : equationSystem.getSortedVariablesToFind()) { + double[] x = new double[equationSystem.getIndex().getSortedVariablesToFind().size()]; + for (Variable v : equationSystem.getIndex().getSortedVariablesToFind()) { switch (v.getType()) { case BUS_V: x[v.getRow()] = initializer.getMagnitude(network.getBus(v.getElementNum())); @@ -131,7 +131,7 @@ public static void initStateVector(LfNetwork network, EquationSystem v : equationSystem.getSortedVariablesToFind()) { + for (Variable v : equationSystem.getIndex().getSortedVariablesToFind()) { switch (v.getType()) { case BUS_V: network.getBus(v.getElementNum()).setV(stateVector.get(v.getRow())); diff --git a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java index 08ffc17696..397c6d989e 100644 --- a/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java +++ b/src/main/java/com/powsybl/openloadflow/dc/DcLoadFlowEngine.java @@ -80,8 +80,8 @@ private DcLoadFlowResult run(Reporter reporter, LfNetwork network) { } public static void initStateVector(LfNetwork network, EquationSystem equationSystem, VoltageInitializer initializer) { - double[] x = new double[equationSystem.getSortedVariablesToFind().size()]; - for (Variable v : equationSystem.getSortedVariablesToFind()) { + double[] x = new double[equationSystem.getIndex().getSortedVariablesToFind().size()]; + for (Variable v : equationSystem.getIndex().getSortedVariablesToFind()) { switch (v.getType()) { case BUS_PHI: x[v.getRow()] = Math.toRadians(initializer.getAngle(network.getBus(v.getElementNum()))); @@ -104,7 +104,7 @@ public static void initStateVector(LfNetwork network, EquationSystem equationSystem, double[] x) { // update state variable - for (Variable v : equationSystem.getSortedVariablesToFind()) { + for (Variable v : equationSystem.getIndex().getSortedVariablesToFind()) { switch (v.getType()) { case BUS_PHI: network.getBus(v.getElementNum()).setAngle(Math.toDegrees(x[v.getRow()])); diff --git a/src/main/java/com/powsybl/openloadflow/equations/EquationSystem.java b/src/main/java/com/powsybl/openloadflow/equations/EquationSystem.java index c2e50275c2..f167ff9240 100644 --- a/src/main/java/com/powsybl/openloadflow/equations/EquationSystem.java +++ b/src/main/java/com/powsybl/openloadflow/equations/EquationSystem.java @@ -39,145 +39,14 @@ public class EquationSystem & Quantity, E extends Enum & Qu private final Map, List>> equationTermsByElement = new HashMap<>(); - private class EquationCache implements EquationSystemListener { - - private final NavigableMap, NavigableMap, List>>> sortedEquationsToSolve = new TreeMap<>(); - - private final NavigableMap, Set>> sortedVariablesToFind = new TreeMap<>(); - - private final Set> equationsToRemove = new HashSet<>(); - - private final Set> equationsToAdd = new HashSet<>(); - - private void update() { - if (reIndex()) { - Stopwatch stopwatch = Stopwatch.createStarted(); - - int columnCount = 0; - for (Equation equation : sortedEquationsToSolve.keySet()) { - equation.setColumn(columnCount++); - } - - int rowCount = 0; - for (Variable variable : sortedVariablesToFind.keySet()) { - variable.setRow(rowCount++); - } - - LOGGER.debug("Equation system indexed in {} us", stopwatch.elapsed(TimeUnit.MICROSECONDS)); - } - } - - private boolean reIndex() { - if (equationsToAdd.isEmpty() && equationsToRemove.isEmpty()) { - return false; - } - - // index derivatives per variable then per equation - - // equations to remove - for (Equation equation : equationsToRemove) { - sortedEquationsToSolve.remove(equation); - for (EquationTerm equationTerm : equation.getTerms()) { - for (Variable variable : equationTerm.getVariables()) { - Set> equationsUsingThisVariable = sortedVariablesToFind.get(variable); - if (equationsUsingThisVariable != null) { - equationsUsingThisVariable.remove(equation); - if (equationsUsingThisVariable.isEmpty()) { - sortedVariablesToFind.remove(variable); - } - } - } - } - } - - // equations to add - for (Equation equation : equationsToAdd) { - // do not use equations that would be updated only after NR - if (equation.isActive()) { - // check we have at least one equation term active - boolean atLeastOneTermIsValid = false; - for (EquationTerm equationTerm : equation.getTerms()) { - if (equationTerm.isActive()) { - atLeastOneTermIsValid = true; - for (Variable variable : equationTerm.getVariables()) { - sortedEquationsToSolve.computeIfAbsent(equation, k -> new TreeMap<>()) - .computeIfAbsent(variable, k -> new ArrayList<>()) - .add(equationTerm); - sortedVariablesToFind.computeIfAbsent(variable, k -> new TreeSet<>()) - .add(equation); - } - } - } - if (!atLeastOneTermIsValid) { - throw new IllegalStateException("Equation " + equation + " is active but all of its terms are inactive"); - } - } - } - - equationsToRemove.clear(); - equationsToAdd.clear(); - - return true; - } - - @Override - public void onEquationChange(Equation equation, EquationEventType eventType) { - switch (eventType) { - case EQUATION_REMOVED: - case EQUATION_DEACTIVATED: - if (!sortedEquationsToSolve.isEmpty()) { // not need to remove if not already indexed - equationsToRemove.add(equation); - } - equationsToAdd.remove(equation); - break; - - case EQUATION_CREATED: - case EQUATION_ACTIVATED: - // no need to remove first because activated event means it was not already activated - equationsToAdd.add(equation); - break; - - default: - throw new IllegalStateException("Event type not supported: " + eventType); - } - } - - @Override - public void onEquationTermChange(EquationTerm term, EquationTermEventType eventType) { - switch (eventType) { - case EQUATION_TERM_ADDED: - case EQUATION_TERM_ACTIVATED: - case EQUATION_TERM_DEACTIVATED: - if (!sortedEquationsToSolve.isEmpty()) { // not need to remove if not already indexed - equationsToRemove.add(term.getEquation()); - } - equationsToAdd.add(term.getEquation()); - break; - - default: - throw new IllegalStateException("Event type not supported: " + eventType); - } - } - - private NavigableMap, NavigableMap, List>>> getSortedEquationsToSolve() { - update(); - return sortedEquationsToSolve; - } - - private NavigableSet> getSortedVariablesToFind() { - update(); - return sortedVariablesToFind.navigableKeySet(); - } - } - - private final EquationCache equationCache = new EquationCache(); - private final List> listeners = new ArrayList<>(); private final VariableSet variableSet; private final StateVector stateVector = new StateVector(); + private final EquationSystemIndex index; + public EquationSystem() { this(false); } @@ -189,7 +58,7 @@ public EquationSystem(boolean indexTerms) { public EquationSystem(VariableSet variableSet, boolean indexTerms) { this.variableSet = Objects.requireNonNull(variableSet); this.indexTerms = indexTerms; - addListener(equationCache); + index = new EquationSystemIndex<>(this); } public VariableSet getVariableSet() { @@ -204,6 +73,14 @@ public StateVector getStateVector() { return stateVector; } + public EquationSystemIndex getIndex() { + return index; + } + + public Collection> getEquations() { + return equations.values(); + } + void addEquationTerm(EquationTerm equationTerm) { if (indexTerms) { Objects.requireNonNull(equationTerm); @@ -283,41 +160,33 @@ public void attach(EquationTerm term) { term.setStateVector(stateVector); } - public SortedSet> getSortedVariablesToFind() { - return equationCache.getSortedVariablesToFind(); - } - - public NavigableMap, NavigableMap, List>>> getSortedEquationsToSolve() { - return equationCache.getSortedEquationsToSolve(); - } - public List getRowNames(LfNetwork network) { - return getSortedVariablesToFind().stream() + return index.getSortedVariablesToFind().stream() .map(eq -> network.getBus(eq.getElementNum()).getId() + "/" + eq.getType()) .collect(Collectors.toList()); } public List getColumnNames(LfNetwork network) { - return getSortedEquationsToSolve().navigableKeySet().stream() + return index.getSortedEquationsToSolve().stream() .map(v -> network.getBus(v.getElementNum()).getId() + "/" + v.getType()) .collect(Collectors.toList()); } public double[] createEquationVector() { - double[] fx = new double[equationCache.getSortedEquationsToSolve().size()]; + double[] fx = new double[index.getSortedEquationsToSolve().size()]; updateEquationVector(fx); return fx; } public void updateEquationVector(double[] fx) { - if (fx.length != equationCache.getSortedEquationsToSolve().size()) { + if (fx.length != index.getSortedEquationsToSolve().size()) { throw new IllegalArgumentException("Bad equation vector length: " + fx.length); } Stopwatch stopwatch = Stopwatch.createStarted(); Arrays.fill(fx, 0); - for (Equation equation : equationCache.getSortedEquationsToSolve().keySet()) { + for (Equation equation : index.getSortedEquationsToSolve()) { fx[equation.getColumn()] = equation.eval(); } @@ -380,7 +249,7 @@ public String writeToString() { } public List, Double>> findLargestMismatches(double[] mismatch, int count) { - return getSortedEquationsToSolve().keySet().stream() + return index.getSortedEquationsToSolve().stream() .map(equation -> Pair.of(equation, mismatch[equation.getColumn()])) .filter(e -> Math.abs(e.getValue()) > Math.pow(10, -7)) .sorted(Comparator.comparingDouble((Map.Entry, Double> e) -> Math.abs(e.getValue())).reversed()) diff --git a/src/main/java/com/powsybl/openloadflow/equations/EquationSystemIndex.java b/src/main/java/com/powsybl/openloadflow/equations/EquationSystemIndex.java new file mode 100644 index 0000000000..205d2e2448 --- /dev/null +++ b/src/main/java/com/powsybl/openloadflow/equations/EquationSystemIndex.java @@ -0,0 +1,193 @@ +/** + * Copyright (c) 2022, 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/. + */ +package com.powsybl.openloadflow.equations; + +import org.apache.commons.lang3.mutable.MutableInt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + +/** + * @author Geoffroy Jamgotchian + */ +public class EquationSystemIndex & Quantity, E extends Enum & Quantity> + implements EquationSystemListener { + + private static final Logger LOGGER = LoggerFactory.getLogger(EquationSystemIndex.class); + + private final TreeSet> sortedEquationsToSolve = new TreeSet<>(); + + // variable reference counting in equation terms + private final NavigableMap, MutableInt> sortedVariablesToFindRefCount = new TreeMap<>(); + + private boolean equationsIndexValid = false; + + private boolean variablesIndexValid = false; + + private final List> listeners = new ArrayList<>(); + + public EquationSystemIndex(EquationSystem equationSystem) { + Objects.requireNonNull(equationSystem).addListener(this); + } + + public void addListener(EquationSystemIndexListener listener) { + listeners.add(Objects.requireNonNull(listener)); + } + + public void removeListener(EquationSystemIndexListener listener) { + listeners.remove(Objects.requireNonNull(listener)); + } + + private void notifyEquationChange(Equation equation, EquationSystemIndexListener.ChangeType changeType) { + listeners.forEach(listener -> listener.onEquationChange(equation, changeType)); + } + + private void notifyVariableChange(Variable variable, EquationSystemIndexListener.ChangeType changeType) { + listeners.forEach(listener -> listener.onVariableChange(variable, changeType)); + } + + private void notifyEquationTermChange(EquationTerm term) { + listeners.forEach(listener -> listener.onEquationTermChange(term)); + } + + private void update() { + if (!equationsIndexValid) { + int columnCount = 0; + for (Equation equation : sortedEquationsToSolve) { + equation.setColumn(columnCount++); + } + equationsIndexValid = true; + LOGGER.debug("Equations index updated ({} columns)", columnCount); + } + + if (!variablesIndexValid) { + int rowCount = 0; + for (Variable variable : sortedVariablesToFindRefCount.keySet()) { + variable.setRow(rowCount++); + } + variablesIndexValid = true; + LOGGER.debug("Variables index updated ({} rows)", rowCount); + } + } + + private void addTerm(EquationTerm term) { + notifyEquationTermChange(term); + for (Variable variable : term.getVariables()) { + MutableInt variableRefCount = sortedVariablesToFindRefCount.get(variable); + if (variableRefCount == null) { + variableRefCount = new MutableInt(1); + sortedVariablesToFindRefCount.put(variable, variableRefCount); + variablesIndexValid = false; + notifyVariableChange(variable, EquationSystemIndexListener.ChangeType.ADDED); + } else { + variableRefCount.increment(); + } + } + } + + private void addEquation(Equation equation) { + sortedEquationsToSolve.add(equation); + equationsIndexValid = false; + for (EquationTerm term : equation.getTerms()) { + if (term.isActive()) { + addTerm(term); + } + } + notifyEquationChange(equation, EquationSystemIndexListener.ChangeType.ADDED); + } + + private void removeTerm(EquationTerm term) { + notifyEquationTermChange(term); + for (Variable variable : term.getVariables()) { + MutableInt variableRefCount = sortedVariablesToFindRefCount.get(variable); + if (variableRefCount != null) { + variableRefCount.decrement(); + if (variableRefCount.intValue() == 0) { + variable.setRow(-1); + sortedVariablesToFindRefCount.remove(variable); + variablesIndexValid = false; + notifyVariableChange(variable, EquationSystemIndexListener.ChangeType.REMOVED); + } + } + } + } + + private void removeEquation(Equation equation) { + equation.setColumn(-1); + sortedEquationsToSolve.remove(equation); + equationsIndexValid = false; + for (EquationTerm term : equation.getTerms()) { + if (term.isActive()) { + removeTerm(term); + } + } + notifyEquationChange(equation, EquationSystemIndexListener.ChangeType.REMOVED); + } + + @Override + public void onEquationChange(Equation equation, EquationEventType eventType) { + switch (eventType) { + case EQUATION_REMOVED: + if (equation.isActive()) { + removeEquation(equation); + } + break; + + case EQUATION_DEACTIVATED: + removeEquation(equation); + break; + + case EQUATION_CREATED: + if (equation.isActive()) { + addEquation(equation); + } + break; + + case EQUATION_ACTIVATED: + addEquation(equation); + break; + + default: + throw new IllegalStateException("Event type not supported: " + eventType); + } + } + + @Override + public void onEquationTermChange(EquationTerm term, EquationTermEventType eventType) { + if (term.getEquation().isActive()) { + switch (eventType) { + case EQUATION_TERM_ADDED: + if (term.isActive()) { + addTerm(term); + } + break; + + case EQUATION_TERM_ACTIVATED: + addTerm(term); + break; + + case EQUATION_TERM_DEACTIVATED: + removeTerm(term); + break; + + default: + throw new IllegalStateException("Event type not supported: " + eventType); + } + } + } + + public NavigableSet> getSortedEquationsToSolve() { + update(); + return sortedEquationsToSolve; + } + + public NavigableSet> getSortedVariablesToFind() { + update(); + return sortedVariablesToFindRefCount.navigableKeySet(); + } +} diff --git a/src/main/java/com/powsybl/openloadflow/equations/EquationSystemIndexListener.java b/src/main/java/com/powsybl/openloadflow/equations/EquationSystemIndexListener.java new file mode 100644 index 0000000000..b0882cb076 --- /dev/null +++ b/src/main/java/com/powsybl/openloadflow/equations/EquationSystemIndexListener.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2022, 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/. + */ +package com.powsybl.openloadflow.equations; + +/** + * @author Geoffroy Jamgotchian + */ +public interface EquationSystemIndexListener & Quantity, E extends Enum & Quantity> { + + enum ChangeType { + ADDED, + REMOVED + } + + /** + * Called when a new variable has been added or removed to the system. + */ + void onVariableChange(Variable variable, ChangeType changeType); + + /** + * Called when a new equation has been added or removed to the system. + */ + void onEquationChange(Equation equation, ChangeType changeType); + + /** + * Called when a term is added or removed from an equation. + */ + void onEquationTermChange(EquationTerm term); +} diff --git a/src/main/java/com/powsybl/openloadflow/equations/JacobianMatrix.java b/src/main/java/com/powsybl/openloadflow/equations/JacobianMatrix.java index 9ebfeae325..4aafbf87b4 100644 --- a/src/main/java/com/powsybl/openloadflow/equations/JacobianMatrix.java +++ b/src/main/java/com/powsybl/openloadflow/equations/JacobianMatrix.java @@ -24,7 +24,7 @@ * @author Geoffroy Jamgotchian */ public class JacobianMatrix & Quantity, E extends Enum & Quantity> - implements EquationSystemListener, StateVectorListener, AutoCloseable { + implements EquationSystemIndexListener, StateVectorListener, AutoCloseable { private static final Logger LOGGER = LoggerFactory.getLogger(JacobianMatrix.class); @@ -67,61 +67,44 @@ Variable getVariable() { private enum Status { VALID, - MATRIX_INVALID, // structure has changed - VALUES_INVALID // same structure but values have to be updated + VALUES_INVALID, // same structure but values have to be updated + VALUES_AND_ZEROS_INVALID, // same structure but values have to be updated and non zero values might have changed + STRUCTURE_INVALID, // structure has changed } - private Status status = Status.MATRIX_INVALID; + private Status status = Status.STRUCTURE_INVALID; public JacobianMatrix(EquationSystem equationSystem, MatrixFactory matrixFactory) { this.equationSystem = Objects.requireNonNull(equationSystem); this.matrixFactory = Objects.requireNonNull(matrixFactory); - equationSystem.addListener(this); + equationSystem.getIndex().addListener(this); equationSystem.getStateVector().addListener(this); } - @Override - public void onEquationChange(Equation equation, EquationEventType eventType) { - switch (eventType) { - case EQUATION_CREATED: - case EQUATION_REMOVED: - case EQUATION_ACTIVATED: - case EQUATION_DEACTIVATED: - status = Status.MATRIX_INVALID; - break; - - default: - throw new IllegalStateException("Event type not supported: " + eventType); + private void updateStatus(Status status) { + if (status.ordinal() > this.status.ordinal()) { + this.status = status; } } @Override - public void onEquationTermChange(EquationTerm term, EquationTermEventType eventType) { - switch (eventType) { - case EQUATION_TERM_ADDED: - case EQUATION_TERM_ACTIVATED: - case EQUATION_TERM_DEACTIVATED: - // FIXME - // Note for later, it might be possible in the future in case of a term change to not fully rebuild - // the matrix as the structure has not changed (same equations and variables). But... we have for that - // to handle the case where the invalidation of an equation term break the graph connectivity. This - // is typically the case when the equation term is the active power flow of a branch which is also a - // bridge (so necessary for the connectivity). Normally in that case a bus equation should also have been - // deactivated and so it should work but for an unknown reason it fails with a KLU singular error (which - // means most of the time we have created the matrix with a non fully connected network) - status = Status.MATRIX_INVALID; - break; - - default: - throw new IllegalStateException("Event type not supported: " + eventType); - } + public void onEquationChange(Equation equation, ChangeType changeType) { + updateStatus(Status.STRUCTURE_INVALID); + } + + @Override + public void onVariableChange(Variable variable, ChangeType changeType) { + updateStatus(Status.STRUCTURE_INVALID); + } + + @Override + public void onEquationTermChange(EquationTerm term) { + updateStatus(Status.VALUES_AND_ZEROS_INVALID); } @Override public void onStateUpdate() { - if (status == Status.VALID) { - status = Status.VALUES_INVALID; - } + updateStatus(Status.VALUES_INVALID); } private void clearLu() { @@ -131,11 +114,22 @@ private void clearLu() { lu = null; } + private Map, List>> indexTermsByVariable(Equation eq) { + Map, List>> termsByVariable = new TreeMap<>(); + for (EquationTerm term : eq.getTerms()) { + for (Variable v : term.getVariables()) { + termsByVariable.computeIfAbsent(v, k -> new ArrayList<>()) + .add(term); + } + } + return termsByVariable; + } + private void initMatrix() { Stopwatch stopwatch = Stopwatch.createStarted(); - int rowCount = equationSystem.getSortedEquationsToSolve().size(); - int columnCount = equationSystem.getSortedVariablesToFind().size(); + int rowCount = equationSystem.getIndex().getSortedEquationsToSolve().size(); + int columnCount = equationSystem.getIndex().getSortedVariablesToFind().size(); if (rowCount != columnCount) { throw new PowsyblException("Expected to have same number of equations (" + rowCount + ") and variables (" + columnCount + ")"); @@ -145,16 +139,20 @@ private void initMatrix() { matrix = matrixFactory.create(rowCount, columnCount, estimatedNonZeroValueCount); partialDerivatives = new ArrayList<>(estimatedNonZeroValueCount); - for (Map.Entry, NavigableMap, List>>> e : equationSystem.getSortedEquationsToSolve().entrySet()) { - Equation eq = e.getKey(); + for (Equation eq : equationSystem.getIndex().getSortedEquationsToSolve()) { int column = eq.getColumn(); - for (Map.Entry, List>> e2 : e.getValue().entrySet()) { - Variable var = e2.getKey(); - int row = var.getRow(); - for (EquationTerm equationTerm : e2.getValue()) { - double value = equationTerm.der(var); - int elementIndex = matrix.addAndGetIndex(row, column, value); - partialDerivatives.add(new JacobianMatrix.PartialDerivative<>(equationTerm, elementIndex, var)); + Map, List>> termsByVariable = indexTermsByVariable(eq); + for (Map.Entry, List>> e : termsByVariable.entrySet()) { + Variable v = e.getKey(); + int row = v.getRow(); + if (row != -1) { + for (EquationTerm term : e.getValue()) { + // create a derivative for all terms including de-activated ones because could be reactivated + // at jacobian update stage without any equation or variable index change + double value = term.isActive() ? term.der(v) : 0; + int elementIndex = matrix.addAndGetIndex(row, column, value); + partialDerivatives.add(new JacobianMatrix.PartialDerivative<>(term, elementIndex, v)); + } } } } @@ -164,42 +162,48 @@ private void initMatrix() { clearLu(); } - private void updateLu() { + private void updateLu(boolean allowIncrementalUpdate) { if (lu != null) { Stopwatch stopwatch = Stopwatch.createStarted(); - lu.update(); + lu.update(allowIncrementalUpdate); LOGGER.debug(PERFORMANCE_MARKER, "LU decomposition updated in {} us", stopwatch.elapsed(TimeUnit.MICROSECONDS)); } } - private void updateValues() { + private void updateValues(boolean allowIncrementalUpdate) { Stopwatch stopwatch = Stopwatch.createStarted(); matrix.reset(); for (PartialDerivative partialDerivative : partialDerivatives) { - EquationTerm equationTerm = partialDerivative.getEquationTerm(); - int elementIndex = partialDerivative.getElementIndex(); - Variable var = partialDerivative.getVariable(); - double value = equationTerm.der(var); - matrix.addAtIndex(elementIndex, value); + EquationTerm term = partialDerivative.getEquationTerm(); + if (term.isActive()) { + int elementIndex = partialDerivative.getElementIndex(); + Variable v = partialDerivative.getVariable(); + double value = term.der(v); + matrix.addAtIndex(elementIndex, value); + } } LOGGER.debug(PERFORMANCE_MARKER, "Jacobian matrix values updated in {} us", stopwatch.elapsed(TimeUnit.MICROSECONDS)); - updateLu(); + updateLu(allowIncrementalUpdate); } public Matrix getMatrix() { if (status != Status.VALID) { switch (status) { - case MATRIX_INVALID: + case STRUCTURE_INVALID: initMatrix(); break; case VALUES_INVALID: - updateValues(); + updateValues(true); + break; + + case VALUES_AND_ZEROS_INVALID: + updateValues(false); break; default: @@ -240,7 +244,7 @@ public void solveTransposed(DenseMatrix b) { @Override public void close() { - equationSystem.removeListener(this); + equationSystem.getIndex().removeListener(this); equationSystem.getStateVector().removeListener(this); matrix = null; partialDerivatives = null; diff --git a/src/main/java/com/powsybl/openloadflow/equations/TargetVector.java b/src/main/java/com/powsybl/openloadflow/equations/TargetVector.java index 21c8556ddd..f7c8d10746 100644 --- a/src/main/java/com/powsybl/openloadflow/equations/TargetVector.java +++ b/src/main/java/com/powsybl/openloadflow/equations/TargetVector.java @@ -8,14 +8,14 @@ import com.powsybl.openloadflow.network.*; -import java.util.List; -import java.util.NavigableMap; +import java.util.NavigableSet; import java.util.Objects; /** * @author Geoffroy Jamgotchian */ -public class TargetVector & Quantity, E extends Enum & Quantity> extends AbstractLfNetworkListener implements EquationSystemListener { +public class TargetVector & Quantity, E extends Enum & Quantity> extends AbstractLfNetworkListener + implements EquationSystemIndexListener { @FunctionalInterface public interface Initializer & Quantity, E extends Enum & Quantity> { @@ -44,7 +44,7 @@ public TargetVector(LfNetwork network, EquationSystem equationSystem, Init this.equationSystem = Objects.requireNonNull(equationSystem); this.initializer = Objects.requireNonNull(initializer); network.addListener(this); - equationSystem.addListener(this); + equationSystem.getIndex().addListener(this); } private void invalidateValues() { @@ -79,12 +79,17 @@ public void onDiscretePhaseControlTapPositionChange(LfBranch controllerBranch, i } @Override - public void onEquationChange(Equation equation, EquationEventType eventType) { + public void onEquationChange(Equation equation, ChangeType changeType) { status = Status.VECTOR_INVALID; } @Override - public void onEquationTermChange(EquationTerm term, EquationTermEventType eventType) { + public void onVariableChange(Variable variable, ChangeType changeType) { + // nothing to do + } + + @Override + public void onEquationTermChange(EquationTerm term) { // nothing to do } @@ -109,9 +114,9 @@ public static & Quantity, E extends Enum & Quantity> doubl Objects.requireNonNull(network); Objects.requireNonNull(equationSystem); Objects.requireNonNull(initializer); - NavigableMap, NavigableMap, List>>> sortedEquationsToSolve = equationSystem.getSortedEquationsToSolve(); + NavigableSet> sortedEquationsToSolve = equationSystem.getIndex().getSortedEquationsToSolve(); double[] array = new double[sortedEquationsToSolve.size()]; - for (Equation equation : sortedEquationsToSolve.keySet()) { + for (Equation equation : sortedEquationsToSolve) { initializer.initialize(equation, network, array); } return array; @@ -123,8 +128,8 @@ private void createArray() { } private void updateArray() { - NavigableMap, NavigableMap, List>>> sortedEquationsToSolve = equationSystem.getSortedEquationsToSolve(); - for (Equation equation : sortedEquationsToSolve.keySet()) { + NavigableSet> sortedEquationsToSolve = equationSystem.getIndex().getSortedEquationsToSolve(); + for (Equation equation : sortedEquationsToSolve) { initializer.initialize(equation, network, array); } status = Status.VALID; diff --git a/src/main/java/com/powsybl/openloadflow/sensi/AbstractSensitivityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sensi/AbstractSensitivityAnalysis.java index 5b5cc440f9..f9d4ed8aa9 100644 --- a/src/main/java/com/powsybl/openloadflow/sensi/AbstractSensitivityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sensi/AbstractSensitivityAnalysis.java @@ -591,7 +591,7 @@ protected List getParticipatingElements(Collection } protected DenseMatrix initFactorsRhs(EquationSystem equationSystem, List> factorsGroups, Map participationByBus) { - DenseMatrix rhs = new DenseMatrix(equationSystem.getSortedEquationsToSolve().size(), factorsGroups.size()); + DenseMatrix rhs = new DenseMatrix(equationSystem.getIndex().getSortedEquationsToSolve().size(), factorsGroups.size()); fillRhsSensitivityVariable(factorsGroups, rhs, participationByBus); return rhs; } diff --git a/src/main/java/com/powsybl/openloadflow/sensi/AcSensitivityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sensi/AcSensitivityAnalysis.java index 815dd5421c..5e23b35a2b 100644 --- a/src/main/java/com/powsybl/openloadflow/sensi/AcSensitivityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sensi/AcSensitivityAnalysis.java @@ -253,7 +253,7 @@ public void analyse(Network network, List contingencies, // we make the assumption that we ran a loadflow before, and thus this jacobian is the right one // otherwise, defining the rhs matrix will result in integer overflow - if (factorGroups.size() >= Integer.MAX_VALUE / (context.getEquationSystem().getSortedEquationsToSolve().size() * Double.BYTES)) { + if (factorGroups.size() >= Integer.MAX_VALUE / (context.getEquationSystem().getIndex().getSortedEquationsToSolve().size() * Double.BYTES)) { throw new PowsyblException("Too many factors!"); } diff --git a/src/main/java/com/powsybl/openloadflow/sensi/DcSensitivityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sensi/DcSensitivityAnalysis.java index 6991ab5a96..1a8f432fdd 100644 --- a/src/main/java/com/powsybl/openloadflow/sensi/DcSensitivityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sensi/DcSensitivityAnalysis.java @@ -366,7 +366,7 @@ protected void fillRhsContingency(final LfNetwork lfNetwork, final EquationSyste } protected DenseMatrix initContingencyRhs(LfNetwork lfNetwork, EquationSystem equationSystem, Collection contingencyElements) { - DenseMatrix rhs = new DenseMatrix(equationSystem.getSortedEquationsToSolve().size(), contingencyElements.size()); + DenseMatrix rhs = new DenseMatrix(equationSystem.getIndex().getSortedEquationsToSolve().size(), contingencyElements.size()); fillRhsContingency(lfNetwork, equationSystem, contingencyElements, rhs); return rhs; } diff --git a/src/test/java/com/powsybl/openloadflow/ac/NonImpedantBranchDisablingTest.java b/src/test/java/com/powsybl/openloadflow/ac/NonImpedantBranchDisablingTest.java index 172599fc39..0e517d57d4 100644 --- a/src/test/java/com/powsybl/openloadflow/ac/NonImpedantBranchDisablingTest.java +++ b/src/test/java/com/powsybl/openloadflow/ac/NonImpedantBranchDisablingTest.java @@ -46,7 +46,7 @@ void test() { try (AcLoadFlowContext context = new AcLoadFlowContext(lfNetwork, parameters)) { var engine = new AcloadFlowEngine(context); engine.run(); - assertEquals(8, context.getEquationSystem().getSortedVariablesToFind().size()); + assertEquals(8, context.getEquationSystem().getIndex().getSortedVariablesToFind().size()); var l1 = lfNetwork.getBranchById("L1"); var l2 = lfNetwork.getBranchById("L2"); assertEquals(3.01884, l1.getP1().eval(), 10e-5); @@ -55,7 +55,7 @@ void test() { lfNetwork.getBranchById("C").setDisabled(true); engine.run(); - assertEquals(8, context.getEquationSystem().getSortedVariablesToFind().size()); // we have kept same variables!!! + assertEquals(8, context.getEquationSystem().getIndex().getSortedVariablesToFind().size()); // we have kept same variables!!! assertEquals(0, l1.getP1().eval(), 10e-5); assertEquals(6.07782, l2.getP1().eval(), 10e-5); } diff --git a/src/test/java/com/powsybl/openloadflow/equations/EquationSystemIndexTest.java b/src/test/java/com/powsybl/openloadflow/equations/EquationSystemIndexTest.java new file mode 100644 index 0000000000..f2a2de8c1d --- /dev/null +++ b/src/test/java/com/powsybl/openloadflow/equations/EquationSystemIndexTest.java @@ -0,0 +1,193 @@ +/** + * Copyright (c) 2022, 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/. + */ +package com.powsybl.openloadflow.equations; + +import com.powsybl.openloadflow.equations.EquationSystemIndexListener.ChangeType; +import com.powsybl.openloadflow.network.ElementType; +import org.apache.commons.lang3.tuple.Pair; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @author Geoffroy Jamgotchian + */ +class EquationSystemIndexTest { + + public enum TestEquationType implements Quantity { + X("x_", ElementType.BUS), + Y("y_", ElementType.BUS); + + private final String symbol; + + private final ElementType elementType; + + TestEquationType(String symbol, ElementType elementType) { + this.symbol = symbol; + this.elementType = elementType; + } + + @Override + public String getSymbol() { + return symbol; + } + + @Override + public ElementType getElementType() { + return elementType; + } + } + + public enum TestVariableType implements Quantity { + A("a_", ElementType.BUS), + B("b_", ElementType.BUS), + C("c_", ElementType.BUS); + + private final String symbol; + + private final ElementType elementType; + + TestVariableType(String symbol, ElementType elementType) { + this.symbol = symbol; + this.elementType = elementType; + } + + @Override + public String getSymbol() { + return symbol; + } + + @Override + public ElementType getElementType() { + return elementType; + } + } + + private final List> quantityAdded = new ArrayList<>(); + + @Test + void test() { + EquationSystem equationSystem = new EquationSystem<>(); + equationSystem.getIndex().addListener(new EquationSystemIndexListener<>() { + @Override + public void onVariableChange(Variable variable, ChangeType changeType) { + quantityAdded.add(Pair.of(variable.getType(), changeType)); + } + + @Override + public void onEquationChange(Equation equation, ChangeType changeType) { + quantityAdded.add(Pair.of(equation.getType(), changeType)); + } + + @Override + public void onEquationTermChange(EquationTerm term) { + // nothing to do + } + }); + + // x = a + b + // y = a + c + var a = equationSystem.getVariableSet().getVariable(0, TestVariableType.A); + var b = equationSystem.getVariableSet().getVariable(0, TestVariableType.B); + var c = equationSystem.getVariableSet().getVariable(0, TestVariableType.C); + EquationTerm aTerm = a.createTerm(); + EquationTerm bTerm = b.createTerm(); + var x = equationSystem.createEquation(0, TestEquationType.X) + .addTerm(aTerm) + .addTerm(bTerm); + EquationTerm aTerm2 = a.createTerm(); + EquationTerm cTerm = c.createTerm(); + var y = equationSystem.createEquation(0, TestEquationType.Y) + .addTerm(aTerm2) + .addTerm(cTerm); + assertEquals(List.of(Pair.of(TestEquationType.X, ChangeType.ADDED), + Pair.of(TestVariableType.A, ChangeType.ADDED), + Pair.of(TestVariableType.B, ChangeType.ADDED), + Pair.of(TestEquationType.Y, ChangeType.ADDED), + Pair.of(TestVariableType.C, ChangeType.ADDED)), + quantityAdded); + quantityAdded.clear(); + assertEquals(Set.of(x, y), equationSystem.getIndex().getSortedEquationsToSolve()); + assertEquals(Set.of(a, b, c), equationSystem.getIndex().getSortedVariablesToFind()); + + // deactivate y + // x = a + b + y.setActive(false); + assertEquals(List.of(Pair.of(TestVariableType.C, ChangeType.REMOVED), + Pair.of(TestEquationType.Y, ChangeType.REMOVED)), + quantityAdded); + quantityAdded.clear(); + assertEquals(Set.of(x), equationSystem.getIndex().getSortedEquationsToSolve()); + assertEquals(Set.of(a, b), equationSystem.getIndex().getSortedVariablesToFind()); + + // reactivate y + // x = a + b + // y = a + c + y.setActive(true); + assertEquals(List.of(Pair.of(TestVariableType.C, ChangeType.ADDED), + Pair.of(TestEquationType.Y, ChangeType.ADDED)), + quantityAdded); + quantityAdded.clear(); + assertEquals(Set.of(x, y), equationSystem.getIndex().getSortedEquationsToSolve()); + assertEquals(Set.of(a, b, c), equationSystem.getIndex().getSortedVariablesToFind()); + + // deactivate c term + // x = a + b + // y = a + cTerm.setActive(false); + assertEquals(List.of(Pair.of(TestVariableType.C, ChangeType.REMOVED)), + quantityAdded); + quantityAdded.clear(); + assertEquals(Set.of(x, y), equationSystem.getIndex().getSortedEquationsToSolve()); + assertEquals(Set.of(a, b), equationSystem.getIndex().getSortedVariablesToFind()); + + // reactivate c term + // x = a + b + // y = a + c + cTerm.setActive(true); + assertEquals(List.of(Pair.of(TestVariableType.C, ChangeType.ADDED)), + quantityAdded); + quantityAdded.clear(); + assertEquals(Set.of(x, y), equationSystem.getIndex().getSortedEquationsToSolve()); + assertEquals(Set.of(a, b, c), equationSystem.getIndex().getSortedVariablesToFind()); + + // deactivate all a term + // x = b + // y = c + aTerm.setActive(false); + assertTrue(quantityAdded.isEmpty()); + aTerm2.setActive(false); + assertEquals(List.of(Pair.of(TestVariableType.A, ChangeType.REMOVED)), + quantityAdded); + quantityAdded.clear(); + assertEquals(Set.of(x, y), equationSystem.getIndex().getSortedEquationsToSolve()); + assertEquals(Set.of(b, c), equationSystem.getIndex().getSortedVariablesToFind()); + + // reactivate one 'a' term + // x = a + b + // y = c + aTerm.setActive(true); + assertEquals(List.of(Pair.of(TestVariableType.A, ChangeType.ADDED)), + quantityAdded); + quantityAdded.clear(); + assertEquals(Set.of(x, y), equationSystem.getIndex().getSortedEquationsToSolve()); + assertEquals(Set.of(a, b, c), equationSystem.getIndex().getSortedVariablesToFind()); + + // reactovate other 'a' term + // x = a + b + // y = a + c + aTerm2.setActive(true); + assertTrue(quantityAdded.isEmpty()); + assertEquals(Set.of(x, y), equationSystem.getIndex().getSortedEquationsToSolve()); + assertEquals(Set.of(a, b, c), equationSystem.getIndex().getSortedVariablesToFind()); + } +} diff --git a/src/test/java/com/powsybl/openloadflow/equations/EquationSystemTest.java b/src/test/java/com/powsybl/openloadflow/equations/EquationSystemTest.java index d5a0962199..5b87643846 100644 --- a/src/test/java/com/powsybl/openloadflow/equations/EquationSystemTest.java +++ b/src/test/java/com/powsybl/openloadflow/equations/EquationSystemTest.java @@ -65,7 +65,7 @@ public void onEquationTermChange(EquationTerm te }); assertTrue(equations.isEmpty()); assertTrue(equationEventTypes.isEmpty()); - assertTrue(equationSystem.getSortedEquationsToSolve().isEmpty()); + assertTrue(equationSystem.getIndex().getSortedEquationsToSolve().isEmpty()); equationSystem.createEquation(bus.getNum(), AcEquationType.BUS_TARGET_V).addTerm(equationSystem.getVariable(bus.getNum(), AcVariableType.BUS_V).createTerm()); assertEquals(1, equations.size()); @@ -73,7 +73,7 @@ public void onEquationTermChange(EquationTerm te assertEquals(1, equationTermEventTypes.size()); assertEquals(EquationEventType.EQUATION_CREATED, equationEventTypes.get(0)); assertEquals(EquationTermEventType.EQUATION_TERM_ADDED, equationTermEventTypes.get(0)); - assertEquals(1, equationSystem.getSortedEquationsToSolve().size()); + assertEquals(1, equationSystem.getIndex().getSortedEquationsToSolve().size()); clearEvents(); equationSystem.createEquation(bus.getNum(), AcEquationType.BUS_TARGET_V).setActive(true); @@ -84,14 +84,14 @@ public void onEquationTermChange(EquationTerm te assertEquals(1, equations.size()); assertEquals(1, equationEventTypes.size()); assertEquals(EquationEventType.EQUATION_DEACTIVATED, equationEventTypes.get(0)); - assertTrue(equationSystem.getSortedEquationsToSolve().isEmpty()); + assertTrue(equationSystem.getIndex().getSortedEquationsToSolve().isEmpty()); clearEvents(); equationSystem.createEquation(bus.getNum(), AcEquationType.BUS_TARGET_V).setActive(true); assertEquals(1, equations.size()); assertEquals(1, equationEventTypes.size()); assertEquals(EquationEventType.EQUATION_ACTIVATED, equationEventTypes.get(0)); - assertEquals(1, equationSystem.getSortedEquationsToSolve().size()); + assertEquals(1, equationSystem.getIndex().getSortedEquationsToSolve().size()); assertTrue(equationSystem.getEquation(bus.getNum(), AcEquationType.BUS_TARGET_V).isPresent()); assertEquals(1, equationSystem.getEquations(ElementType.BUS, bus.getNum()).size()); diff --git a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java index 34b2452c58..8c344d9c1f 100644 --- a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java +++ b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java @@ -1174,14 +1174,14 @@ void testSaWithGeneratorContingency() { // pre-contingency tests PreContingencyResult preContingencyResult = result.getPreContingencyResult(); - assertEquals(109.999, preContingencyResult.getPreContingencyBranchResult("l24").getP1(), LoadFlowAssert.DELTA_POWER); - assertEquals(-39.999, preContingencyResult.getPreContingencyBranchResult("l14").getP2(), LoadFlowAssert.DELTA_POWER); + assertEquals(110, preContingencyResult.getPreContingencyBranchResult("l24").getP1(), LoadFlowAssert.DELTA_POWER); + assertEquals(-40, preContingencyResult.getPreContingencyBranchResult("l14").getP2(), LoadFlowAssert.DELTA_POWER); assertEquals(50.0, preContingencyResult.getPreContingencyBranchResult("l34").getP2(), LoadFlowAssert.DELTA_POWER); // post-contingency tests PostContingencyResult g1ContingencyResult = getPostContingencyResult(result, "g1"); - assertEquals(179.999, g1ContingencyResult.getBranchResult("l24").getP1(), LoadFlowAssert.DELTA_POWER); - assertEquals(29.999, g1ContingencyResult.getBranchResult("l14").getP2(), LoadFlowAssert.DELTA_POWER); + assertEquals(180, g1ContingencyResult.getBranchResult("l24").getP1(), LoadFlowAssert.DELTA_POWER); + assertEquals(30, g1ContingencyResult.getBranchResult("l14").getP2(), LoadFlowAssert.DELTA_POWER); assertEquals(50.0, g1ContingencyResult.getBranchResult("l34").getP2(), LoadFlowAssert.DELTA_POWER); assertEquals(399.855, g1ContingencyResult.getBusResult("b1").getV(), LoadFlowAssert.DELTA_V); assertEquals(400, g1ContingencyResult.getBusResult("b2").getV(), LoadFlowAssert.DELTA_V); From a8e6c0d14a69fe90b01df9b80289bb51e4084d92 Mon Sep 17 00:00:00 2001 From: Florian Dupuy <66690739+flo-dup@users.noreply.github.com> Date: Fri, 3 Jun 2022 16:50:20 +0200 Subject: [PATCH 03/15] Bump powsybl-core to 4.9.0-RC1 (#540) Signed-off-by: Etienne LESOT Signed-off-by: Florian Dupuy --- pom.xml | 2 +- .../openloadflow/OpenLoadFlowParameters.java | 37 +++++++------- .../openloadflow/OpenLoadFlowProvider.java | 11 ++++- .../powsybl/openloadflow/network/LfBus.java | 4 +- .../network/impl/AbstractLfBus.java | 6 +-- .../sa/AbstractSecurityAnalysis.java | 4 +- .../openloadflow/sa/AcSecurityAnalysis.java | 4 +- .../sa/OpenSecurityAnalysisProvider.java | 3 +- .../OpenSensitivityAnalysisConfigLoader.java | 41 ---------------- ...tivityAnalysisParameterJsonSerializer.java | 7 ++- .../OpenSensitivityAnalysisParameters.java | 24 ++++++++- .../OpenSensitivityAnalysisProvider.java | 29 ++++++++++- .../OpenLoadFlowParametersTest.java | 23 +++++++++ .../OpenLoadFlowProviderTest.java | 12 +++-- .../sa/OpenSecurityAnalysisTest.java | 12 +++-- ...OpenSensitivityAnalysisParametersTest.java | 49 +++++++++++++++++++ .../OpenSensitivityAnalysisProviderTest.java | 19 +++++++ ...cSensitivityAnalysisContingenciesTest.java | 2 +- .../util/LoadFlowResultBuilder.java | 2 +- src/test/resources/debug-network.xiidm | 2 +- 20 files changed, 205 insertions(+), 88 deletions(-) delete mode 100644 src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisConfigLoader.java create mode 100644 src/test/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisParametersTest.java diff --git a/pom.xml b/pom.xml index 34059306a8..eb37535bdb 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,7 @@ 5.5.2 1.6.2 - 4.8.0 + 4.9.0-RC1 diff --git a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java index 65535bc52f..e62793be1a 100644 --- a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java +++ b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java @@ -334,38 +334,41 @@ public static OpenLoadFlowParameters load(PlatformConfig platformConfig) { } public static OpenLoadFlowParameters load(Map properties) { - OpenLoadFlowParameters parameters = new OpenLoadFlowParameters(); + return new OpenLoadFlowParameters().update(properties); + } + + public OpenLoadFlowParameters update(Map properties) { Optional.ofNullable(properties.get(SLACK_BUS_SELECTION_PARAM_NAME)) - .ifPresent(prop -> parameters.setSlackBusSelectionMode(SlackBusSelectionMode.valueOf(prop))); + .ifPresent(prop -> this.setSlackBusSelectionMode(SlackBusSelectionMode.valueOf(prop))); Optional.ofNullable(properties.get(SLACK_BUSES_IDS_PARAM_NAME)) - .ifPresent(prop -> parameters.setSlackBusesIds(Arrays.asList(prop.split("[:,]")))); + .ifPresent(prop -> this.setSlackBusesIds(Arrays.asList(prop.split("[:,]")))); Optional.ofNullable(properties.get(LOW_IMPEDANCE_BRANCH_MODE_PARAM_NAME)) - .ifPresent(prop -> parameters.setLowImpedanceBranchMode(LowImpedanceBranchMode.valueOf(prop))); + .ifPresent(prop -> this.setLowImpedanceBranchMode(LowImpedanceBranchMode.valueOf(prop))); Optional.ofNullable(properties.get(VOLTAGE_REMOTE_CONTROL_PARAM_NAME)) - .ifPresent(prop -> parameters.setVoltageRemoteControl(Boolean.parseBoolean(prop))); + .ifPresent(prop -> this.setVoltageRemoteControl(Boolean.parseBoolean(prop))); Optional.ofNullable(properties.get(THROWS_EXCEPTION_IN_CASE_OF_SLACK_DISTRIBUTION_FAILURE_PARAM_NAME)) - .ifPresent(prop -> parameters.setThrowsExceptionInCaseOfSlackDistributionFailure(Boolean.parseBoolean(prop))); + .ifPresent(prop -> this.setThrowsExceptionInCaseOfSlackDistributionFailure(Boolean.parseBoolean(prop))); Optional.ofNullable(properties.get(LOAD_POWER_FACTOR_CONSTANT_PARAM_NAME)) - .ifPresent(prop -> parameters.setLoadPowerFactorConstant(Boolean.parseBoolean(prop))); + .ifPresent(prop -> this.setLoadPowerFactorConstant(Boolean.parseBoolean(prop))); Optional.ofNullable(properties.get(PLAUSIBLE_ACTIVE_POWER_LIMIT_PARAM_NAME)) - .ifPresent(prop -> parameters.setPlausibleActivePowerLimit(Double.parseDouble(prop))); + .ifPresent(prop -> this.setPlausibleActivePowerLimit(Double.parseDouble(prop))); Optional.ofNullable(properties.get(ADD_RATIO_TO_LINES_WITH_DIFFERENT_NOMINAL_VOLTAGE_AT_BOTH_ENDS_NAME)) - .ifPresent(prop -> parameters.setAddRatioToLinesWithDifferentNominalVoltageAtBothEnds(Boolean.parseBoolean(prop))); + .ifPresent(prop -> this.setAddRatioToLinesWithDifferentNominalVoltageAtBothEnds(Boolean.parseBoolean(prop))); Optional.ofNullable(properties.get(SLACK_BUS_P_MAX_MISMATCH_NAME)) - .ifPresent(prop -> parameters.setSlackBusPMaxMismatch(Double.parseDouble(prop))); + .ifPresent(prop -> this.setSlackBusPMaxMismatch(Double.parseDouble(prop))); Optional.ofNullable(properties.get(VOLTAGE_PER_REACTIVE_POWER_CONTROL_NAME)) - .ifPresent(prop -> parameters.setVoltagePerReactivePowerControl(Boolean.parseBoolean(prop))); + .ifPresent(prop -> this.setVoltagePerReactivePowerControl(Boolean.parseBoolean(prop))); Optional.ofNullable(properties.get(REACTIVE_POWER_REMOTE_CONTROL_PARAM_NAME)) - .ifPresent(prop -> parameters.setReactivePowerRemoteControl(Boolean.parseBoolean(prop))); + .ifPresent(prop -> this.setReactivePowerRemoteControl(Boolean.parseBoolean(prop))); Optional.ofNullable(properties.get(MAX_ITERATION_NAME)) - .ifPresent(prop -> parameters.setMaxIteration(Integer.parseInt(prop))); + .ifPresent(prop -> this.setMaxIteration(Integer.parseInt(prop))); Optional.ofNullable(properties.get(NEWTON_RAPHSON_CONV_EPS_PER_EQ_NAME)) - .ifPresent(prop -> parameters.setNewtonRaphsonConvEpsPerEq(Double.parseDouble(prop))); + .ifPresent(prop -> this.setNewtonRaphsonConvEpsPerEq(Double.parseDouble(prop))); Optional.ofNullable(properties.get(VOLTAGE_INIT_MODE_OVERRIDE_NAME)) - .ifPresent(prop -> parameters.setVoltageInitModeOverride(VoltageInitModeOverride.valueOf(prop))); + .ifPresent(prop -> this.setVoltageInitModeOverride(VoltageInitModeOverride.valueOf(prop))); Optional.ofNullable(properties.get(TRANSFORMER_VOLTAGE_CONTROL_MODE_NAME)) - .ifPresent(prop -> parameters.setTransformerVoltageControlMode(TransformerVoltageControlMode.valueOf(prop))); - return parameters; + .ifPresent(prop -> this.setTransformerVoltageControlMode(TransformerVoltageControlMode.valueOf(prop))); + return this; } @Override diff --git a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java index e6ebf45046..104395e7c5 100644 --- a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java +++ b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowProvider.java @@ -144,7 +144,8 @@ private LoadFlowResult runAc(Network network, LoadFlowParameters parameters, Rep status, result.getNewtonRaphsonIterations(), result.getNetwork().getSlackBus().getId(), - result.getSlackBusActivePowerMismatch() * PerUnit.SB)); + result.getSlackBusActivePowerMismatch() * PerUnit.SB, + Double.NaN)); } // zero or low impedance branch flows computation @@ -197,7 +198,8 @@ private LoadFlowResult.ComponentResult processResult(Network network, DcLoadFlow pResult.getStatus(), 0, pResult.getNetwork().getSlackBus().getId(), - pResult.getSlackBusActivePowerMismatch() * PerUnit.SB); + pResult.getSlackBusActivePowerMismatch() * PerUnit.SB, + Double.NaN); } @Override @@ -253,4 +255,9 @@ public Optional> loadSpecificParameters(Map getSpecificParametersNames() { return OpenLoadFlowParameters.SPECIFIC_PARAMETERS_NAMES; } + + @Override + public void updateSpecificParameters(Extension extension, Map properties) { + ((OpenLoadFlowParameters) extension).update(properties); + } } diff --git a/src/main/java/com/powsybl/openloadflow/network/LfBus.java b/src/main/java/com/powsybl/openloadflow/network/LfBus.java index d9e1f144a2..3f14154a41 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfBus.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfBus.java @@ -7,7 +7,7 @@ package com.powsybl.openloadflow.network; import com.powsybl.openloadflow.util.Evaluable; -import com.powsybl.security.results.BusResults; +import com.powsybl.security.results.BusResult; import java.util.List; import java.util.Map; @@ -151,7 +151,7 @@ default boolean isParticipating() { return false; } - BusResults createBusResult(); + BusResult createBusResult(); /** * Find bus + parallel branches neighbors. diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java b/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java index ef35f1d418..2e1ac9b5c7 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java @@ -11,7 +11,7 @@ import com.powsybl.openloadflow.network.*; import com.powsybl.openloadflow.util.Evaluable; import com.powsybl.openloadflow.util.PerUnit; -import com.powsybl.security.results.BusResults; +import com.powsybl.security.results.BusResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -539,8 +539,8 @@ public Evaluable getQ() { } @Override - public BusResults createBusResult() { - return new BusResults(getVoltageLevelId(), getId(), v, getAngle()); + public BusResult createBusResult() { + return new BusResult(getVoltageLevelId(), getId(), v, getAngle()); } @Override diff --git a/src/main/java/com/powsybl/openloadflow/sa/AbstractSecurityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sa/AbstractSecurityAnalysis.java index 96561d073b..0902af66ba 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/AbstractSecurityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sa/AbstractSecurityAnalysis.java @@ -27,7 +27,7 @@ import com.powsybl.security.monitor.StateMonitor; import com.powsybl.security.monitor.StateMonitorIndex; import com.powsybl.security.results.BranchResult; -import com.powsybl.security.results.BusResults; +import com.powsybl.security.results.BusResult; import com.powsybl.security.results.ThreeWindingsTransformerResult; import org.apache.commons.lang3.tuple.Pair; import org.slf4j.Logger; @@ -249,7 +249,7 @@ protected static boolean isFlowViolation(LimitViolation limit) { } protected void addMonitorInfo(LfNetwork network, StateMonitor monitor, Collection branchResultConsumer, - Collection busResultsConsumer, Collection threeWindingsTransformerResultConsumer, + Collection busResultsConsumer, Collection threeWindingsTransformerResultConsumer, Map preContingencyBranchResults, String contingencyId) { network.getBranches().stream().filter(lfBranch -> monitor.getBranchIds().contains(lfBranch.getId())) .filter(lfBranch -> !lfBranch.isDisabled()) diff --git a/src/main/java/com/powsybl/openloadflow/sa/AcSecurityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sa/AcSecurityAnalysis.java index c3b46f9d72..20f5cb356b 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/AcSecurityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sa/AcSecurityAnalysis.java @@ -116,7 +116,7 @@ private SecurityAnalysisResult runSimulations(LfNetwork network, List preContingencyBranchResults = new ArrayList<>(); - List preContingencyBusResults = new ArrayList<>(); + List preContingencyBusResults = new ArrayList<>(); List preContingencyThreeWindingsTransformerResults = new ArrayList<>(); // run pre-contingency simulation @@ -178,7 +178,7 @@ private PostContingencyResult runPostContingencySimulation(LfNetwork network, Ac Stopwatch stopwatch = Stopwatch.createStarted(); List branchResults = new ArrayList<>(); - List busResults = new ArrayList<>(); + List busResults = new ArrayList<>(); List threeWindingsTransformerResults = new ArrayList<>(); // restart LF on post contingency equation system diff --git a/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisProvider.java b/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisProvider.java index 4e2a420c30..2d2fba9d71 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisProvider.java +++ b/src/main/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisProvider.java @@ -7,6 +7,7 @@ package com.powsybl.openloadflow.sa; import com.google.auto.service.AutoService; +import com.powsybl.commons.reporter.Reporter; import com.powsybl.computation.ComputationManager; import com.powsybl.contingency.ContingenciesProvider; import com.powsybl.iidm.network.Network; @@ -48,7 +49,7 @@ public OpenSecurityAnalysisProvider() { public CompletableFuture run(Network network, String workingVariantId, LimitViolationDetector limitViolationDetector, LimitViolationFilter limitViolationFilter, ComputationManager computationManager, SecurityAnalysisParameters securityAnalysisParameters, ContingenciesProvider contingenciesProvider, - List interceptors, List stateMonitors) { + List interceptors, List stateMonitors, Reporter reporter) { Objects.requireNonNull(network); Objects.requireNonNull(workingVariantId); Objects.requireNonNull(limitViolationDetector); diff --git a/src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisConfigLoader.java b/src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisConfigLoader.java deleted file mode 100644 index 9886d33551..0000000000 --- a/src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisConfigLoader.java +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2021, 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/. - */ -package com.powsybl.openloadflow.sensi; - -import com.google.auto.service.AutoService; -import com.powsybl.commons.config.PlatformConfig; -import com.powsybl.sensitivity.SensitivityAnalysisParameters; - -/** - * @author Geoffroy Jamgotchian - */ -@AutoService(SensitivityAnalysisParameters.ConfigLoader.class) -public class OpenSensitivityAnalysisConfigLoader implements SensitivityAnalysisParameters.ConfigLoader { - - @Override - public OpenSensitivityAnalysisParameters load(PlatformConfig platformConfig) { - OpenSensitivityAnalysisParameters parameters = new OpenSensitivityAnalysisParameters(); - platformConfig.getOptionalModuleConfig("open-sensitivity-default-parameters") - .ifPresent(config -> parameters.setDebugDir(config.getStringProperty("debug-dir", null))); - return parameters; - } - - @Override - public String getExtensionName() { - return "open-sensitivity-parameters"; - } - - @Override - public String getCategoryName() { - return "sensitivity-parameters"; - } - - @Override - public Class getExtensionClass() { - return OpenSensitivityAnalysisParameters.class; - } -} diff --git a/src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisParameterJsonSerializer.java b/src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisParameterJsonSerializer.java index ff59686a17..d9258d2dcd 100644 --- a/src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisParameterJsonSerializer.java +++ b/src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisParameterJsonSerializer.java @@ -12,17 +12,16 @@ import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializerProvider; -import com.google.auto.service.AutoService; +import com.powsybl.commons.extensions.ExtensionJsonSerializer; import com.powsybl.commons.json.JsonUtil; -import com.powsybl.sensitivity.json.SensitivityJson; +import com.powsybl.sensitivity.SensitivityAnalysisParameters; import java.io.IOException; /** * @author Geoffroy Jamgotchian */ -@AutoService(SensitivityJson.ExtensionSerializer.class) -public class OpenSensitivityAnalysisParameterJsonSerializer implements SensitivityJson.ExtensionSerializer { +public class OpenSensitivityAnalysisParameterJsonSerializer implements ExtensionJsonSerializer { @Override public String getExtensionName() { diff --git a/src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisParameters.java b/src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisParameters.java index 15da42a7c6..34837f473d 100644 --- a/src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisParameters.java +++ b/src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisParameters.java @@ -10,6 +10,10 @@ import com.powsybl.commons.extensions.AbstractExtension; import com.powsybl.sensitivity.SensitivityAnalysisParameters; +import java.util.List; +import java.util.Map; +import java.util.Optional; + /** * @author Geoffroy Jamgotchian */ @@ -17,6 +21,10 @@ public class OpenSensitivityAnalysisParameters extends AbstractExtension SPECIFIC_PARAMETERS_NAMES = List.of(DEBUG_DIR_PARAM_NAME); + @Override public String getName() { return "open-sensitivity-parameters"; @@ -32,6 +40,20 @@ public OpenSensitivityAnalysisParameters setDebugDir(String debugDir) { } public static OpenSensitivityAnalysisParameters load() { - return new OpenSensitivityAnalysisConfigLoader().load(PlatformConfig.defaultConfig()); + return load(PlatformConfig.defaultConfig()); + } + + public static OpenSensitivityAnalysisParameters load(PlatformConfig platformConfig) { + OpenSensitivityAnalysisParameters parameters = new OpenSensitivityAnalysisParameters(); + platformConfig.getOptionalModuleConfig("open-sensitivityanalysis-default-parameters") + .ifPresent(config -> parameters + .setDebugDir(config.getStringProperty(DEBUG_DIR_PARAM_NAME, DEBUG_DIR_DEFAULT_VALUE))); + return parameters; + } + + public static OpenSensitivityAnalysisParameters load(Map properties) { + OpenSensitivityAnalysisParameters parameters = new OpenSensitivityAnalysisParameters(); + Optional.ofNullable(properties.get(DEBUG_DIR_PARAM_NAME)).ifPresent(parameters::setDebugDir); + return parameters; } } diff --git a/src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisProvider.java b/src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisProvider.java index ccf6589436..724c8cb692 100644 --- a/src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisProvider.java +++ b/src/main/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisProvider.java @@ -10,7 +10,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; import com.google.auto.service.AutoService; +import com.powsybl.commons.PowsyblException; import com.powsybl.commons.config.PlatformConfig; +import com.powsybl.commons.extensions.Extension; +import com.powsybl.commons.extensions.ExtensionJsonSerializer; import com.powsybl.commons.reporter.Reporter; import com.powsybl.computation.ComputationManager; import com.powsybl.computation.local.LocalComputationManager; @@ -44,7 +47,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.CompletableFuture; /** @@ -84,6 +89,26 @@ public String getVersion() { return new PowsyblCoreVersion().getMavenProjectVersion(); } + @Override + public Optional getSpecificParametersSerializer() { + return Optional.of(new OpenSensitivityAnalysisParameterJsonSerializer()); + } + + @Override + public Optional> loadSpecificParameters(PlatformConfig platformConfig) { + return Optional.of(OpenSensitivityAnalysisParameters.load(platformConfig)); + } + + @Override + public Optional> loadSpecificParameters(Map properties) { + return Optional.of(OpenSensitivityAnalysisParameters.load(properties)); + } + + @Override + public List getSpecificParametersNames() { + return OpenSensitivityAnalysisParameters.SPECIFIC_PARAMETERS_NAMES; + } + private static OpenSensitivityAnalysisParameters getSensitivityAnalysisParametersExtension(SensitivityAnalysisParameters sensitivityAnalysisParameters) { OpenSensitivityAnalysisParameters sensiParametersExt = sensitivityAnalysisParameters.getExtension(OpenSensitivityAnalysisParameters.class); if (sensiParametersExt == null) { @@ -136,7 +161,9 @@ public CompletableFuture run(Network network, // debugging if (sensitivityAnalysisParametersExt.getDebugDir() != null) { - Path debugDir = PlatformConfig.defaultConfig().getConfigDir().getFileSystem().getPath(sensitivityAnalysisParametersExt.getDebugDir()); + Path debugDir = PlatformConfig.defaultConfig().getConfigDir() + .map(dir -> dir.getFileSystem().getPath(sensitivityAnalysisParametersExt.getDebugDir())) + .orElseThrow(() -> new PowsyblException("Cannot write to debug directory as no configuration directory has been defined")); String dateStr = DateTime.now().toString(DATE_TIME_FORMAT); NetworkXml.write(network, debugDir.resolve("network-" + dateStr + ".xiidm")); diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java index de1d86c5e0..a951d027b6 100644 --- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java +++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java @@ -33,7 +33,9 @@ import java.nio.file.FileSystem; import java.nio.file.Files; import java.nio.file.Path; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static org.junit.jupiter.api.Assertions.*; @@ -196,4 +198,25 @@ void testSetSlackBusPMaxMismatch() { LoadFlowResult result2 = loadFlowRunner2.run(network, parameters); assertEquals(-1.8703e-5, result2.getComponentResults().get(0).getSlackBusActivePowerMismatch(), DELTA_MISMATCH); } + + @Test + void testUpdateParameters() { + Map parametersMap = new HashMap<>(); + parametersMap.put("slackBusSelectionMode", "FIRST"); + parametersMap.put("voltageRemoteControl", "true"); + parametersMap.put("reactivePowerRemoteControl", "false"); + OpenLoadFlowParameters parameters = OpenLoadFlowParameters.load(parametersMap); + assertEquals(SlackBusSelectionMode.FIRST, parameters.getSlackBusSelectionMode()); + assertTrue(parameters.hasVoltageRemoteControl()); + assertFalse(parameters.hasReactivePowerRemoteControl()); + Map updateParametersMap = new HashMap<>(); + updateParametersMap.put("slackBusSelectionMode", "MOST_MESHED"); + updateParametersMap.put("voltageRemoteControl", "false"); + updateParametersMap.put("maxIteration", "10"); + parameters.update(updateParametersMap); + assertEquals(SlackBusSelectionMode.MOST_MESHED, parameters.getSlackBusSelectionMode()); + assertFalse(parameters.hasVoltageRemoteControl()); + assertEquals(10, parameters.getMaxIteration()); + assertFalse(parameters.hasReactivePowerRemoteControl()); + } } diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java index 6b0181c32a..cac7e0d510 100644 --- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java +++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java @@ -28,10 +28,10 @@ import org.mockito.Mockito; import java.util.Collections; +import java.util.HashMap; import java.util.Map; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; /** * @author Geoffroy Jamgotchian @@ -84,7 +84,7 @@ void testGetExtendedVoltageInitializer() { @Test void specificParametersTest() { - var provider = new OpenLoadFlowProvider(); + OpenLoadFlowProvider provider = new OpenLoadFlowProvider(); assertEquals(15, provider.getSpecificParametersNames().size()); LoadFlowParameters parameters = new LoadFlowParameters(); @@ -95,5 +95,11 @@ void specificParametersTest() { provider.loadSpecificParameters(Map.of(OpenLoadFlowParameters.SLACK_BUS_SELECTION_PARAM_NAME, SlackBusSelectionMode.FIRST.name())) .ifPresent(parametersExt -> parameters.addExtension((Class) parametersExt.getClass(), parametersExt)); assertEquals(SlackBusSelectionMode.FIRST, parameters.getExtension(OpenLoadFlowParameters.class).getSlackBusSelectionMode()); + Map updateParametersMap = new HashMap<>(); + updateParametersMap.put("slackBusSelectionMode", "MOST_MESHED"); + updateParametersMap.put("voltageRemoteControl", "false"); + provider.updateSpecificParameters(parameters.getExtension(OpenLoadFlowParameters.class), updateParametersMap); + assertEquals(SlackBusSelectionMode.MOST_MESHED, parameters.getExtension(OpenLoadFlowParameters.class).getSlackBusSelectionMode()); + assertFalse(parameters.getExtension(OpenLoadFlowParameters.class).hasVoltageRemoteControl()); } } diff --git a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java index 8c344d9c1f..38e93ea89f 100644 --- a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java +++ b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java @@ -7,6 +7,7 @@ package com.powsybl.openloadflow.sa; import com.powsybl.commons.PowsyblException; +import com.powsybl.commons.reporter.Reporter; import com.powsybl.computation.ComputationManager; import com.powsybl.contingency.*; import com.powsybl.ieeecdf.converter.IeeeCdfNetworkFactory; @@ -129,7 +130,8 @@ private SecurityAnalysisResult runSecurityAnalysis(Network network, List busResults = preContingencyResult.getPreContingencyBusResults(); - BusResults expectedBus = new BusResults("VLLOAD", "NLOAD", 147.6, -9.6); + List busResults = preContingencyResult.getPreContingencyBusResults(); + BusResult expectedBus = new BusResult("VLLOAD", "NLOAD", 147.6, -9.6); assertEquals(1, busResults.size()); assertAlmostEquals(expectedBus, busResults.get(0), 0.1); @@ -527,7 +529,7 @@ void testSaWithStateMonitorDisconnectBranch() { assertEquals(1, result.getPreContingencyResult().getPreContingencyBusResults().size()); - assertEquals(new BusResults("b1_vl", "b1", 400, 0.003581299841270782), result.getPreContingencyResult().getPreContingencyBusResults().get(0)); + assertEquals(new BusResult("b1_vl", "b1", 400, 0.003581299841270782), result.getPreContingencyResult().getPreContingencyBusResults().get(0)); assertEquals(1, result.getPreContingencyResult().getPreContingencyBusResults().size()); assertEquals(new BranchResult("l24", NaN, NaN, NaN, 0.0, -0.0, 0.0), result.getPreContingencyResult().getPreContingencyBranchResults().get(0)); diff --git a/src/test/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisParametersTest.java b/src/test/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisParametersTest.java new file mode 100644 index 0000000000..01e4911660 --- /dev/null +++ b/src/test/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisParametersTest.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2022, 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/. + */ +package com.powsybl.openloadflow.sensi; + +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; +import com.powsybl.commons.config.InMemoryPlatformConfig; +import com.powsybl.commons.config.MapModuleConfig; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.FileSystem; + +/** + * @author Etienne Lesot + */ +class OpenSensitivityAnalysisParametersTest { + + private InMemoryPlatformConfig platformConfig; + + private FileSystem fileSystem; + + @BeforeEach + public void setUp() { + fileSystem = Jimfs.newFileSystem(Configuration.unix()); + platformConfig = new InMemoryPlatformConfig(fileSystem); + + MapModuleConfig lfModuleConfig = platformConfig.createModuleConfig("open-sensitivityanalysis-default-parameters"); + lfModuleConfig.setStringProperty("debugDir", "/debugDir"); + } + + @AfterEach + void tearDown() throws IOException { + fileSystem.close(); + } + + @Test + void test() { + OpenSensitivityAnalysisParameters parameters = OpenSensitivityAnalysisParameters.load(platformConfig); + Assertions.assertEquals("/debugDir", parameters.getDebugDir()); + } +} diff --git a/src/test/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisProviderTest.java b/src/test/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisProviderTest.java index 01b3c81231..7ec602ad9c 100644 --- a/src/test/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisProviderTest.java +++ b/src/test/java/com/powsybl/openloadflow/sensi/OpenSensitivityAnalysisProviderTest.java @@ -7,11 +7,15 @@ package com.powsybl.openloadflow.sensi; import com.powsybl.math.matrix.DenseMatrixFactory; +import com.powsybl.sensitivity.SensitivityAnalysisParameters; import com.powsybl.tools.PowsyblCoreVersion; import org.junit.jupiter.api.Test; +import java.util.Collections; +import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; /** * @author Geoffroy Jamgotchian @@ -24,4 +28,19 @@ void testGeneralInfos() { assertEquals("OpenSensitivityAnalysis", provider.getName()); assertEquals(new PowsyblCoreVersion().getMavenProjectVersion(), provider.getVersion()); } + + @Test + void specificParametersTest() { + var provider = new OpenSensitivityAnalysisProvider(); + assertEquals(1, provider.getSpecificParametersNames().size()); + SensitivityAnalysisParameters parameters = new SensitivityAnalysisParameters(); + + provider.loadSpecificParameters(Collections.emptyMap()) + .ifPresent(parametersExt -> parameters.addExtension((Class) parametersExt.getClass(), parametersExt)); + assertNull(parameters.getExtension(OpenSensitivityAnalysisParameters.class).getDebugDir()); + + provider.loadSpecificParameters(Map.of(OpenSensitivityAnalysisParameters.DEBUG_DIR_PARAM_NAME, "")) + .ifPresent(parametersExt -> parameters.addExtension((Class) parametersExt.getClass(), parametersExt)); + assertEquals("", parameters.getExtension(OpenSensitivityAnalysisParameters.class).getDebugDir()); + } } 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 24dac6dd83..4f8b3e5c2f 100644 --- a/src/test/java/com/powsybl/openloadflow/sensi/dc/DcSensitivityAnalysisContingenciesTest.java +++ b/src/test/java/com/powsybl/openloadflow/sensi/dc/DcSensitivityAnalysisContingenciesTest.java @@ -1560,7 +1560,7 @@ void testDebug() throws IOException { Path networkFile = null; Path parametersFile = null; Path variableSetsFile = null; - FileSystem fileSystem = PlatformConfig.defaultConfig().getConfigDir().getFileSystem(); + FileSystem fileSystem = PlatformConfig.defaultConfig().getConfigDir().map(Path::getFileSystem).orElseThrow(PowsyblException::new); PathMatcher contingenciesMatcher = fileSystem.getPathMatcher("glob:contingencies-*.json"); PathMatcher factorsMatcher = fileSystem.getPathMatcher("glob:factors-*.json"); PathMatcher networkMatcher = fileSystem.getPathMatcher("glob:network-*.xiidm"); diff --git a/src/test/java/com/powsybl/openloadflow/util/LoadFlowResultBuilder.java b/src/test/java/com/powsybl/openloadflow/util/LoadFlowResultBuilder.java index 88bf289039..60bd174382 100644 --- a/src/test/java/com/powsybl/openloadflow/util/LoadFlowResultBuilder.java +++ b/src/test/java/com/powsybl/openloadflow/util/LoadFlowResultBuilder.java @@ -40,7 +40,7 @@ public LoadFlowResultBuilder setLogs(String logs) { } public LoadFlowResultBuilder addComponentResult(int componentNum, int synchronousComponentNum, LoadFlowResult.ComponentResult.Status status, int iterationCount, String slackBusId, double slackBusActivePowerMismatch) { - this.componentResults.add(new LoadFlowResultImpl.ComponentResultImpl(componentNum, synchronousComponentNum, status, iterationCount, slackBusId, slackBusActivePowerMismatch)); + this.componentResults.add(new LoadFlowResultImpl.ComponentResultImpl(componentNum, synchronousComponentNum, status, iterationCount, slackBusId, slackBusActivePowerMismatch, Double.NaN)); return this; } diff --git a/src/test/resources/debug-network.xiidm b/src/test/resources/debug-network.xiidm index 9be1f20f42..1950876b75 100644 --- a/src/test/resources/debug-network.xiidm +++ b/src/test/resources/debug-network.xiidm @@ -1,5 +1,5 @@ - + From acee838ea388965dc7ae95e1a261af8d908aa3f7 Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Sun, 5 Jun 2022 20:55:30 +0200 Subject: [PATCH 04/15] Add AC equations unit tests Signed-off-by: Geoffroy Jamgotchian --- .../AbstractBranchAcFlowEquationTerm.java | 2 +- .../openloadflow/equations/StateVector.java | 8 + .../powsybl/openloadflow/network/PiModel.java | 2 + .../openloadflow/network/PiModelArray.java | 5 + .../openloadflow/network/SimplePiModel.java | 5 + .../impl/LfVscConverterStationImpl.java | 4 +- .../openloadflow/ac/AcEquationsTest.java | 201 ++++++++++++++++++ 7 files changed, 224 insertions(+), 3 deletions(-) create mode 100644 src/test/java/com/powsybl/openloadflow/ac/AcEquationsTest.java diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractBranchAcFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractBranchAcFlowEquationTerm.java index 94c4a21455..4609bd95d6 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractBranchAcFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractBranchAcFlowEquationTerm.java @@ -32,7 +32,7 @@ protected AbstractBranchAcFlowEquationTerm(LfBranch branch) { b2 = piModel.getB2(); g1 = piModel.getG1(); g2 = piModel.getG2(); - y = 1 / piModel.getZ(); + y = piModel.getY(); ksi = piModel.getKsi(); } } diff --git a/src/main/java/com/powsybl/openloadflow/equations/StateVector.java b/src/main/java/com/powsybl/openloadflow/equations/StateVector.java index 92d938d561..b6da2583fa 100644 --- a/src/main/java/com/powsybl/openloadflow/equations/StateVector.java +++ b/src/main/java/com/powsybl/openloadflow/equations/StateVector.java @@ -19,6 +19,14 @@ public class StateVector { private final List listeners = new ArrayList<>(); + public StateVector() { + this(null); + } + + public StateVector(double[] array) { + this.array = array; + } + public void set(double[] array) { this.array = Objects.requireNonNull(array); notifyStateUpdate(); diff --git a/src/main/java/com/powsybl/openloadflow/network/PiModel.java b/src/main/java/com/powsybl/openloadflow/network/PiModel.java index 1a4f14722c..c1eee508a2 100644 --- a/src/main/java/com/powsybl/openloadflow/network/PiModel.java +++ b/src/main/java/com/powsybl/openloadflow/network/PiModel.java @@ -25,6 +25,8 @@ public interface PiModel { double getZ(); + double getY(); + double getKsi(); double getG1(); diff --git a/src/main/java/com/powsybl/openloadflow/network/PiModelArray.java b/src/main/java/com/powsybl/openloadflow/network/PiModelArray.java index ab753b0ea5..385341a170 100644 --- a/src/main/java/com/powsybl/openloadflow/network/PiModelArray.java +++ b/src/main/java/com/powsybl/openloadflow/network/PiModelArray.java @@ -61,6 +61,11 @@ public double getZ() { return getModel().getZ(); } + @Override + public double getY() { + return getModel().getY(); + } + @Override public double getKsi() { return getModel().getKsi(); diff --git a/src/main/java/com/powsybl/openloadflow/network/SimplePiModel.java b/src/main/java/com/powsybl/openloadflow/network/SimplePiModel.java index 97c521bd67..f5ad0895c4 100644 --- a/src/main/java/com/powsybl/openloadflow/network/SimplePiModel.java +++ b/src/main/java/com/powsybl/openloadflow/network/SimplePiModel.java @@ -49,6 +49,11 @@ public double getZ() { return FastMath.hypot(r, x); } + @Override + public double getY() { + return 1 / getZ(); + } + @Override public double getKsi() { return FastMath.atan2(r, x); diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfVscConverterStationImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfVscConverterStationImpl.java index 14d9af9874..18c06b37d4 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfVscConverterStationImpl.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfVscConverterStationImpl.java @@ -15,13 +15,13 @@ /** * @author Geoffroy Jamgotchian */ -public final class LfVscConverterStationImpl extends AbstractLfGenerator { +public class LfVscConverterStationImpl extends AbstractLfGenerator { private final VscConverterStation station; private double lossFactor; - private LfVscConverterStationImpl(VscConverterStation station, boolean breakers, boolean reactiveLimits, LfNetworkLoadingReport report) { + public LfVscConverterStationImpl(VscConverterStation station, boolean breakers, boolean reactiveLimits, LfNetworkLoadingReport report) { super(HvdcConverterStations.getConverterStationTargetP(station)); this.station = station; this.lossFactor = station.getLossFactor(); diff --git a/src/test/java/com/powsybl/openloadflow/ac/AcEquationsTest.java b/src/test/java/com/powsybl/openloadflow/ac/AcEquationsTest.java new file mode 100644 index 0000000000..e363c743cf --- /dev/null +++ b/src/test/java/com/powsybl/openloadflow/ac/AcEquationsTest.java @@ -0,0 +1,201 @@ +/** + * Copyright (c) 2022, 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/. + */ +package com.powsybl.openloadflow.ac; + +import com.powsybl.commons.PowsyblException; +import com.powsybl.openloadflow.ac.equations.*; +import com.powsybl.openloadflow.equations.EquationTerm; +import com.powsybl.openloadflow.equations.StateVector; +import com.powsybl.openloadflow.equations.Variable; +import com.powsybl.openloadflow.equations.VariableSet; +import com.powsybl.openloadflow.network.*; +import com.powsybl.openloadflow.network.impl.LfVscConverterStationImpl; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +/** + * @author Geoffroy Jamgotchian + */ +class AcEquationsTest { + + public static class RuntimeExceptionAnswer implements Answer { + + public Object answer(InvocationOnMock invocation) { + throw new PowsyblException(invocation.getMethod().getName() + " is not stubbed"); + } + } + + private static final RuntimeExceptionAnswer ANSWER = new RuntimeExceptionAnswer(); + + private static final double R = 5.872576933488291E-4; + private static final double X = 0.007711911135433123; + private static final double Y = 129.29521139058275; + private static final double KSI = 0.07600275710144264; + private static final double G_1 = 0.08448324029284184; + private static final double G_2 = 0.06483244848429284; + private static final double B_1 = 0.13324220618233085; + private static final double B_2 = 0.18320177723653615; + private static final double V_1 = 1.0714396912858781; + private static final double PH_1 = 0.1613653508202422; + private static final double R_1 = 0.95455; + private static final double A_1 = 0.324294234; + private static final double V_2 = 1.0718794209362505; + private static final double PH_2 = 0.18609589391040748; + private static final double B = 0.2748383993949494; + private static final double DROOP = 103.13240312354819; + private static final double P_0 = 1.9280906677246095; + private static final double LOSS_FACTOR_1 = 0.01100000023841858; + private static final double LOSS_FACTOR_2 = 0.02400453453002384; + + private static double[] eval(EquationTerm term, List> variables, + StateVector sv) { + term.setStateVector(sv); + double[] values = new double[variables.size() + 1]; + values[0] = term.eval(); + for (int i = 0; i < variables.size(); i++) { + var v = variables.get(i); + try { + values[i + 1] = term.der(v); + } catch (IllegalStateException e) { + // ignore because not supported + values[i + 1] = Double.NaN; + } + } + return values; + } + + @Test + void branchTest() { + var branch = Mockito.mock(LfBranch.class, ANSWER); + Mockito.doReturn(0).when(branch).getNum(); + PiModel piModel = Mockito.mock(PiModel.class, ANSWER); + Mockito.doReturn(piModel).when(branch).getPiModel(); + Mockito.doReturn(R).when(piModel).getR(); + Mockito.doReturn(X).when(piModel).getX(); + Mockito.doReturn(Y).when(piModel).getY(); + Mockito.doReturn(G_1).when(piModel).getG1(); + Mockito.doReturn(G_2).when(piModel).getG2(); + Mockito.doReturn(B_1).when(piModel).getB1(); + Mockito.doReturn(B_2).when(piModel).getB2(); + Mockito.doReturn(KSI).when(piModel).getKsi(); + Mockito.doReturn(R_1).when(piModel).getR1(); + + var bus1 = Mockito.mock(LfBus.class, ANSWER); + var bus2 = Mockito.mock(LfBus.class, ANSWER); + Mockito.doReturn(0).when(bus1).getNum(); + Mockito.doReturn(1).when(bus2).getNum(); + + VariableSet variableSet = new VariableSet<>(); + var v1Var = variableSet.getVariable(0, AcVariableType.BUS_V); + var ph1Var = variableSet.getVariable(0, AcVariableType.BUS_PHI); + var v2Var = variableSet.getVariable(1, AcVariableType.BUS_V); + var ph2Var = variableSet.getVariable(1, AcVariableType.BUS_PHI); + var r1Var = variableSet.getVariable(0, AcVariableType.BRANCH_RHO1); + var a1Var = variableSet.getVariable(0, AcVariableType.BRANCH_ALPHA1); + + var variables = List.of(v1Var, ph1Var, v2Var, ph2Var, r1Var, a1Var); + v1Var.setRow(0); + ph1Var.setRow(1); + v2Var.setRow(2); + ph2Var.setRow(3); + r1Var.setRow(4); + a1Var.setRow(5); + + var sv = new StateVector(new double[] {V_1, PH_1, V_2, PH_2, R_1, A_1}); + + // closed branch equations + assertArrayEquals(new double[] {41.78173051479356, 48.66261692116701, 138.21343172859858, 29.31710523088579, -138.21343172859858, 54.62161149356045, 138.21343172859858}, + eval(new ClosedBranchSide1ActiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true), variables, sv)); + assertArrayEquals(new double[] {-3.500079625302254, 122.46444997806617, 31.42440177840898, -128.9449438332101, -31.42440177840898, 137.46086897280827, 31.42440177840898}, + eval(new ClosedBranchSide1ReactiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true), variables, sv)); + assertArrayEquals(new double[] {39.13246485286217, -0.8052805161189096, 126.09926753871545, 37.31322159867258, -126.09926753871542, Double.NaN, 126.09926753871542}, + eval(new ClosedBranchSide1CurrentMagnitudeEquationTerm(branch, bus1, bus2, variableSet, true, true), variables, sv)); + assertArrayEquals(new double[] {-40.6365773800554, -48.52391742324069, -131.8614376204652, -27.319027760225953, 131.8614376204652, -54.4659275092331, -131.8614376204652}, + eval(new ClosedBranchSide2ActiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true), variables, sv)); + assertArrayEquals(new double[] {16.04980301110306, -123.06939783256767, 51.99045110393844, 152.96594042215764, -51.99045110393844, -138.1398958886022, 51.99045110393844}, + eval(new ClosedBranchSide2ReactiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true), variables, sv)); + assertArrayEquals(new double[] {40.7613721648136, -0.07246503940372644, 132.23571821183896, 38.10038077658943, -132.23571821183896, Double.NaN, -132.23571821183896}, + eval(new ClosedBranchSide2CurrentMagnitudeEquationTerm(branch, bus1, bus2, variableSet, true, true), variables, sv)); + + // open branch equations + assertArrayEquals(new double[] {0.1717595025847833, Double.NaN, Double.NaN, 0.3204828812456483, Double.NaN, Double.NaN, Double.NaN}, + eval(new OpenBranchSide1ActiveFlowEquationTerm(branch, bus2, variableSet, false, false), variables, sv)); + assertArrayEquals(new double[] {-0.36364935827807376, Double.NaN, Double.NaN, -0.6785266162875639, Double.NaN, Double.NaN, Double.NaN}, + eval(new OpenBranchSide1ReactiveFlowEquationTerm(branch, bus2, variableSet, false, false), variables, sv)); + assertArrayEquals(new double[] {0.37520249405559764, Double.NaN, Double.NaN, 0.3500416993992393, Double.NaN, Double.NaN, Double.NaN}, + eval(new OpenBranchSide1CurrentMagnitudeEquationTerm(branch, bus2, variableSet, false, false), variables, sv)); + assertArrayEquals(new double[] {0.15652310047954035, Double.NaN, Double.NaN, 0.2920535601715773, Double.NaN, Double.NaN, Double.NaN}, + eval(new OpenBranchSide2ActiveFlowEquationTerm(branch, bus2, variableSet, false, false), variables, sv)); + assertArrayEquals(new double[] {-0.331495628053771, Double.NaN, Double.NaN, -0.6185315653587614, Double.NaN, Double.NaN, Double.NaN}, + eval(new OpenBranchSide2ReactiveFlowEquationTerm(branch, bus2, variableSet, false, false), variables, sv)); + assertArrayEquals(new double[] {0.3420075216110214, Double.NaN, Double.NaN, 0.31907275662806295, Double.NaN, Double.NaN, Double.NaN}, + eval(new OpenBranchSide2CurrentMagnitudeEquationTerm(branch, bus2, variableSet, false, false), variables, sv)); + + } + + @Test + void shuntTest() { + var shunt = Mockito.mock(LfShunt.class, new RuntimeExceptionAnswer()); + Mockito.doReturn(0).when(shunt).getNum(); + + var bus = Mockito.mock(LfBus.class, ANSWER); + Mockito.doReturn(0).when(bus).getNum(); + + VariableSet variableSet = new VariableSet<>(); + var vVar = variableSet.getVariable(0, AcVariableType.BUS_V); + var bVar = variableSet.getVariable(0, AcVariableType.SHUNT_B); + + var variables = List.of(vVar, bVar); + vVar.setRow(0); + bVar.setRow(1); + + var sv = new StateVector(new double[] {V_1, B}); + + assertArrayEquals(new double[] {-0.3155098135679268, -0.588945539602459, -1.1479830120627779}, + eval(new ShuntCompensatorReactiveFlowEquationTerm(shunt, bus, variableSet, true), variables, sv)); + } + + @Test + void hvdcTest() { + var hvdc = Mockito.mock(LfHvdc.class, new RuntimeExceptionAnswer()); + Mockito.doReturn(0).when(hvdc).getNum(); + Mockito.doReturn(DROOP).when(hvdc).getDroop(); + Mockito.doReturn(P_0).when(hvdc).getP0(); + LfVscConverterStationImpl station1 = Mockito.mock(LfVscConverterStationImpl.class, new RuntimeExceptionAnswer()); + LfVscConverterStationImpl station2 = Mockito.mock(LfVscConverterStationImpl.class, new RuntimeExceptionAnswer()); + Mockito.doReturn(station1).when(hvdc).getConverterStation1(); + Mockito.doReturn(station2).when(hvdc).getConverterStation2(); + Mockito.doReturn(LOSS_FACTOR_1).when(station1).getLossFactor(); + Mockito.doReturn(LOSS_FACTOR_2).when(station2).getLossFactor(); + + var bus1 = Mockito.mock(LfBus.class, ANSWER); + var bus2 = Mockito.mock(LfBus.class, ANSWER); + Mockito.doReturn(0).when(bus1).getNum(); + Mockito.doReturn(1).when(bus2).getNum(); + + VariableSet variableSet = new VariableSet<>(); + var hvdcPh1Var = variableSet.getVariable(0, AcVariableType.BUS_PHI); + var hvdcPh2Var = variableSet.getVariable(1, AcVariableType.BUS_PHI); + + var variables = List.of(hvdcPh1Var, hvdcPh2Var); + hvdcPh1Var.setRow(0); + hvdcPh2Var.setRow(1); + + var sv = new StateVector(new double[] {PH_1, PH_2}); + + assertArrayEquals(new double[] {-144.1554855266458, 5906.983150087268, -5906.983150087268}, + eval(new HvdcAcEmulationSide1ActiveFlowEquationTerm(hvdc, bus1, bus2, variableSet), variables, sv)); + assertArrayEquals(new double[] {144.20596034441598, -5909.051430021139, 5909.051430021139}, + eval(new HvdcAcEmulationSide2ActiveFlowEquationTerm(hvdc, bus1, bus2, variableSet), variables, sv)); + } +} From 62d9b159a4acfcb553d021fe298dfc8c5c3a63bd Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Sun, 5 Jun 2022 21:57:21 +0200 Subject: [PATCH 05/15] Fix LfVscConverterStationImpl design (#546) Signed-off-by: Geoffroy Jamgotchian --- .../powsybl/openloadflow/network/LfHvdc.java | 9 ++++--- .../network/LfVscConverterStation.java | 15 ++++++++++++ .../openloadflow/network/impl/LfHvdcImpl.java | 24 +++++++++---------- .../impl/LfVscConverterStationImpl.java | 6 +++-- 4 files changed, 35 insertions(+), 19 deletions(-) create mode 100644 src/main/java/com/powsybl/openloadflow/network/LfVscConverterStation.java diff --git a/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java b/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java index 50b81afd20..5151becf1f 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfHvdc.java @@ -6,7 +6,6 @@ */ package com.powsybl.openloadflow.network; -import com.powsybl.openloadflow.network.impl.LfVscConverterStationImpl; import com.powsybl.openloadflow.util.Evaluable; /** @@ -30,13 +29,13 @@ public interface LfHvdc extends LfElement { double getP0(); - LfVscConverterStationImpl getConverterStation1(); + LfVscConverterStation getConverterStation1(); - LfVscConverterStationImpl getConverterStation2(); + LfVscConverterStation getConverterStation2(); - void setConverterStation1(LfVscConverterStationImpl converterStation1); + void setConverterStation1(LfVscConverterStation converterStation1); - void setConverterStation2(LfVscConverterStationImpl converterStation2); + void setConverterStation2(LfVscConverterStation converterStation2); void updateState(); } diff --git a/src/main/java/com/powsybl/openloadflow/network/LfVscConverterStation.java b/src/main/java/com/powsybl/openloadflow/network/LfVscConverterStation.java new file mode 100644 index 0000000000..7ec49f135e --- /dev/null +++ b/src/main/java/com/powsybl/openloadflow/network/LfVscConverterStation.java @@ -0,0 +1,15 @@ +/** + * Copyright (c) 2022, 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/. + */ +package com.powsybl.openloadflow.network; + +/** + * @author Geoffroy Jamgotchian + */ +public interface LfVscConverterStation extends LfGenerator { + + double getLossFactor(); +} diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java index 13fd7d8429..4aa546bf1a 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfHvdcImpl.java @@ -34,9 +34,9 @@ public class LfHvdcImpl extends AbstractElement implements LfHvdc { private final double p0; - private LfVscConverterStationImpl vsc1; + private LfVscConverterStation converterStation1; - private LfVscConverterStationImpl vsc2; + private LfVscConverterStation converterStation2; public LfHvdcImpl(String id, LfBus bus1, LfBus bus2, LfNetwork network, HvdcAngleDroopActivePowerControl control) { super(network); @@ -99,31 +99,31 @@ public double getP0() { } @Override - public LfVscConverterStationImpl getConverterStation1() { - return vsc1; + public LfVscConverterStation getConverterStation1() { + return converterStation1; } @Override - public LfVscConverterStationImpl getConverterStation2() { - return vsc2; + public LfVscConverterStation getConverterStation2() { + return converterStation2; } @Override - public void setConverterStation1(LfVscConverterStationImpl converterStation1) { - this.vsc1 = converterStation1; + public void setConverterStation1(LfVscConverterStation converterStation1) { + this.converterStation1 = Objects.requireNonNull(converterStation1); converterStation1.setTargetP(0); } @Override - public void setConverterStation2(LfVscConverterStationImpl converterStation2) { - this.vsc2 = converterStation2; + public void setConverterStation2(LfVscConverterStation converterStation2) { + this.converterStation2 = Objects.requireNonNull(converterStation2); converterStation2.setTargetP(0); } @Override public void updateState() { // Should be done before updating state of generators. - vsc1.setTargetP(-p1.eval()); - vsc2.setTargetP(-p2.eval()); + converterStation1.setTargetP(-p1.eval()); + converterStation2.setTargetP(-p2.eval()); } } diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfVscConverterStationImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfVscConverterStationImpl.java index 18c06b37d4..00c5f95dc1 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfVscConverterStationImpl.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfVscConverterStationImpl.java @@ -7,6 +7,7 @@ package com.powsybl.openloadflow.network.impl; import com.powsybl.iidm.network.*; +import com.powsybl.openloadflow.network.LfVscConverterStation; import com.powsybl.openloadflow.util.PerUnit; import java.util.Objects; @@ -15,11 +16,11 @@ /** * @author Geoffroy Jamgotchian */ -public class LfVscConverterStationImpl extends AbstractLfGenerator { +public class LfVscConverterStationImpl extends AbstractLfGenerator implements LfVscConverterStation { private final VscConverterStation station; - private double lossFactor; + private final double lossFactor; public LfVscConverterStationImpl(VscConverterStation station, boolean breakers, boolean reactiveLimits, LfNetworkLoadingReport report) { super(HvdcConverterStations.getConverterStationTargetP(station)); @@ -37,6 +38,7 @@ public static LfVscConverterStationImpl create(VscConverterStation station, bool return new LfVscConverterStationImpl(station, breakers, reactiveLimits, report); } + @Override public double getLossFactor() { return lossFactor; } From b1cc04d68d1f38755ec6fad6939803c7ebb930cb Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Mon, 6 Jun 2022 11:58:35 +0200 Subject: [PATCH 06/15] Add unit test for sensi value non regression (#548) Signed-off-by: Geoffroy Jamgotchian --- .../openloadflow/ac/AcEquationsTest.java | 52 +++++++++++++------ 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/src/test/java/com/powsybl/openloadflow/ac/AcEquationsTest.java b/src/test/java/com/powsybl/openloadflow/ac/AcEquationsTest.java index e363c743cf..232be3a476 100644 --- a/src/test/java/com/powsybl/openloadflow/ac/AcEquationsTest.java +++ b/src/test/java/com/powsybl/openloadflow/ac/AcEquationsTest.java @@ -7,6 +7,7 @@ package com.powsybl.openloadflow.ac; import com.powsybl.commons.PowsyblException; +import com.powsybl.math.matrix.DenseMatrix; import com.powsybl.openloadflow.ac.equations.*; import com.powsybl.openloadflow.equations.EquationTerm; import com.powsybl.openloadflow.equations.StateVector; @@ -19,6 +20,7 @@ import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import java.util.Arrays; import java.util.List; import static org.junit.jupiter.api.Assertions.assertArrayEquals; @@ -60,17 +62,33 @@ public Object answer(InvocationOnMock invocation) { private static double[] eval(EquationTerm term, List> variables, StateVector sv) { term.setStateVector(sv); - double[] values = new double[variables.size() + 1]; + double[] values = new double[variables.size() + 2]; + + // equation value values[0] = term.eval(); + + // all derivative values for (int i = 0; i < variables.size(); i++) { var v = variables.get(i); try { values[i + 1] = term.der(v); } catch (IllegalStateException e) { - // ignore because not supported + // not supported values[i + 1] = Double.NaN; } } + + // sensitivity value + double[] one = new double[values.length]; + Arrays.fill(one, 1); + DenseMatrix dx = new DenseMatrix(values.length, 1, one); + try { + values[values.length - 1] = term.calculateSensi(dx, 0); + } catch (UnsupportedOperationException e) { + // not supported + values[values.length - 1] = Double.NaN; + } + return values; } @@ -114,31 +132,31 @@ void branchTest() { var sv = new StateVector(new double[] {V_1, PH_1, V_2, PH_2, R_1, A_1}); // closed branch equations - assertArrayEquals(new double[] {41.78173051479356, 48.66261692116701, 138.21343172859858, 29.31710523088579, -138.21343172859858, 54.62161149356045, 138.21343172859858}, + assertArrayEquals(new double[] {41.78173051479356, 48.66261692116701, 138.21343172859858, 29.31710523088579, -138.21343172859858, 54.62161149356045, 138.21343172859858, 77.9797221520528}, eval(new ClosedBranchSide1ActiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true), variables, sv)); - assertArrayEquals(new double[] {-3.500079625302254, 122.46444997806617, 31.42440177840898, -128.9449438332101, -31.42440177840898, 137.46086897280827, 31.42440177840898}, + assertArrayEquals(new double[] {-3.500079625302254, 122.46444997806617, 31.42440177840898, -128.9449438332101, -31.42440177840898, 137.46086897280827, 31.42440177840898, -6.480493855143919}, eval(new ClosedBranchSide1ReactiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true), variables, sv)); - assertArrayEquals(new double[] {39.13246485286217, -0.8052805161189096, 126.09926753871545, 37.31322159867258, -126.09926753871542, Double.NaN, 126.09926753871542}, + assertArrayEquals(new double[] {39.13246485286217, -0.8052805161189096, 126.09926753871545, 37.31322159867258, -126.09926753871542, Double.NaN, 126.09926753871542, 36.50794108255369}, eval(new ClosedBranchSide1CurrentMagnitudeEquationTerm(branch, bus1, bus2, variableSet, true, true), variables, sv)); - assertArrayEquals(new double[] {-40.6365773800554, -48.52391742324069, -131.8614376204652, -27.319027760225953, 131.8614376204652, -54.4659275092331, -131.8614376204652}, + assertArrayEquals(new double[] {-40.6365773800554, -48.52391742324069, -131.8614376204652, -27.319027760225953, 131.8614376204652, -54.4659275092331, -131.8614376204652, -75.84294518346664}, eval(new ClosedBranchSide2ActiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true), variables, sv)); - assertArrayEquals(new double[] {16.04980301110306, -123.06939783256767, 51.99045110393844, 152.96594042215764, -51.99045110393844, -138.1398958886022, 51.99045110393844}, + assertArrayEquals(new double[] {16.04980301110306, -123.06939783256767, 51.99045110393844, 152.96594042215764, -51.99045110393844, -138.1398958886022, 51.99045110393844, 29.89654258958997}, eval(new ClosedBranchSide2ReactiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true), variables, sv)); - assertArrayEquals(new double[] {40.7613721648136, -0.07246503940372644, 132.23571821183896, 38.10038077658943, -132.23571821183896, Double.NaN, -132.23571821183896}, + assertArrayEquals(new double[] {40.7613721648136, -0.07246503940372644, 132.23571821183896, 38.10038077658943, -132.23571821183896, Double.NaN, -132.23571821183896, 38.02791573718571}, eval(new ClosedBranchSide2CurrentMagnitudeEquationTerm(branch, bus1, bus2, variableSet, true, true), variables, sv)); // open branch equations - assertArrayEquals(new double[] {0.1717595025847833, Double.NaN, Double.NaN, 0.3204828812456483, Double.NaN, Double.NaN, Double.NaN}, + assertArrayEquals(new double[] {0.1717595025847833, Double.NaN, Double.NaN, 0.3204828812456483, Double.NaN, Double.NaN, Double.NaN, Double.NaN}, eval(new OpenBranchSide1ActiveFlowEquationTerm(branch, bus2, variableSet, false, false), variables, sv)); - assertArrayEquals(new double[] {-0.36364935827807376, Double.NaN, Double.NaN, -0.6785266162875639, Double.NaN, Double.NaN, Double.NaN}, + assertArrayEquals(new double[] {-0.36364935827807376, Double.NaN, Double.NaN, -0.6785266162875639, Double.NaN, Double.NaN, Double.NaN, Double.NaN}, eval(new OpenBranchSide1ReactiveFlowEquationTerm(branch, bus2, variableSet, false, false), variables, sv)); - assertArrayEquals(new double[] {0.37520249405559764, Double.NaN, Double.NaN, 0.3500416993992393, Double.NaN, Double.NaN, Double.NaN}, + assertArrayEquals(new double[] {0.37520249405559764, Double.NaN, Double.NaN, 0.3500416993992393, Double.NaN, Double.NaN, Double.NaN, Double.NaN}, eval(new OpenBranchSide1CurrentMagnitudeEquationTerm(branch, bus2, variableSet, false, false), variables, sv)); - assertArrayEquals(new double[] {0.15652310047954035, Double.NaN, Double.NaN, 0.2920535601715773, Double.NaN, Double.NaN, Double.NaN}, + assertArrayEquals(new double[] {0.15652310047954035, Double.NaN, Double.NaN, 0.2920535601715773, Double.NaN, Double.NaN, Double.NaN, Double.NaN}, eval(new OpenBranchSide2ActiveFlowEquationTerm(branch, bus2, variableSet, false, false), variables, sv)); - assertArrayEquals(new double[] {-0.331495628053771, Double.NaN, Double.NaN, -0.6185315653587614, Double.NaN, Double.NaN, Double.NaN}, + assertArrayEquals(new double[] {-0.331495628053771, Double.NaN, Double.NaN, -0.6185315653587614, Double.NaN, Double.NaN, Double.NaN, Double.NaN}, eval(new OpenBranchSide2ReactiveFlowEquationTerm(branch, bus2, variableSet, false, false), variables, sv)); - assertArrayEquals(new double[] {0.3420075216110214, Double.NaN, Double.NaN, 0.31907275662806295, Double.NaN, Double.NaN, Double.NaN}, + assertArrayEquals(new double[] {0.3420075216110214, Double.NaN, Double.NaN, 0.31907275662806295, Double.NaN, Double.NaN, Double.NaN, Double.NaN}, eval(new OpenBranchSide2CurrentMagnitudeEquationTerm(branch, bus2, variableSet, false, false), variables, sv)); } @@ -161,7 +179,7 @@ void shuntTest() { var sv = new StateVector(new double[] {V_1, B}); - assertArrayEquals(new double[] {-0.3155098135679268, -0.588945539602459, -1.1479830120627779}, + assertArrayEquals(new double[] {-0.3155098135679268, -0.588945539602459, -1.1479830120627779, Double.NaN}, eval(new ShuntCompensatorReactiveFlowEquationTerm(shunt, bus, variableSet, true), variables, sv)); } @@ -193,9 +211,9 @@ void hvdcTest() { var sv = new StateVector(new double[] {PH_1, PH_2}); - assertArrayEquals(new double[] {-144.1554855266458, 5906.983150087268, -5906.983150087268}, + assertArrayEquals(new double[] {-144.1554855266458, 5906.983150087268, -5906.983150087268, Double.NaN}, eval(new HvdcAcEmulationSide1ActiveFlowEquationTerm(hvdc, bus1, bus2, variableSet), variables, sv)); - assertArrayEquals(new double[] {144.20596034441598, -5909.051430021139, 5909.051430021139}, + assertArrayEquals(new double[] {144.20596034441598, -5909.051430021139, 5909.051430021139, Double.NaN}, eval(new HvdcAcEmulationSide2ActiveFlowEquationTerm(hvdc, bus1, bus2, variableSet), variables, sv)); } } From b4dccb8c04ab96462495b551d7638ff2a544024f Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Tue, 7 Jun 2022 08:16:03 +0200 Subject: [PATCH 07/15] Replace p0 and q0 of batteries by targetP and targetQ (#547) Signed-off-by: Geoffroy Jamgotchian --- .../powsybl/openloadflow/network/impl/LfBatteryImpl.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/LfBatteryImpl.java b/src/main/java/com/powsybl/openloadflow/network/impl/LfBatteryImpl.java index 744db9332b..5ec0367f03 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/LfBatteryImpl.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/LfBatteryImpl.java @@ -26,7 +26,7 @@ public final class LfBatteryImpl extends AbstractLfGenerator { private double droop; private LfBatteryImpl(Battery battery, double plausibleActivePowerLimit, LfNetworkLoadingReport report) { - super(battery.getP0()); + super(battery.getTargetP()); this.battery = battery; participating = true; droop = DEFAULT_DROOP; @@ -39,7 +39,7 @@ private LfBatteryImpl(Battery battery, double plausibleActivePowerLimit, LfNetwo } } - if (!checkActivePowerControl(battery.getP0(), battery.getMinP(), battery.getMaxP(), plausibleActivePowerLimit, report)) { + if (!checkActivePowerControl(battery.getTargetP(), battery.getMinP(), battery.getMaxP(), plausibleActivePowerLimit, report)) { participating = false; } } @@ -57,7 +57,7 @@ public String getId() { @Override public double getTargetQ() { - return battery.getQ0() / PerUnit.SB; + return battery.getTargetQ() / PerUnit.SB; } @Override @@ -94,6 +94,6 @@ public double getDroop() { public void updateState() { battery.getTerminal() .setP(-targetP) - .setQ(-battery.getQ0()); + .setQ(-battery.getTargetQ()); } } From e3eb55b477fb18f8c90574cf6c7a0bff06fcd04c Mon Sep 17 00:00:00 2001 From: Hadrien Date: Tue, 7 Jun 2022 10:32:31 +0200 Subject: [PATCH 08/15] Check current for pre-contingency results Signed-off-by: Hadrien --- .../openloadflow/sa/DcSecurityAnalysis.java | 20 +++++++++++++++---- .../sa/OpenSecurityAnalysisTest.java | 11 +++++----- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java index 06d06762c7..ff2e5c8413 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java @@ -71,7 +71,7 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete preContingencyBranchResults.put(branchId, new BranchResult(branchId, sensValue.getFunctionReference(), Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN)); detector.checkActivePower(branch, Branch.Side.ONE, Math.abs(sensValue.getFunctionReference()), violation -> preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); - checkDcCurrent(branch, Math.abs(sensValue.getFunctionReference())); + checkDcCurrent(branch, Math.abs(sensValue.getFunctionReference()), preContingencyLimitViolationsMap); } LimitViolationsResult preContingencyResult = new LimitViolationsResult(true, @@ -112,12 +112,24 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete return new SecurityAnalysisReport(new SecurityAnalysisResult(preContingencyResult, postContingencyResults, new ArrayList<>(preContingencyBranchResults.values()), Collections.emptyList(), Collections.emptyList())); } - private void checkDcCurrent(Branch branch, double activePower) { - // Check side 1 + private void checkDcCurrent(Branch branch, double activePower, Map, LimitViolation> preContingencyLimitViolationsMap) { // TODO: get cosphi from parameters - double branchCurrent = currentFromAdnActivePower(activePower, branch.getTerminal1().getVoltageLevel().getNominalV(), 0.4); + double cosPhi = Math.cos(Math.atan(0.4)); + // Permanent limits + // Check side 1 + double branchCurrent1 = currentFromAdnActivePower(activePower, branch.getTerminal1().getVoltageLevel().getNominalV(), cosPhi); + if (branchCurrent1 > branch.getCurrentLimits1().getPermanentLimit()) { + LimitViolation violation = new LimitViolation(branch.getId(), LimitViolationType.CURRENT, "Current_Violation_1_" + branch.getId(), 2147483647, branch.getCurrentLimits1().getPermanentLimit(), 0, branchCurrent1, Branch.Side.ONE); + preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation); + } // Check side 2 + double branchCurrent2 = currentFromAdnActivePower(activePower, branch.getTerminal2().getVoltageLevel().getNominalV(), cosPhi); + if (branchCurrent2 > branch.getCurrentLimits2().getPermanentLimit()) { + LimitViolation violation = new LimitViolation(branch.getId(), LimitViolationType.CURRENT, "Current_Violation_2_" + branch.getId(), 2147483647, branch.getCurrentLimits2().getPermanentLimit(), 0, branchCurrent2, Branch.Side.TWO); + preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation); + } + // TODO: temporary limits } public static double currentFromAdnActivePower(double activePower, double dcVoltage, double cosPhi) { diff --git a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java index 38e93ea89f..9159688b35 100644 --- a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java +++ b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java @@ -1533,11 +1533,11 @@ void testDcCurrentLimitViolations() { List contingencies = allBranches(fourBusNetwork); - fourBusNetwork.getLine("l14").newCurrentLimits1().setPermanentLimit(0.1).add(); - fourBusNetwork.getLine("l12").newCurrentLimits1().setPermanentLimit(0.2).add(); - fourBusNetwork.getLine("l23").newCurrentLimits2().setPermanentLimit(0.25).add(); - fourBusNetwork.getLine("l34").newCurrentLimits1().setPermanentLimit(0.15).add(); - fourBusNetwork.getLine("l13").newCurrentLimits2().setPermanentLimit(0.1).add(); + fourBusNetwork.getLine("l14").newCurrentLimits1().setPermanentLimit(62.2).add(); + fourBusNetwork.getLine("l12").newCurrentLimits1().setPermanentLimit(124.4).add(); + fourBusNetwork.getLine("l23").newCurrentLimits2().setPermanentLimit(155.5).add(); + fourBusNetwork.getLine("l34").newCurrentLimits1().setPermanentLimit(93.3).add(); + fourBusNetwork.getLine("l13").newCurrentLimits2().setPermanentLimit(62.2).add(); List monitors = List.of(new StateMonitor(ContingencyContext.all(), Set.of("l14", "l12", "l23", "l34", "l13"), Collections.emptySet(), Collections.emptySet())); @@ -1552,5 +1552,4 @@ void testDcCurrentLimitViolations() { assertEquals(4, result.getPostContingencyResults().get(3).getLimitViolationsResult().getLimitViolations().size()); assertEquals(4, result.getPostContingencyResults().get(4).getLimitViolationsResult().getLimitViolations().size()); } - } From 00248c203b7401983259859ffd0cd3267782e380 Mon Sep 17 00:00:00 2001 From: Hadrien Date: Tue, 7 Jun 2022 11:20:29 +0200 Subject: [PATCH 09/15] Test is ok Signed-off-by: Hadrien --- .../openloadflow/sa/DcSecurityAnalysis.java | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java index ff2e5c8413..ca95d50326 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java @@ -99,6 +99,7 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete } detector.checkActivePower(branch, Branch.Side.ONE, Math.abs(v.getFunctionReference()), violation -> violations.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); + checkDcCurrent(branch, Math.abs(v.getFunctionReference()), violations); } preContingencyLimitViolationsMap.forEach((subjectSideId, preContingencyViolation) -> { LimitViolation postContingencyViolation = violations.get(subjectSideId); @@ -117,17 +118,25 @@ private void checkDcCurrent(Branch branch, double activePower, Map branch.getCurrentLimits1().getPermanentLimit()) { - LimitViolation violation = new LimitViolation(branch.getId(), LimitViolationType.CURRENT, "Current_Violation_1_" + branch.getId(), 2147483647, branch.getCurrentLimits1().getPermanentLimit(), 0, branchCurrent1, Branch.Side.ONE); - preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation); + try { + double permanentLimit1 = branch.getCurrentLimits1().getPermanentLimit(); + double branchCurrent1 = currentFromAdnActivePower(activePower, branch.getTerminal1().getVoltageLevel().getNominalV(), cosPhi); + if (branchCurrent1 > permanentLimit1) { + LimitViolation violation = new LimitViolation(branch.getId(), LimitViolationType.CURRENT, "Current_Permanent_Limit_Violation_1_" + branch.getId(), 2147483647, permanentLimit1, 1, branchCurrent1, Branch.Side.ONE); + preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation); + } + } catch (NullPointerException ignored) { } // Check side 2 - double branchCurrent2 = currentFromAdnActivePower(activePower, branch.getTerminal2().getVoltageLevel().getNominalV(), cosPhi); - if (branchCurrent2 > branch.getCurrentLimits2().getPermanentLimit()) { - LimitViolation violation = new LimitViolation(branch.getId(), LimitViolationType.CURRENT, "Current_Violation_2_" + branch.getId(), 2147483647, branch.getCurrentLimits2().getPermanentLimit(), 0, branchCurrent2, Branch.Side.TWO); - preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation); + try { + double permanentLimit2 = branch.getCurrentLimits2().getPermanentLimit(); + double branchCurrent2 = currentFromAdnActivePower(activePower, branch.getTerminal2().getVoltageLevel().getNominalV(), cosPhi); + if (branchCurrent2 > permanentLimit2) { + LimitViolation violation = new LimitViolation(branch.getId(), LimitViolationType.CURRENT, "Current_Permanent_Limit_Violation_2_" + branch.getId(), 2147483647, permanentLimit2, 1, branchCurrent2, Branch.Side.TWO); + preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation); + } + } catch (NullPointerException ignored) { } // TODO: temporary limits } From 823872d067cdc600ac6399848ef93f5106cd6d2f Mon Sep 17 00:00:00 2001 From: Hadrien Date: Tue, 7 Jun 2022 14:48:48 +0200 Subject: [PATCH 10/15] Refactoring and test for temporary limits Signed-off-by: Hadrien --- .../openloadflow/sa/DcSecurityAnalysis.java | 41 +++++------------ .../sa/OpenSecurityAnalysisTest.java | 44 ++++++++++++++++--- 2 files changed, 49 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java index ca95d50326..81ac592cc1 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java @@ -63,6 +63,9 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete StateMonitor monitor = monitorIndex.getAllStateMonitor(); Map preContingencyBranchResults = new HashMap<>(); + // CosPhi for DC power to current conversion + double cosPhi = Math.cos(Math.atan(0.4)); + Map, LimitViolation> preContingencyLimitViolationsMap = new HashMap<>(); for (SensitivityValue sensValue : res.getValues(null)) { SensitivityFactor factor = factors.get(sensValue.getFactorIndex()); @@ -71,7 +74,10 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete preContingencyBranchResults.put(branchId, new BranchResult(branchId, sensValue.getFunctionReference(), Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN)); detector.checkActivePower(branch, Branch.Side.ONE, Math.abs(sensValue.getFunctionReference()), violation -> preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); - checkDcCurrent(branch, Math.abs(sensValue.getFunctionReference()), preContingencyLimitViolationsMap); + detector.checkCurrent(branch, Branch.Side.ONE, currentFromAdnActivePower(Math.abs(sensValue.getFunctionReference()), branch.getTerminal1().getVoltageLevel().getNominalV(), cosPhi), + violation -> preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); + detector.checkCurrent(branch, Branch.Side.TWO, currentFromAdnActivePower(Math.abs(sensValue.getFunctionReference()), branch.getTerminal2().getVoltageLevel().getNominalV(), cosPhi), + violation -> preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); } LimitViolationsResult preContingencyResult = new LimitViolationsResult(true, @@ -99,7 +105,10 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete } detector.checkActivePower(branch, Branch.Side.ONE, Math.abs(v.getFunctionReference()), violation -> violations.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); - checkDcCurrent(branch, Math.abs(v.getFunctionReference()), violations); + detector.checkCurrent(branch, Branch.Side.ONE, currentFromAdnActivePower(Math.abs(v.getFunctionReference()), branch.getTerminal1().getVoltageLevel().getNominalV(), cosPhi), + violation -> violations.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); + detector.checkCurrent(branch, Branch.Side.TWO, currentFromAdnActivePower(Math.abs(v.getFunctionReference()), branch.getTerminal2().getVoltageLevel().getNominalV(), cosPhi), + violation -> violations.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); } preContingencyLimitViolationsMap.forEach((subjectSideId, preContingencyViolation) -> { LimitViolation postContingencyViolation = violations.get(subjectSideId); @@ -113,34 +122,6 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete return new SecurityAnalysisReport(new SecurityAnalysisResult(preContingencyResult, postContingencyResults, new ArrayList<>(preContingencyBranchResults.values()), Collections.emptyList(), Collections.emptyList())); } - private void checkDcCurrent(Branch branch, double activePower, Map, LimitViolation> preContingencyLimitViolationsMap) { - // TODO: get cosphi from parameters - double cosPhi = Math.cos(Math.atan(0.4)); - // Permanent limits - // Check side 1 - try { - double permanentLimit1 = branch.getCurrentLimits1().getPermanentLimit(); - double branchCurrent1 = currentFromAdnActivePower(activePower, branch.getTerminal1().getVoltageLevel().getNominalV(), cosPhi); - if (branchCurrent1 > permanentLimit1) { - LimitViolation violation = new LimitViolation(branch.getId(), LimitViolationType.CURRENT, "Current_Permanent_Limit_Violation_1_" + branch.getId(), 2147483647, permanentLimit1, 1, branchCurrent1, Branch.Side.ONE); - preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation); - } - } catch (NullPointerException ignored) { - } - - // Check side 2 - try { - double permanentLimit2 = branch.getCurrentLimits2().getPermanentLimit(); - double branchCurrent2 = currentFromAdnActivePower(activePower, branch.getTerminal2().getVoltageLevel().getNominalV(), cosPhi); - if (branchCurrent2 > permanentLimit2) { - LimitViolation violation = new LimitViolation(branch.getId(), LimitViolationType.CURRENT, "Current_Permanent_Limit_Violation_2_" + branch.getId(), 2147483647, permanentLimit2, 1, branchCurrent2, Branch.Side.TWO); - preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation); - } - } catch (NullPointerException ignored) { - } - // TODO: temporary limits - } - public static double currentFromAdnActivePower(double activePower, double dcVoltage, double cosPhi) { return 1000 * activePower / (Math.sqrt(3) * cosPhi * dcVoltage); } diff --git a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java index 9159688b35..109a4fcec3 100644 --- a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java +++ b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java @@ -1523,7 +1523,7 @@ void testSwitchLoopIssue() { } @Test - void testDcCurrentLimitViolations() { + void testDcPermanentCurrentLimitViolations() { Network fourBusNetwork = FourBusNetworkFactory.create(); SecurityAnalysisParameters securityAnalysisParameters = new SecurityAnalysisParameters(); LoadFlowParameters lfParameters = new LoadFlowParameters() @@ -1533,11 +1533,11 @@ void testDcCurrentLimitViolations() { List contingencies = allBranches(fourBusNetwork); - fourBusNetwork.getLine("l14").newCurrentLimits1().setPermanentLimit(62.2).add(); - fourBusNetwork.getLine("l12").newCurrentLimits1().setPermanentLimit(124.4).add(); - fourBusNetwork.getLine("l23").newCurrentLimits2().setPermanentLimit(155.5).add(); - fourBusNetwork.getLine("l34").newCurrentLimits1().setPermanentLimit(93.3).add(); - fourBusNetwork.getLine("l13").newCurrentLimits2().setPermanentLimit(62.2).add(); + fourBusNetwork.getLine("l14").newCurrentLimits1().setPermanentLimit(60.0).add(); + fourBusNetwork.getLine("l12").newCurrentLimits1().setPermanentLimit(120.0).add(); + fourBusNetwork.getLine("l23").newCurrentLimits2().setPermanentLimit(150.0).add(); + fourBusNetwork.getLine("l34").newCurrentLimits1().setPermanentLimit(90.0).add(); + fourBusNetwork.getLine("l13").newCurrentLimits2().setPermanentLimit(60.0).add(); List monitors = List.of(new StateMonitor(ContingencyContext.all(), Set.of("l14", "l12", "l23", "l34", "l13"), Collections.emptySet(), Collections.emptySet())); @@ -1552,4 +1552,36 @@ void testDcCurrentLimitViolations() { assertEquals(4, result.getPostContingencyResults().get(3).getLimitViolationsResult().getLimitViolations().size()); assertEquals(4, result.getPostContingencyResults().get(4).getLimitViolationsResult().getLimitViolations().size()); } + + @Test + void testDcTemporaryCurrentLimitViolations() { + Network fourBusNetwork = FourBusNetworkFactory.create(); + SecurityAnalysisParameters securityAnalysisParameters = new SecurityAnalysisParameters(); + LoadFlowParameters lfParameters = new LoadFlowParameters() + .setDc(true); + setSlackBusId(lfParameters, "b1_vl_0"); + securityAnalysisParameters.setLoadFlowParameters(lfParameters); + + List contingencies = allBranches(fourBusNetwork); + + fourBusNetwork.getLine("l14").newCurrentLimits1().beginTemporaryLimit().setName("60").setAcceptableDuration(60).setValue(60.0).endTemporaryLimit().add(); + fourBusNetwork.getLine("l12").newCurrentLimits1().beginTemporaryLimit().setName("60").setAcceptableDuration(60).setValue(120.0).endTemporaryLimit().add(); + fourBusNetwork.getLine("l23").newCurrentLimits2().beginTemporaryLimit().setName("60").setAcceptableDuration(60).setValue(150.0).endTemporaryLimit().add(); + fourBusNetwork.getLine("l34").newCurrentLimits1().beginTemporaryLimit().setName("60").setAcceptableDuration(60).setValue(90.0).endTemporaryLimit().add(); + fourBusNetwork.getLine("l13").newCurrentLimits2().beginTemporaryLimit().setName("60").setAcceptableDuration(60).setValue(60.0).endTemporaryLimit().add(); + + List monitors = List.of(new StateMonitor(ContingencyContext.all(), Set.of("l14", "l12", "l23", "l34", "l13"), Collections.emptySet(), Collections.emptySet())); + + SecurityAnalysisResult result = runSecurityAnalysis(fourBusNetwork, contingencies, monitors, securityAnalysisParameters); + + assertTrue(result.getPreContingencyResult().getLimitViolationsResult().isComputationOk()); + // FIXME: temporary limits are not detected + //assertEquals(5, result.getPreContingencyResult().getLimitViolationsResult().getLimitViolations().size()); + //assertEquals(5, result.getPostContingencyResults().size()); + //assertEquals(2, result.getPostContingencyResults().get(0).getLimitViolationsResult().getLimitViolations().size()); + //assertEquals(2, result.getPostContingencyResults().get(1).getLimitViolationsResult().getLimitViolations().size()); + //assertEquals(4, result.getPostContingencyResults().get(2).getLimitViolationsResult().getLimitViolations().size()); + //assertEquals(4, result.getPostContingencyResults().get(3).getLimitViolationsResult().getLimitViolations().size()); + //assertEquals(4, result.getPostContingencyResults().get(4).getLimitViolationsResult().getLimitViolations().size()); + } } From 75cb5a2b67bff9bbd5b6c7056887511568b50229 Mon Sep 17 00:00:00 2001 From: Anne Tilloy Date: Tue, 7 Jun 2022 17:40:00 +0200 Subject: [PATCH 11/15] Fix test. Signed-off-by: Anne Tilloy --- .../openloadflow/sa/DcSecurityAnalysis.java | 12 ++-- .../sa/OpenSecurityAnalysisTest.java | 66 ++++++++++++------- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java index 81ac592cc1..ca44508180 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java @@ -74,9 +74,9 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete preContingencyBranchResults.put(branchId, new BranchResult(branchId, sensValue.getFunctionReference(), Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN)); detector.checkActivePower(branch, Branch.Side.ONE, Math.abs(sensValue.getFunctionReference()), violation -> preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); - detector.checkCurrent(branch, Branch.Side.ONE, currentFromAdnActivePower(Math.abs(sensValue.getFunctionReference()), branch.getTerminal1().getVoltageLevel().getNominalV(), cosPhi), + detector.checkCurrent(branch, Branch.Side.ONE, currentActivePower(Math.abs(sensValue.getFunctionReference()), branch.getTerminal1().getVoltageLevel().getNominalV(), cosPhi), violation -> preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); - detector.checkCurrent(branch, Branch.Side.TWO, currentFromAdnActivePower(Math.abs(sensValue.getFunctionReference()), branch.getTerminal2().getVoltageLevel().getNominalV(), cosPhi), + detector.checkCurrent(branch, Branch.Side.TWO, currentActivePower(Math.abs(sensValue.getFunctionReference()), branch.getTerminal2().getVoltageLevel().getNominalV(), cosPhi), violation -> preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); } @@ -105,9 +105,9 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete } detector.checkActivePower(branch, Branch.Side.ONE, Math.abs(v.getFunctionReference()), violation -> violations.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); - detector.checkCurrent(branch, Branch.Side.ONE, currentFromAdnActivePower(Math.abs(v.getFunctionReference()), branch.getTerminal1().getVoltageLevel().getNominalV(), cosPhi), + detector.checkCurrent(branch, Branch.Side.ONE, currentActivePower(Math.abs(v.getFunctionReference()), branch.getTerminal1().getVoltageLevel().getNominalV(), cosPhi), violation -> violations.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); - detector.checkCurrent(branch, Branch.Side.TWO, currentFromAdnActivePower(Math.abs(v.getFunctionReference()), branch.getTerminal2().getVoltageLevel().getNominalV(), cosPhi), + detector.checkCurrent(branch, Branch.Side.TWO, currentActivePower(Math.abs(v.getFunctionReference()), branch.getTerminal2().getVoltageLevel().getNominalV(), cosPhi), violation -> violations.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); } preContingencyLimitViolationsMap.forEach((subjectSideId, preContingencyViolation) -> { @@ -122,7 +122,7 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete return new SecurityAnalysisReport(new SecurityAnalysisResult(preContingencyResult, postContingencyResults, new ArrayList<>(preContingencyBranchResults.values()), Collections.emptyList(), Collections.emptyList())); } - public static double currentFromAdnActivePower(double activePower, double dcVoltage, double cosPhi) { - return 1000 * activePower / (Math.sqrt(3) * cosPhi * dcVoltage); + public static double currentActivePower(double activePower, double voltage, double cosPhi) { + return 1000 * activePower / (Math.sqrt(3) * cosPhi * voltage); } } diff --git a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java index 109a4fcec3..5b983180d4 100644 --- a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java +++ b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java @@ -7,6 +7,8 @@ package com.powsybl.openloadflow.sa; import com.powsybl.commons.PowsyblException; +import com.powsybl.commons.io.table.AsciiTableFormatterFactory; +import com.powsybl.commons.io.table.TableFormatterConfig; import com.powsybl.commons.reporter.Reporter; import com.powsybl.computation.ComputationManager; import com.powsybl.contingency.*; @@ -34,6 +36,7 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import java.io.OutputStreamWriter; import java.util.*; import java.util.concurrent.CompletionException; import java.util.concurrent.ForkJoinPool; @@ -1524,24 +1527,30 @@ void testSwitchLoopIssue() { @Test void testDcPermanentCurrentLimitViolations() { - Network fourBusNetwork = FourBusNetworkFactory.create(); + Network network = FourBusNetworkFactory.create(); SecurityAnalysisParameters securityAnalysisParameters = new SecurityAnalysisParameters(); LoadFlowParameters lfParameters = new LoadFlowParameters() .setDc(true); setSlackBusId(lfParameters, "b1_vl_0"); securityAnalysisParameters.setLoadFlowParameters(lfParameters); - List contingencies = allBranches(fourBusNetwork); + List contingencies = allBranches(network); - fourBusNetwork.getLine("l14").newCurrentLimits1().setPermanentLimit(60.0).add(); - fourBusNetwork.getLine("l12").newCurrentLimits1().setPermanentLimit(120.0).add(); - fourBusNetwork.getLine("l23").newCurrentLimits2().setPermanentLimit(150.0).add(); - fourBusNetwork.getLine("l34").newCurrentLimits1().setPermanentLimit(90.0).add(); - fourBusNetwork.getLine("l13").newCurrentLimits2().setPermanentLimit(60.0).add(); + network.getLine("l14").newCurrentLimits1().setPermanentLimit(60.0).add(); + network.getLine("l12").newCurrentLimits1().setPermanentLimit(120.0).add(); + network.getLine("l23").newCurrentLimits2().setPermanentLimit(150.0).add(); + network.getLine("l34").newCurrentLimits1().setPermanentLimit(90.0).add(); + network.getLine("l13").newCurrentLimits2().setPermanentLimit(60.0).add(); List monitors = List.of(new StateMonitor(ContingencyContext.all(), Set.of("l14", "l12", "l23", "l34", "l13"), Collections.emptySet(), Collections.emptySet())); - SecurityAnalysisResult result = runSecurityAnalysis(fourBusNetwork, contingencies, monitors, securityAnalysisParameters); + SecurityAnalysisResult result = runSecurityAnalysis(network, contingencies, monitors, securityAnalysisParameters); + + Security.print(result, + network, + new OutputStreamWriter(System.out), + new AsciiTableFormatterFactory(), + new Security.PostContingencyLimitViolationWriteConfig(null, TableFormatterConfig.load(), true, false)); assertTrue(result.getPreContingencyResult().getLimitViolationsResult().isComputationOk()); assertEquals(5, result.getPreContingencyResult().getLimitViolationsResult().getLimitViolations().size()); @@ -1555,33 +1564,42 @@ void testDcPermanentCurrentLimitViolations() { @Test void testDcTemporaryCurrentLimitViolations() { - Network fourBusNetwork = FourBusNetworkFactory.create(); + Network network = FourBusNetworkFactory.create(); SecurityAnalysisParameters securityAnalysisParameters = new SecurityAnalysisParameters(); LoadFlowParameters lfParameters = new LoadFlowParameters() .setDc(true); setSlackBusId(lfParameters, "b1_vl_0"); securityAnalysisParameters.setLoadFlowParameters(lfParameters); - List contingencies = allBranches(fourBusNetwork); + List contingencies = allBranches(network); - fourBusNetwork.getLine("l14").newCurrentLimits1().beginTemporaryLimit().setName("60").setAcceptableDuration(60).setValue(60.0).endTemporaryLimit().add(); - fourBusNetwork.getLine("l12").newCurrentLimits1().beginTemporaryLimit().setName("60").setAcceptableDuration(60).setValue(120.0).endTemporaryLimit().add(); - fourBusNetwork.getLine("l23").newCurrentLimits2().beginTemporaryLimit().setName("60").setAcceptableDuration(60).setValue(150.0).endTemporaryLimit().add(); - fourBusNetwork.getLine("l34").newCurrentLimits1().beginTemporaryLimit().setName("60").setAcceptableDuration(60).setValue(90.0).endTemporaryLimit().add(); - fourBusNetwork.getLine("l13").newCurrentLimits2().beginTemporaryLimit().setName("60").setAcceptableDuration(60).setValue(60.0).endTemporaryLimit().add(); + network.getLine("l14").newCurrentLimits1().setPermanentLimit(60.0) + .beginTemporaryLimit().setName("60").setAcceptableDuration(Integer.MAX_VALUE).setValue(200.0).endTemporaryLimit() + .beginTemporaryLimit().setName("0").setAcceptableDuration(60).setValue(Double.MAX_VALUE).endTemporaryLimit().add(); + network.getLine("l12").newCurrentLimits1().setPermanentLimit(120.0) + .beginTemporaryLimit().setName("60").setAcceptableDuration(Integer.MAX_VALUE).setValue(300.0).endTemporaryLimit() + .beginTemporaryLimit().setName("0").setAcceptableDuration(60).setValue(Double.MAX_VALUE).endTemporaryLimit().add(); + network.getLine("l23").newCurrentLimits2().setPermanentLimit(150.0) + .beginTemporaryLimit().setName("60").setAcceptableDuration(Integer.MAX_VALUE).setValue(500.0).endTemporaryLimit() + .beginTemporaryLimit().setName("0").setAcceptableDuration(60).setValue(Double.MAX_VALUE).endTemporaryLimit().add(); + network.getLine("l34").newCurrentLimits1().setPermanentLimit(90.0) + .beginTemporaryLimit().setName("60").setAcceptableDuration(Integer.MAX_VALUE).setValue(300.0).endTemporaryLimit() + .beginTemporaryLimit().setName("0").setAcceptableDuration(60).setValue(Double.MAX_VALUE).endTemporaryLimit().add(); + network.getLine("l13").newCurrentLimits2().setPermanentLimit(60.0) + .beginTemporaryLimit().setName("60").setAcceptableDuration(Integer.MAX_VALUE).setValue(300.0).endTemporaryLimit() + .beginTemporaryLimit().setName("0").setAcceptableDuration(60).setValue(Double.MAX_VALUE).endTemporaryLimit().add(); List monitors = List.of(new StateMonitor(ContingencyContext.all(), Set.of("l14", "l12", "l23", "l34", "l13"), Collections.emptySet(), Collections.emptySet())); - SecurityAnalysisResult result = runSecurityAnalysis(fourBusNetwork, contingencies, monitors, securityAnalysisParameters); + SecurityAnalysisResult result = runSecurityAnalysis(network, contingencies, monitors, securityAnalysisParameters); assertTrue(result.getPreContingencyResult().getLimitViolationsResult().isComputationOk()); - // FIXME: temporary limits are not detected - //assertEquals(5, result.getPreContingencyResult().getLimitViolationsResult().getLimitViolations().size()); - //assertEquals(5, result.getPostContingencyResults().size()); - //assertEquals(2, result.getPostContingencyResults().get(0).getLimitViolationsResult().getLimitViolations().size()); - //assertEquals(2, result.getPostContingencyResults().get(1).getLimitViolationsResult().getLimitViolations().size()); - //assertEquals(4, result.getPostContingencyResults().get(2).getLimitViolationsResult().getLimitViolations().size()); - //assertEquals(4, result.getPostContingencyResults().get(3).getLimitViolationsResult().getLimitViolations().size()); - //assertEquals(4, result.getPostContingencyResults().get(4).getLimitViolationsResult().getLimitViolations().size()); + assertEquals(5, result.getPreContingencyResult().getLimitViolationsResult().getLimitViolations().size()); + assertEquals(5, result.getPostContingencyResults().size()); + assertEquals(2, result.getPostContingencyResults().get(0).getLimitViolationsResult().getLimitViolations().size()); + assertEquals(2, result.getPostContingencyResults().get(1).getLimitViolationsResult().getLimitViolations().size()); + assertEquals(4, result.getPostContingencyResults().get(2).getLimitViolationsResult().getLimitViolations().size()); + assertEquals(4, result.getPostContingencyResults().get(3).getLimitViolationsResult().getLimitViolations().size()); + assertEquals(4, result.getPostContingencyResults().get(4).getLimitViolationsResult().getLimitViolations().size()); } } From a580f3b8ba06844b50ec5e1070d02b33f564dfba Mon Sep 17 00:00:00 2001 From: Anne Tilloy Date: Mon, 13 Jun 2022 16:06:39 +0200 Subject: [PATCH 12/15] Add open loadflow parameter. Signed-off-by: Anne Tilloy --- .../openloadflow/OpenLoadFlowParameters.java | 22 ++++++++++++++++++- .../openloadflow/sa/DcSecurityAnalysis.java | 4 +++- .../OpenLoadFlowParametersTest.java | 1 + .../sa/OpenSecurityAnalysisTest.java | 2 ++ src/test/resources/debug-parameters.json | 3 ++- 5 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java index e62793be1a..05ca4eefa1 100644 --- a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java +++ b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java @@ -61,6 +61,8 @@ public class OpenLoadFlowParameters extends AbstractExtension SPECIFIC_PARAMETERS_NAMES = List.of(SLACK_BUS_SELECTION_PARAM_NAME, SLACK_BUSES_IDS_PARAM_NAME, LOW_IMPEDANCE_BRANCH_MODE_PARAM_NAME, @@ -157,6 +161,8 @@ public enum LowImpedanceBranchMode { private TransformerVoltageControlMode transformerVoltageControlMode = TRANSFORMER_VOLTAGE_CONTROL_MODE_DEFAULT_VALUE; + private double dcCosPhi = DC_COS_PHI_DEFAULT_VALUE; + @Override public String getName() { return "open-load-flow-parameters"; @@ -305,6 +311,15 @@ public OpenLoadFlowParameters setTransformerVoltageControlMode(TransformerVoltag return this; } + public double getDcCosPhi() { + return dcCosPhi; + } + + public OpenLoadFlowParameters setDcCosPhi(double dcCosPhi) { + this.dcCosPhi = dcCosPhi; + return this; + } + public static OpenLoadFlowParameters load() { return load(PlatformConfig.defaultConfig()); } @@ -329,7 +344,8 @@ public static OpenLoadFlowParameters load(PlatformConfig platformConfig) { .setMaxIteration(config.getIntProperty(MAX_ITERATION_NAME, NewtonRaphsonParameters.DEFAULT_MAX_ITERATION)) .setNewtonRaphsonConvEpsPerEq(config.getDoubleProperty(NEWTON_RAPHSON_CONV_EPS_PER_EQ_NAME, DefaultNewtonRaphsonStoppingCriteria.DEFAULT_CONV_EPS_PER_EQ)) .setVoltageInitModeOverride(config.getEnumProperty(VOLTAGE_INIT_MODE_OVERRIDE_NAME, VoltageInitModeOverride.class, VOLTAGE_INIT_MODE_OVERRIDE_DEFAULT_VALUE)) - .setTransformerVoltageControlMode(config.getEnumProperty(TRANSFORMER_VOLTAGE_CONTROL_MODE_NAME, TransformerVoltageControlMode.class, TRANSFORMER_VOLTAGE_CONTROL_MODE_DEFAULT_VALUE))); + .setTransformerVoltageControlMode(config.getEnumProperty(TRANSFORMER_VOLTAGE_CONTROL_MODE_NAME, TransformerVoltageControlMode.class, TRANSFORMER_VOLTAGE_CONTROL_MODE_DEFAULT_VALUE)) + .setDcCosPhi(config.getDoubleProperty(DC_COS_PHI_NAME, DC_COS_PHI_DEFAULT_VALUE))); return parameters; } @@ -368,6 +384,8 @@ public OpenLoadFlowParameters update(Map properties) { .ifPresent(prop -> this.setVoltageInitModeOverride(VoltageInitModeOverride.valueOf(prop))); Optional.ofNullable(properties.get(TRANSFORMER_VOLTAGE_CONTROL_MODE_NAME)) .ifPresent(prop -> this.setTransformerVoltageControlMode(TransformerVoltageControlMode.valueOf(prop))); + Optional.ofNullable(properties.get(DC_COS_PHI_NAME)) + .ifPresent(prop -> this.setDcCosPhi(Double.parseDouble(prop))); return this; } @@ -389,6 +407,7 @@ public String toString() { ", newtonRaphsonConvEpsPerEq=" + newtonRaphsonConvEpsPerEq + ", voltageInitModeOverride=" + voltageInitModeOverride + ", transformerVoltageControlMode=" + transformerVoltageControlMode + + ", dcCosPhi=" + dcCosPhi + ')'; } @@ -424,6 +443,7 @@ public static void logDc(LoadFlowParameters parameters, OpenLoadFlowParameters p LOGGER.info("Plausible active power limit: {}", parametersExt.getPlausibleActivePowerLimit()); LOGGER.info("Add ratio to lines with different nominal voltage at both ends: {}", parametersExt.isAddRatioToLinesWithDifferentNominalVoltageAtBothEnds()); LOGGER.info("Connected component mode: {}", parameters.getConnectedComponentMode()); + LOGGER.info("DC cos phi: {}", parametersExt.getDcCosPhi()); } /** diff --git a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java index ca44508180..c81244d170 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java @@ -12,6 +12,7 @@ import com.powsybl.iidm.network.Branch; import com.powsybl.iidm.network.Network; import com.powsybl.math.matrix.MatrixFactory; +import com.powsybl.openloadflow.OpenLoadFlowParameters; import com.powsybl.openloadflow.graph.GraphDecrementalConnectivityFactory; import com.powsybl.openloadflow.network.LfBranch; import com.powsybl.openloadflow.network.LfBus; @@ -64,7 +65,8 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete Map preContingencyBranchResults = new HashMap<>(); // CosPhi for DC power to current conversion - double cosPhi = Math.cos(Math.atan(0.4)); + OpenLoadFlowParameters parametersExt = OpenLoadFlowParameters.get(securityAnalysisParameters.getLoadFlowParameters()); + double cosPhi = parametersExt.getDcCosPhi(); Map, LimitViolation> preContingencyLimitViolationsMap = new HashMap<>(); for (SensitivityValue sensValue : res.getValues(null)) { diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java index a951d027b6..365dad7c8e 100644 --- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java +++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java @@ -105,6 +105,7 @@ void testDefaultOpenLoadflowConfig() { assertEquals(OpenLoadFlowParameters.THROWS_EXCEPTION_IN_CASE_OF_SLACK_DISTRIBUTION_FAILURE_DEFAULT_VALUE, olfParameters.isThrowsExceptionInCaseOfSlackDistributionFailure()); assertEquals(OpenLoadFlowParameters.SLACK_BUS_P_MAX_MISMATCH_DEFAULT_VALUE, olfParameters.getSlackBusPMaxMismatch(), 0.0); assertEquals(OpenLoadFlowParameters.REACTIVE_POWER_REMOTE_CONTROL_DEFAULT_VALUE, olfParameters.hasReactivePowerRemoteControl()); + assertEquals(OpenLoadFlowParameters.DC_COS_PHI_DEFAULT_VALUE, olfParameters.getDcCosPhi()); } @Test diff --git a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java index 5b983180d4..2efd697481 100644 --- a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java +++ b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java @@ -1568,6 +1568,8 @@ void testDcTemporaryCurrentLimitViolations() { SecurityAnalysisParameters securityAnalysisParameters = new SecurityAnalysisParameters(); LoadFlowParameters lfParameters = new LoadFlowParameters() .setDc(true); + OpenLoadFlowParameters lfParametersExt = new OpenLoadFlowParameters().setDcCosPhi(Math.tan(0.4)); + lfParameters.addExtension(OpenLoadFlowParameters.class, lfParametersExt); setSlackBusId(lfParameters, "b1_vl_0"); securityAnalysisParameters.setLoadFlowParameters(lfParameters); diff --git a/src/test/resources/debug-parameters.json b/src/test/resources/debug-parameters.json index cb07de15dd..a0495ea4d1 100644 --- a/src/test/resources/debug-parameters.json +++ b/src/test/resources/debug-parameters.json @@ -31,7 +31,8 @@ "maxIteration" : 30, "newtonRaphsonConvEpsPerEq" : 1.0E-4, "voltageInitModeOverride" : "NONE", - "transformerVoltageControlMode" : "WITH_GENERATOR_VOLTAGE_CONTROL" + "transformerVoltageControlMode" : "WITH_GENERATOR_VOLTAGE_CONTROL", + "dcCosPhi" : 1.0 } } }, From 22fae8904f78a349a530d3fa4144ad2d9526b9c4 Mon Sep 17 00:00:00 2001 From: Anne Tilloy Date: Mon, 13 Jun 2022 18:04:14 +0200 Subject: [PATCH 13/15] Change parameter name. Signed-off-by: Anne Tilloy --- .../openloadflow/OpenLoadFlowParameters.java | 27 ++++++++++--------- .../openloadflow/sa/DcSecurityAnalysis.java | 2 +- .../OpenLoadFlowParametersTest.java | 2 +- .../OpenLoadFlowProviderTest.java | 2 +- .../sa/OpenSecurityAnalysisTest.java | 8 +++++- src/test/resources/debug-parameters.json | 2 +- 6 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java index 05ca4eefa1..83d2692c13 100644 --- a/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java +++ b/src/main/java/com/powsybl/openloadflow/OpenLoadFlowParameters.java @@ -61,7 +61,7 @@ public class OpenLoadFlowParameters extends AbstractExtension SPECIFIC_PARAMETERS_NAMES = List.of(SLACK_BUS_SELECTION_PARAM_NAME, SLACK_BUSES_IDS_PARAM_NAME, @@ -109,7 +109,8 @@ public class OpenLoadFlowParameters extends AbstractExtension properties) { .ifPresent(prop -> this.setVoltageInitModeOverride(VoltageInitModeOverride.valueOf(prop))); Optional.ofNullable(properties.get(TRANSFORMER_VOLTAGE_CONTROL_MODE_NAME)) .ifPresent(prop -> this.setTransformerVoltageControlMode(TransformerVoltageControlMode.valueOf(prop))); - Optional.ofNullable(properties.get(DC_COS_PHI_NAME)) - .ifPresent(prop -> this.setDcCosPhi(Double.parseDouble(prop))); + Optional.ofNullable(properties.get(DC_POWER_FACTOR_NAME)) + .ifPresent(prop -> this.setDcPowerFactor(Double.parseDouble(prop))); return this; } @@ -407,7 +408,7 @@ public String toString() { ", newtonRaphsonConvEpsPerEq=" + newtonRaphsonConvEpsPerEq + ", voltageInitModeOverride=" + voltageInitModeOverride + ", transformerVoltageControlMode=" + transformerVoltageControlMode + - ", dcCosPhi=" + dcCosPhi + + ", dcPowerFactor=" + dcPowerFactor + ')'; } @@ -443,7 +444,7 @@ public static void logDc(LoadFlowParameters parameters, OpenLoadFlowParameters p LOGGER.info("Plausible active power limit: {}", parametersExt.getPlausibleActivePowerLimit()); LOGGER.info("Add ratio to lines with different nominal voltage at both ends: {}", parametersExt.isAddRatioToLinesWithDifferentNominalVoltageAtBothEnds()); LOGGER.info("Connected component mode: {}", parameters.getConnectedComponentMode()); - LOGGER.info("DC cos phi: {}", parametersExt.getDcCosPhi()); + LOGGER.info("DC power factor: {}", parametersExt.getDcPowerFactor()); } /** diff --git a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java index c81244d170..a854fabd29 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java @@ -66,7 +66,7 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete // CosPhi for DC power to current conversion OpenLoadFlowParameters parametersExt = OpenLoadFlowParameters.get(securityAnalysisParameters.getLoadFlowParameters()); - double cosPhi = parametersExt.getDcCosPhi(); + double cosPhi = parametersExt.getDcPowerFactor(); Map, LimitViolation> preContingencyLimitViolationsMap = new HashMap<>(); for (SensitivityValue sensValue : res.getValues(null)) { diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java index 365dad7c8e..c2617bdbe9 100644 --- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java +++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowParametersTest.java @@ -105,7 +105,7 @@ void testDefaultOpenLoadflowConfig() { assertEquals(OpenLoadFlowParameters.THROWS_EXCEPTION_IN_CASE_OF_SLACK_DISTRIBUTION_FAILURE_DEFAULT_VALUE, olfParameters.isThrowsExceptionInCaseOfSlackDistributionFailure()); assertEquals(OpenLoadFlowParameters.SLACK_BUS_P_MAX_MISMATCH_DEFAULT_VALUE, olfParameters.getSlackBusPMaxMismatch(), 0.0); assertEquals(OpenLoadFlowParameters.REACTIVE_POWER_REMOTE_CONTROL_DEFAULT_VALUE, olfParameters.hasReactivePowerRemoteControl()); - assertEquals(OpenLoadFlowParameters.DC_COS_PHI_DEFAULT_VALUE, olfParameters.getDcCosPhi()); + assertEquals(OpenLoadFlowParameters.DC_POWER_FACTOR_DEFAULT_VALUE, olfParameters.getDcPowerFactor()); } @Test diff --git a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java index cac7e0d510..9903060e41 100644 --- a/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java +++ b/src/test/java/com/powsybl/openloadflow/OpenLoadFlowProviderTest.java @@ -85,7 +85,7 @@ void testGetExtendedVoltageInitializer() { @Test void specificParametersTest() { OpenLoadFlowProvider provider = new OpenLoadFlowProvider(); - assertEquals(15, provider.getSpecificParametersNames().size()); + assertEquals(16, provider.getSpecificParametersNames().size()); LoadFlowParameters parameters = new LoadFlowParameters(); provider.loadSpecificParameters(Collections.emptyMap()) diff --git a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java index 2efd697481..2cdbca8609 100644 --- a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java +++ b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java @@ -1568,7 +1568,7 @@ void testDcTemporaryCurrentLimitViolations() { SecurityAnalysisParameters securityAnalysisParameters = new SecurityAnalysisParameters(); LoadFlowParameters lfParameters = new LoadFlowParameters() .setDc(true); - OpenLoadFlowParameters lfParametersExt = new OpenLoadFlowParameters().setDcCosPhi(Math.tan(0.4)); + OpenLoadFlowParameters lfParametersExt = new OpenLoadFlowParameters().setDcPowerFactor(Math.tan(0.4)); lfParameters.addExtension(OpenLoadFlowParameters.class, lfParametersExt); setSlackBusId(lfParameters, "b1_vl_0"); securityAnalysisParameters.setLoadFlowParameters(lfParameters); @@ -1603,5 +1603,11 @@ void testDcTemporaryCurrentLimitViolations() { assertEquals(4, result.getPostContingencyResults().get(2).getLimitViolationsResult().getLimitViolations().size()); assertEquals(4, result.getPostContingencyResults().get(3).getLimitViolationsResult().getLimitViolations().size()); assertEquals(4, result.getPostContingencyResults().get(4).getLimitViolationsResult().getLimitViolations().size()); + + Security.print(result, + network, + new OutputStreamWriter(System.out), + new AsciiTableFormatterFactory(), + new Security.PostContingencyLimitViolationWriteConfig(null, TableFormatterConfig.load(), true, false)); } } diff --git a/src/test/resources/debug-parameters.json b/src/test/resources/debug-parameters.json index a0495ea4d1..027ca60307 100644 --- a/src/test/resources/debug-parameters.json +++ b/src/test/resources/debug-parameters.json @@ -32,7 +32,7 @@ "newtonRaphsonConvEpsPerEq" : 1.0E-4, "voltageInitModeOverride" : "NONE", "transformerVoltageControlMode" : "WITH_GENERATOR_VOLTAGE_CONTROL", - "dcCosPhi" : 1.0 + "dcPowerFactor" : 1.0 } } }, From 2f7f6901b848b61719932770179dbb1aa09fe149 Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Mon, 13 Jun 2022 21:21:29 +0200 Subject: [PATCH 14/15] Fix var name Signed-off-by: Geoffroy Jamgotchian --- .../powsybl/openloadflow/sa/DcSecurityAnalysis.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java index a854fabd29..0b5cfe9f38 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java @@ -66,7 +66,7 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete // CosPhi for DC power to current conversion OpenLoadFlowParameters parametersExt = OpenLoadFlowParameters.get(securityAnalysisParameters.getLoadFlowParameters()); - double cosPhi = parametersExt.getDcPowerFactor(); + double dcPowerFactor = parametersExt.getDcPowerFactor(); Map, LimitViolation> preContingencyLimitViolationsMap = new HashMap<>(); for (SensitivityValue sensValue : res.getValues(null)) { @@ -76,9 +76,9 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete preContingencyBranchResults.put(branchId, new BranchResult(branchId, sensValue.getFunctionReference(), Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN)); detector.checkActivePower(branch, Branch.Side.ONE, Math.abs(sensValue.getFunctionReference()), violation -> preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); - detector.checkCurrent(branch, Branch.Side.ONE, currentActivePower(Math.abs(sensValue.getFunctionReference()), branch.getTerminal1().getVoltageLevel().getNominalV(), cosPhi), + detector.checkCurrent(branch, Branch.Side.ONE, currentActivePower(Math.abs(sensValue.getFunctionReference()), branch.getTerminal1().getVoltageLevel().getNominalV(), dcPowerFactor), violation -> preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); - detector.checkCurrent(branch, Branch.Side.TWO, currentActivePower(Math.abs(sensValue.getFunctionReference()), branch.getTerminal2().getVoltageLevel().getNominalV(), cosPhi), + detector.checkCurrent(branch, Branch.Side.TWO, currentActivePower(Math.abs(sensValue.getFunctionReference()), branch.getTerminal2().getVoltageLevel().getNominalV(), dcPowerFactor), violation -> preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); } @@ -107,9 +107,9 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete } detector.checkActivePower(branch, Branch.Side.ONE, Math.abs(v.getFunctionReference()), violation -> violations.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); - detector.checkCurrent(branch, Branch.Side.ONE, currentActivePower(Math.abs(v.getFunctionReference()), branch.getTerminal1().getVoltageLevel().getNominalV(), cosPhi), + detector.checkCurrent(branch, Branch.Side.ONE, currentActivePower(Math.abs(v.getFunctionReference()), branch.getTerminal1().getVoltageLevel().getNominalV(), dcPowerFactor), violation -> violations.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); - detector.checkCurrent(branch, Branch.Side.TWO, currentActivePower(Math.abs(v.getFunctionReference()), branch.getTerminal2().getVoltageLevel().getNominalV(), cosPhi), + detector.checkCurrent(branch, Branch.Side.TWO, currentActivePower(Math.abs(v.getFunctionReference()), branch.getTerminal2().getVoltageLevel().getNominalV(), dcPowerFactor), violation -> violations.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); } preContingencyLimitViolationsMap.forEach((subjectSideId, preContingencyViolation) -> { From dbd6e1c98910f83ee7a97e9840ab62f8eb082786 Mon Sep 17 00:00:00 2001 From: Anne Tilloy Date: Tue, 14 Jun 2022 09:18:14 +0200 Subject: [PATCH 15/15] Improve testing. Signed-off-by: Anne Tilloy --- .../openloadflow/sa/DcSecurityAnalysis.java | 17 +++++--- .../sa/OpenSecurityAnalysisTest.java | 41 ++++++++++--------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java index 0b5cfe9f38..eeae699c21 100644 --- a/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java +++ b/src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java @@ -73,12 +73,14 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete SensitivityFactor factor = factors.get(sensValue.getFactorIndex()); String branchId = factor.getFunctionId(); Branch branch = network.getBranch(branchId); - preContingencyBranchResults.put(branchId, new BranchResult(branchId, sensValue.getFunctionReference(), Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN)); + double i1 = currentActivePower(Math.abs(sensValue.getFunctionReference()), branch.getTerminal1().getVoltageLevel().getNominalV(), dcPowerFactor); + double i2 = currentActivePower(Math.abs(sensValue.getFunctionReference()), branch.getTerminal2().getVoltageLevel().getNominalV(), dcPowerFactor); + preContingencyBranchResults.put(branchId, new BranchResult(branchId, sensValue.getFunctionReference(), Double.NaN, i1, -sensValue.getFunctionReference(), Double.NaN, i2, Double.NaN)); detector.checkActivePower(branch, Branch.Side.ONE, Math.abs(sensValue.getFunctionReference()), violation -> preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); - detector.checkCurrent(branch, Branch.Side.ONE, currentActivePower(Math.abs(sensValue.getFunctionReference()), branch.getTerminal1().getVoltageLevel().getNominalV(), dcPowerFactor), + detector.checkCurrent(branch, Branch.Side.ONE, i1, violation -> preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); - detector.checkCurrent(branch, Branch.Side.TWO, currentActivePower(Math.abs(sensValue.getFunctionReference()), branch.getTerminal2().getVoltageLevel().getNominalV(), dcPowerFactor), + detector.checkCurrent(branch, Branch.Side.TWO, i2, violation -> preContingencyLimitViolationsMap.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); } @@ -99,17 +101,20 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete SensitivityFactor factor = factors.get(v.getFactorIndex()); String branchId = factor.getFunctionId(); Branch branch = network.getBranch(branchId); + double i1 = currentActivePower(Math.abs(v.getFunctionReference()), branch.getTerminal1().getVoltageLevel().getNominalV(), dcPowerFactor); + double i2 = currentActivePower(Math.abs(v.getFunctionReference()), branch.getTerminal2().getVoltageLevel().getNominalV(), dcPowerFactor); if (monitor.getBranchIds().contains(branchId)) { BranchResult preContingencyBranchResult = preContingencyBranchResults.get(branchId); double flowTransfer = Double.isNaN(branchInContingencyP1) ? Double.NaN : (v.getFunctionReference() - preContingencyBranchResult.getP1()) / branchInContingencyP1; - postContingencyBranchResults.put(branchId, new BranchResult(branchId, v.getFunctionReference(), Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, flowTransfer)); + postContingencyBranchResults.put(branchId, new BranchResult(branchId, v.getFunctionReference(), Double.NaN, i1, + -v.getFunctionReference(), Double.NaN, i2, flowTransfer)); } detector.checkActivePower(branch, Branch.Side.ONE, Math.abs(v.getFunctionReference()), violation -> violations.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); - detector.checkCurrent(branch, Branch.Side.ONE, currentActivePower(Math.abs(v.getFunctionReference()), branch.getTerminal1().getVoltageLevel().getNominalV(), dcPowerFactor), + detector.checkCurrent(branch, Branch.Side.ONE, i1, violation -> violations.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); - detector.checkCurrent(branch, Branch.Side.TWO, currentActivePower(Math.abs(v.getFunctionReference()), branch.getTerminal2().getVoltageLevel().getNominalV(), dcPowerFactor), + detector.checkCurrent(branch, Branch.Side.TWO, i2, violation -> violations.put(Pair.of(violation.getSubjectId(), violation.getSide()), violation)); } preContingencyLimitViolationsMap.forEach((subjectSideId, preContingencyViolation) -> { diff --git a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java index 2cdbca8609..58a4191e4b 100644 --- a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java +++ b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java @@ -7,8 +7,6 @@ package com.powsybl.openloadflow.sa; import com.powsybl.commons.PowsyblException; -import com.powsybl.commons.io.table.AsciiTableFormatterFactory; -import com.powsybl.commons.io.table.TableFormatterConfig; import com.powsybl.commons.reporter.Reporter; import com.powsybl.computation.ComputationManager; import com.powsybl.contingency.*; @@ -36,7 +34,6 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; -import java.io.OutputStreamWriter; import java.util.*; import java.util.concurrent.CompletionException; import java.util.concurrent.ForkJoinPool; @@ -1546,20 +1543,30 @@ void testDcPermanentCurrentLimitViolations() { SecurityAnalysisResult result = runSecurityAnalysis(network, contingencies, monitors, securityAnalysisParameters); - Security.print(result, - network, - new OutputStreamWriter(System.out), - new AsciiTableFormatterFactory(), - new Security.PostContingencyLimitViolationWriteConfig(null, TableFormatterConfig.load(), true, false)); - assertTrue(result.getPreContingencyResult().getLimitViolationsResult().isComputationOk()); assertEquals(5, result.getPreContingencyResult().getLimitViolationsResult().getLimitViolations().size()); assertEquals(5, result.getPostContingencyResults().size()); - assertEquals(2, result.getPostContingencyResults().get(0).getLimitViolationsResult().getLimitViolations().size()); - assertEquals(2, result.getPostContingencyResults().get(1).getLimitViolationsResult().getLimitViolations().size()); - assertEquals(4, result.getPostContingencyResults().get(2).getLimitViolationsResult().getLimitViolations().size()); - assertEquals(4, result.getPostContingencyResults().get(3).getLimitViolationsResult().getLimitViolations().size()); - assertEquals(4, result.getPostContingencyResults().get(4).getLimitViolationsResult().getLimitViolations().size()); + assertEquals(2, getPostContingencyResult(result, "l14").getLimitViolationsResult().getLimitViolations().size()); + assertEquals(192.450, getPostContingencyResult(result, "l14").getBranchResult("l12").getI1(), LoadFlowAssert.DELTA_I); + assertEquals(962.250, getPostContingencyResult(result, "l14").getBranchResult("l13").getI1(), LoadFlowAssert.DELTA_I); + assertEquals(2, getPostContingencyResult(result, "l12").getLimitViolationsResult().getLimitViolations().size()); + assertEquals(192.450, getPostContingencyResult(result, "l12").getBranchResult("l14").getI1(), LoadFlowAssert.DELTA_I); + assertEquals(962.250, getPostContingencyResult(result, "l12").getBranchResult("l13").getI1(), LoadFlowAssert.DELTA_I); + assertEquals(4, getPostContingencyResult(result, "l13").getLimitViolationsResult().getLimitViolations().size()); + assertEquals(577.350, getPostContingencyResult(result, "l13").getBranchResult("l12").getI1(), LoadFlowAssert.DELTA_I); + assertEquals(577.350, getPostContingencyResult(result, "l13").getBranchResult("l14").getI1(), LoadFlowAssert.DELTA_I); + assertEquals(1154.700, getPostContingencyResult(result, "l13").getBranchResult("l23").getI1(), LoadFlowAssert.DELTA_I); + assertEquals(1154.700, getPostContingencyResult(result, "l13").getBranchResult("l34").getI1(), LoadFlowAssert.DELTA_I); + assertEquals(4, getPostContingencyResult(result, "l23").getLimitViolationsResult().getLimitViolations().size()); + assertEquals(577.350, getPostContingencyResult(result, "l23").getBranchResult("l12").getI1(), LoadFlowAssert.DELTA_I); + assertEquals(384.900, getPostContingencyResult(result, "l23").getBranchResult("l14").getI1(), LoadFlowAssert.DELTA_I); + assertEquals(1347.150, getPostContingencyResult(result, "l23").getBranchResult("l13").getI1(), LoadFlowAssert.DELTA_I); + assertEquals(962.250, getPostContingencyResult(result, "l23").getBranchResult("l34").getI1(), LoadFlowAssert.DELTA_I); + assertEquals(4, getPostContingencyResult(result, "l34").getLimitViolationsResult().getLimitViolations().size()); + assertEquals(384.900, getPostContingencyResult(result, "l34").getBranchResult("l12").getI1(), LoadFlowAssert.DELTA_I); + assertEquals(577.350, getPostContingencyResult(result, "l34").getBranchResult("l14").getI1(), LoadFlowAssert.DELTA_I); + assertEquals(1347.150, getPostContingencyResult(result, "l34").getBranchResult("l13").getI1(), LoadFlowAssert.DELTA_I); + assertEquals(962.250, getPostContingencyResult(result, "l34").getBranchResult("l23").getI1(), LoadFlowAssert.DELTA_I); } @Test @@ -1603,11 +1610,5 @@ void testDcTemporaryCurrentLimitViolations() { assertEquals(4, result.getPostContingencyResults().get(2).getLimitViolationsResult().getLimitViolations().size()); assertEquals(4, result.getPostContingencyResults().get(3).getLimitViolationsResult().getLimitViolations().size()); assertEquals(4, result.getPostContingencyResults().get(4).getLimitViolationsResult().getLimitViolations().size()); - - Security.print(result, - network, - new OutputStreamWriter(System.out), - new AsciiTableFormatterFactory(), - new Security.PostContingencyLimitViolationWriteConfig(null, TableFormatterConfig.load(), true, false)); } }