From fd4f0a6c7be268c442e4244acf00f3c3f4f9cdf6 Mon Sep 17 00:00:00 2001 From: Geoffroy Jamgotchian Date: Sat, 4 Mar 2023 14:02:45 +0100 Subject: [PATCH 1/2] Various performance improvements Signed-off-by: Geoffroy Jamgotchian --- .../openloadflow/equations/Equation.java | 10 +++ .../equations/EquationSystemIndex.java | 31 ++++++---- .../equations/EquationVector.java | 13 ++-- .../equations/JacobianMatrix.java | 61 +++++++++---------- .../openloadflow/equations/TargetVector.java | 6 +- .../equations/EquationSystemIndexTest.java | 33 +++++----- 6 files changed, 86 insertions(+), 68 deletions(-) diff --git a/src/main/java/com/powsybl/openloadflow/equations/Equation.java b/src/main/java/com/powsybl/openloadflow/equations/Equation.java index 17b0e7341f..16731a4c34 100644 --- a/src/main/java/com/powsybl/openloadflow/equations/Equation.java +++ b/src/main/java/com/powsybl/openloadflow/equations/Equation.java @@ -36,6 +36,8 @@ public class Equation & Quantity, E extends Enum & Quantity private final List> terms = new ArrayList<>(); + private final Map, List>> termsByVariable = new TreeMap<>(); + Equation(int elementNum, E type, EquationSystem equationSystem) { this.elementNum = elementNum; this.type = Objects.requireNonNull(type); @@ -81,6 +83,10 @@ public Equation addTerm(EquationTerm term) { + term.getEquation()); } terms.add(term); + for (Variable v : term.getVariables()) { + termsByVariable.computeIfAbsent(v, k -> new ArrayList<>()) + .add(term); + } term.setEquation(this); equationSystem.addEquationTerm(term); equationSystem.notifyEquationTermChange(term, EquationTermEventType.EQUATION_TERM_ADDED); @@ -99,6 +105,10 @@ public List> getTerms() { return terms; } + public Map, List>> getTermsByVariable() { + return termsByVariable; + } + @Override public double eval() { double value = 0; diff --git a/src/main/java/com/powsybl/openloadflow/equations/EquationSystemIndex.java b/src/main/java/com/powsybl/openloadflow/equations/EquationSystemIndex.java index 205d2e2448..9cfe5f9a79 100644 --- a/src/main/java/com/powsybl/openloadflow/equations/EquationSystemIndex.java +++ b/src/main/java/com/powsybl/openloadflow/equations/EquationSystemIndex.java @@ -11,6 +11,7 @@ import org.slf4j.LoggerFactory; import java.util.*; +import java.util.stream.Collectors; /** * @author Geoffroy Jamgotchian @@ -20,10 +21,14 @@ public class EquationSystemIndex & Quantity, E extends Enum private static final Logger LOGGER = LoggerFactory.getLogger(EquationSystemIndex.class); - private final TreeSet> sortedEquationsToSolve = new TreeSet<>(); + private final Set> equationsToSolve = new HashSet<>(); // variable reference counting in equation terms - private final NavigableMap, MutableInt> sortedVariablesToFindRefCount = new TreeMap<>(); + private final Map, MutableInt> variablesToFindRefCount = new HashMap<>(); + + private List> sortedEquationsToSolve = Collections.emptyList(); + + private List> sortedVariablesToFind = Collections.emptyList(); private boolean equationsIndexValid = false; @@ -57,6 +62,7 @@ private void notifyEquationTermChange(EquationTerm term) { private void update() { if (!equationsIndexValid) { + sortedEquationsToSolve = equationsToSolve.stream().sorted().collect(Collectors.toList()); int columnCount = 0; for (Equation equation : sortedEquationsToSolve) { equation.setColumn(columnCount++); @@ -66,8 +72,9 @@ private void update() { } if (!variablesIndexValid) { + sortedVariablesToFind = variablesToFindRefCount.keySet().stream().sorted().collect(Collectors.toList()); int rowCount = 0; - for (Variable variable : sortedVariablesToFindRefCount.keySet()) { + for (Variable variable : sortedVariablesToFind) { variable.setRow(rowCount++); } variablesIndexValid = true; @@ -78,10 +85,10 @@ private void update() { private void addTerm(EquationTerm term) { notifyEquationTermChange(term); for (Variable variable : term.getVariables()) { - MutableInt variableRefCount = sortedVariablesToFindRefCount.get(variable); + MutableInt variableRefCount = variablesToFindRefCount.get(variable); if (variableRefCount == null) { variableRefCount = new MutableInt(1); - sortedVariablesToFindRefCount.put(variable, variableRefCount); + variablesToFindRefCount.put(variable, variableRefCount); variablesIndexValid = false; notifyVariableChange(variable, EquationSystemIndexListener.ChangeType.ADDED); } else { @@ -91,7 +98,7 @@ private void addTerm(EquationTerm term) { } private void addEquation(Equation equation) { - sortedEquationsToSolve.add(equation); + equationsToSolve.add(equation); equationsIndexValid = false; for (EquationTerm term : equation.getTerms()) { if (term.isActive()) { @@ -104,12 +111,12 @@ private void addEquation(Equation equation) { private void removeTerm(EquationTerm term) { notifyEquationTermChange(term); for (Variable variable : term.getVariables()) { - MutableInt variableRefCount = sortedVariablesToFindRefCount.get(variable); + MutableInt variableRefCount = variablesToFindRefCount.get(variable); if (variableRefCount != null) { variableRefCount.decrement(); if (variableRefCount.intValue() == 0) { variable.setRow(-1); - sortedVariablesToFindRefCount.remove(variable); + variablesToFindRefCount.remove(variable); variablesIndexValid = false; notifyVariableChange(variable, EquationSystemIndexListener.ChangeType.REMOVED); } @@ -119,7 +126,7 @@ private void removeTerm(EquationTerm term) { private void removeEquation(Equation equation) { equation.setColumn(-1); - sortedEquationsToSolve.remove(equation); + equationsToSolve.remove(equation); equationsIndexValid = false; for (EquationTerm term : equation.getTerms()) { if (term.isActive()) { @@ -181,13 +188,13 @@ public void onEquationTermChange(EquationTerm term, EquationTermEventType } } - public NavigableSet> getSortedEquationsToSolve() { + public List> getSortedEquationsToSolve() { update(); return sortedEquationsToSolve; } - public NavigableSet> getSortedVariablesToFind() { + public List> getSortedVariablesToFind() { update(); - return sortedVariablesToFindRefCount.navigableKeySet(); + return sortedVariablesToFind; } } diff --git a/src/main/java/com/powsybl/openloadflow/equations/EquationVector.java b/src/main/java/com/powsybl/openloadflow/equations/EquationVector.java index 6b8ba31bd8..77dd466e05 100644 --- a/src/main/java/com/powsybl/openloadflow/equations/EquationVector.java +++ b/src/main/java/com/powsybl/openloadflow/equations/EquationVector.java @@ -11,6 +11,7 @@ import org.slf4j.LoggerFactory; import java.util.Arrays; +import java.util.List; import java.util.concurrent.TimeUnit; import static com.powsybl.openloadflow.util.Markers.PERFORMANCE_MARKER; @@ -40,6 +41,13 @@ protected double[] createArray() { return array; } + private void eval(double[] array, List> equations) { + Arrays.fill(array, 0); // necessary? + for (Equation equation : equations) { + array[equation.getColumn()] = equation.eval(); + } + } + @Override protected void updateArray(double[] array) { Stopwatch stopwatch = Stopwatch.createStarted(); @@ -50,10 +58,7 @@ protected void updateArray(double[] array) { throw new IllegalArgumentException("Bad equation vector length: " + array.length); } - Arrays.fill(array, 0); // necessary? - for (Equation equation : equations) { - array[equation.getColumn()] = equation.eval(); - } + eval(array, equations); LOGGER.debug(PERFORMANCE_MARKER, "Equation vector updated in {} us", stopwatch.elapsed(TimeUnit.MICROSECONDS)); } diff --git a/src/main/java/com/powsybl/openloadflow/equations/JacobianMatrix.java b/src/main/java/com/powsybl/openloadflow/equations/JacobianMatrix.java index 4aafbf87b4..75dcb40fc8 100644 --- a/src/main/java/com/powsybl/openloadflow/equations/JacobianMatrix.java +++ b/src/main/java/com/powsybl/openloadflow/equations/JacobianMatrix.java @@ -15,7 +15,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.concurrent.TimeUnit; import static com.powsybl.openloadflow.util.Markers.PERFORMANCE_MARKER; @@ -107,25 +110,7 @@ public void onStateUpdate() { updateStatus(Status.VALUES_INVALID); } - private void clearLu() { - if (lu != null) { - lu.close(); - } - 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() { + private void initDer() { Stopwatch stopwatch = Stopwatch.createStarted(); int rowCount = equationSystem.getIndex().getSortedEquationsToSolve().size(); @@ -141,8 +126,7 @@ private void initMatrix() { for (Equation eq : equationSystem.getIndex().getSortedEquationsToSolve()) { int column = eq.getColumn(); - Map, List>> termsByVariable = indexTermsByVariable(eq); - for (Map.Entry, List>> e : termsByVariable.entrySet()) { + for (Map.Entry, List>> e : eq.getTermsByVariable().entrySet()) { Variable v = e.getKey(); int row = v.getRow(); if (row != -1) { @@ -151,28 +135,28 @@ private void initMatrix() { // 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)); + partialDerivatives.add(new PartialDerivative<>(term, elementIndex, v)); } } } } LOGGER.debug(PERFORMANCE_MARKER, "Jacobian matrix built in {} us", stopwatch.elapsed(TimeUnit.MICROSECONDS)); - - clearLu(); } - private void updateLu(boolean allowIncrementalUpdate) { + private void clearLu() { if (lu != null) { - Stopwatch stopwatch = Stopwatch.createStarted(); - - lu.update(allowIncrementalUpdate); - - LOGGER.debug(PERFORMANCE_MARKER, "LU decomposition updated in {} us", stopwatch.elapsed(TimeUnit.MICROSECONDS)); + lu.close(); } + lu = null; } - private void updateValues(boolean allowIncrementalUpdate) { + private void initMatrix() { + initDer(); + clearLu(); + } + + private void updateDer() { Stopwatch stopwatch = Stopwatch.createStarted(); matrix.reset(); @@ -187,7 +171,20 @@ private void updateValues(boolean allowIncrementalUpdate) { } LOGGER.debug(PERFORMANCE_MARKER, "Jacobian matrix values updated in {} us", stopwatch.elapsed(TimeUnit.MICROSECONDS)); + } + + private void updateLu(boolean allowIncrementalUpdate) { + if (lu != null) { + Stopwatch stopwatch = Stopwatch.createStarted(); + + lu.update(allowIncrementalUpdate); + LOGGER.debug(PERFORMANCE_MARKER, "LU decomposition updated in {} us", stopwatch.elapsed(TimeUnit.MICROSECONDS)); + } + } + + private void updateValues(boolean allowIncrementalUpdate) { + updateDer(); updateLu(allowIncrementalUpdate); } diff --git a/src/main/java/com/powsybl/openloadflow/equations/TargetVector.java b/src/main/java/com/powsybl/openloadflow/equations/TargetVector.java index 387c2fb7cf..c2c12367b2 100644 --- a/src/main/java/com/powsybl/openloadflow/equations/TargetVector.java +++ b/src/main/java/com/powsybl/openloadflow/equations/TargetVector.java @@ -8,7 +8,7 @@ import com.powsybl.openloadflow.network.*; -import java.util.NavigableSet; +import java.util.List; import java.util.Objects; /** @@ -75,7 +75,7 @@ public static & Quantity, E extends Enum & Quantity> doubl Objects.requireNonNull(network); Objects.requireNonNull(equationSystem); Objects.requireNonNull(initializer); - NavigableSet> sortedEquationsToSolve = equationSystem.getIndex().getSortedEquationsToSolve(); + List> sortedEquationsToSolve = equationSystem.getIndex().getSortedEquationsToSolve(); double[] array = new double[sortedEquationsToSolve.size()]; for (Equation equation : sortedEquationsToSolve) { initializer.initialize(equation, network, array); @@ -90,7 +90,7 @@ protected double[] createArray() { @Override protected void updateArray(double[] array) { - NavigableSet> sortedEquationsToSolve = equationSystem.getIndex().getSortedEquationsToSolve(); + List> sortedEquationsToSolve = equationSystem.getIndex().getSortedEquationsToSolve(); for (Equation equation : sortedEquationsToSolve) { initializer.initialize(equation, network, array); } diff --git a/src/test/java/com/powsybl/openloadflow/equations/EquationSystemIndexTest.java b/src/test/java/com/powsybl/openloadflow/equations/EquationSystemIndexTest.java index 4cb5925fd7..f065ce5553 100644 --- a/src/test/java/com/powsybl/openloadflow/equations/EquationSystemIndexTest.java +++ b/src/test/java/com/powsybl/openloadflow/equations/EquationSystemIndexTest.java @@ -13,7 +13,6 @@ 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; @@ -116,8 +115,8 @@ public void onEquationTermChange(EquationTerm Date: Sat, 4 Mar 2023 14:17:13 +0100 Subject: [PATCH 2/2] More Signed-off-by: Geoffroy Jamgotchian --- .../java/com/powsybl/openloadflow/network/LfBus.java | 2 ++ .../openloadflow/network/impl/AbstractLfBus.java | 12 +++++++++++- .../network/impl/AbstractLfGenerator.java | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/powsybl/openloadflow/network/LfBus.java b/src/main/java/com/powsybl/openloadflow/network/LfBus.java index 233aa37023..41ae64ce40 100644 --- a/src/main/java/com/powsybl/openloadflow/network/LfBus.java +++ b/src/main/java/com/powsybl/openloadflow/network/LfBus.java @@ -72,6 +72,8 @@ public interface LfBus extends LfElement { boolean ensurePowerFactorConstantByLoad(); + void invalidateGenerationTargetP(); + double getGenerationTargetP(); double getGenerationTargetQ(); 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 2b426feb13..835eb06b26 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfBus.java @@ -49,6 +49,8 @@ public abstract class AbstractLfBus extends AbstractElement implements LfBus { protected double loadTargetQ = 0; + protected Double generationTargetP; + protected double generationTargetQ = 0; protected final List generators = new ArrayList<>(); @@ -270,9 +272,17 @@ void setShuntCompensators(List shuntCompensators, LfNetworkPar } } + @Override + public void invalidateGenerationTargetP() { + generationTargetP = null; + } + @Override public double getGenerationTargetP() { - return generators.stream().mapToDouble(LfGenerator::getTargetP).sum(); + if (generationTargetP == null) { + generationTargetP = generators.stream().mapToDouble(LfGenerator::getTargetP).sum(); + } + return generationTargetP; } @Override diff --git a/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfGenerator.java b/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfGenerator.java index 50dab61547..c92999af7c 100644 --- a/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfGenerator.java +++ b/src/main/java/com/powsybl/openloadflow/network/impl/AbstractLfGenerator.java @@ -82,6 +82,7 @@ public void setTargetP(double targetP) { if (newTargetP != this.targetP) { double oldTargetP = this.targetP; this.targetP = newTargetP; + bus.invalidateGenerationTargetP(); for (LfNetworkListener listener : bus.getNetwork().getListeners()) { listener.onGenerationActivePowerTargetChange(this, oldTargetP, newTargetP); }