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 926468d6fa..ac95ab26f8 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractBranchAcFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractBranchAcFlowEquationTerm.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -7,6 +7,7 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.AbstractElementEquationTerm; import com.powsybl.openloadflow.network.LfBranch; import com.powsybl.openloadflow.network.PiModel; @@ -16,29 +17,61 @@ */ abstract class AbstractBranchAcFlowEquationTerm extends AbstractElementEquationTerm { - protected final double b1; - protected final double b2; - protected final double g1; - protected final double g2; - protected final double y; - protected final double ksi; - protected final double g12; - protected final double b12; + protected final AcVectorEngine acVectorEnginee; + protected final int branchNum; - protected AbstractBranchAcFlowEquationTerm(LfBranch branch) { + protected AbstractBranchAcFlowEquationTerm(LfBranch branch, AcVectorEngine acVectorEnginee) { super(branch); PiModel piModel = branch.getPiModel(); if (piModel.getR() == 0 && piModel.getX() == 0) { throw new IllegalArgumentException("Non impedant branch not supported: " + branch.getId()); } - b1 = piModel.getB1(); - b2 = piModel.getB2(); - g1 = piModel.getG1(); - g2 = piModel.getG2(); - y = piModel.getY(); - ksi = piModel.getKsi(); - // y12 = g12+j.b12 = 1/(r+j.x) - g12 = piModel.getR() * y * y; - b12 = -piModel.getX() * y * y; + branchNum = branch.getNum(); + this.acVectorEnginee = acVectorEnginee; + if (!acVectorEnginee.networkDataInitialized[branchNum]) { + acVectorEnginee.b1[branchNum] = piModel.getB1(); + acVectorEnginee.b2[branchNum] = piModel.getB2(); + acVectorEnginee.g1[branchNum] = piModel.getG1(); + acVectorEnginee.g2[branchNum] = piModel.getG2(); + acVectorEnginee.y[branchNum] = piModel.getY(); + acVectorEnginee.ksi[branchNum] = piModel.getKsi(); + // y12 = g12+j.b12 = 1/(r+j.x) + acVectorEnginee.g12[branchNum] = piModel.getR() * y() * y(); + acVectorEnginee.b12[branchNum] = -piModel.getX() * y() * y(); + acVectorEnginee.networkDataInitialized[branchNum] = true; + } + } + + protected double b1() { + return acVectorEnginee.b1[branchNum]; + } + + protected double b2() { + return acVectorEnginee.b2[branchNum]; + } + + protected double g1() { + return acVectorEnginee.g1[branchNum]; + } + + protected double g2() { + return acVectorEnginee.g2[branchNum]; } + + protected double y() { + return acVectorEnginee.y[branchNum]; + } + + protected double ksi() { + return acVectorEnginee.ksi[branchNum]; + } + + protected double g12() { + return acVectorEnginee.g12[branchNum]; + } + + protected double b12() { + return acVectorEnginee.b12[branchNum]; + } + } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractClosedBranchAcFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractClosedBranchAcFlowEquationTerm.java index 2e910c7205..f9e992c286 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractClosedBranchAcFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractClosedBranchAcFlowEquationTerm.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -8,15 +8,19 @@ package com.powsybl.openloadflow.ac.equations; import com.powsybl.math.matrix.DenseMatrix; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; +import com.powsybl.openloadflow.equations.Equation; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBranch; import com.powsybl.openloadflow.network.LfBus; +import com.powsybl.openloadflow.network.PiModelArray; import com.powsybl.openloadflow.util.Fortescue; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.function.DoubleSupplier; import static com.powsybl.openloadflow.network.PiModel.A2; @@ -37,6 +41,12 @@ public abstract class AbstractClosedBranchAcFlowEquationTerm extends AbstractBra protected final Variable r1Var; + private final boolean isArrayPiModel; + + private final double a1; + + private final double r1; + protected final List> variables = new ArrayList<>(); public static AcVariableType getVoltageMagnitudeType(Fortescue.SequenceType sequenceType) { @@ -56,8 +66,8 @@ public static AcVariableType getVoltageAngleType(Fortescue.SequenceType sequence } protected AbstractClosedBranchAcFlowEquationTerm(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet, - boolean deriveA1, boolean deriveR1, Fortescue.SequenceType sequenceType) { - super(branch); + boolean deriveA1, boolean deriveR1, Fortescue.SequenceType sequenceType, AcVectorEngine acVectorEnginee) { + super(branch, acVectorEnginee); Objects.requireNonNull(bus1); Objects.requireNonNull(bus2); Objects.requireNonNull(variableSet); @@ -67,6 +77,20 @@ protected AbstractClosedBranchAcFlowEquationTerm(LfBranch branch, LfBus bus1, Lf v2Var = variableSet.getVariable(bus2.getNum(), vType); ph1Var = variableSet.getVariable(bus1.getNum(), angleType); ph2Var = variableSet.getVariable(bus2.getNum(), angleType); + // Just equations with V and phi are vectorized + if (vType == AcVariableType.BUS_V) { + acVectorEnginee.v1Var[branch.getNum()] = v1Var; + acVectorEnginee.v2Var[branch.getNum()] = v2Var; + } + if (angleType == AcVariableType.BUS_PHI) { + acVectorEnginee.ph1Var[branch.getNum()] = ph1Var; + acVectorEnginee.ph2Var[branch.getNum()] = ph2Var; + } + + isArrayPiModel = branch.getPiModel() instanceof PiModelArray; + a1 = isArrayPiModel ? Double.NaN : branch.getPiModel().getA1(); + r1 = isArrayPiModel ? Double.NaN : branch.getPiModel().getR1(); + a1Var = deriveA1 ? variableSet.getVariable(branch.getNum(), AcVariableType.BRANCH_ALPHA1) : null; r1Var = deriveR1 ? variableSet.getVariable(branch.getNum(), AcVariableType.BRANCH_RHO1) : null; variables.add(v1Var); @@ -75,12 +99,38 @@ protected AbstractClosedBranchAcFlowEquationTerm(LfBranch branch, LfBus bus1, Lf variables.add(ph2Var); if (a1Var != null) { variables.add(a1Var); + } else { + acVectorEnginee.a1[branch.getNum()] = branch.getPiModel().getA1(); } if (r1Var != null) { variables.add(r1Var); } } + @Override + public void setEquation(Equation equation) { + super.setEquation(equation); + if (equation != null) { + acVectorEnginee.addSupplyingTerm(this); + } + } + + public DoubleSupplier getR1Supplier() { + if (r1Var != null || isArrayPiModel) { + return () -> r1(); + } else { + return null; + } + } + + public DoubleSupplier getA1Supplier() { + if (a1Var != null || isArrayPiModel) { + return () -> a1(); + } else { + return null; + } + } + public Variable getA1Var() { return a1Var; } @@ -101,12 +151,18 @@ protected double ph2() { return sv.get(ph2Var.getRow()); } - protected double r1() { - return r1Var != null ? sv.get(r1Var.getRow()) : element.getPiModel().getR1(); + public double r1() { + // TODO: Remove test on var row - should not be called if term is inactive + return r1Var != null && r1Var.getRow() >= 0 ? sv.get(r1Var.getRow()) : + isArrayPiModel ? element.getPiModel().getR1() : r1; + // to avoid memory cache miss we don't load the piModel if not necessary } - protected double a1() { - return a1Var != null ? sv.get(a1Var.getRow()) : element.getPiModel().getA1(); + public double a1() { + // TODO remove test >0 - should not be called if term is inactive + return a1Var != null && a1Var.getRow() >= 0 ? sv.get(a1Var.getRow()) : + isArrayPiModel ? element.getPiModel().getA1() : a1; + // to avoid memory cache miss we don't load the piModel if not necessary } public static double theta1(double ksi, double ph1, double a1, double ph2) { diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractOpenSide1BranchAcFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractOpenSide1BranchAcFlowEquationTerm.java index 8d4342555b..90c83c63c3 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractOpenSide1BranchAcFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractOpenSide1BranchAcFlowEquationTerm.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -7,6 +7,7 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBranch; @@ -22,8 +23,8 @@ abstract class AbstractOpenSide1BranchAcFlowEquationTerm extends AbstractBranchA protected final List> variables; protected AbstractOpenSide1BranchAcFlowEquationTerm(LfBranch branch, AcVariableType variableType, - LfBus bus, VariableSet variableSet) { - super(branch); + LfBus bus, VariableSet variableSet, AcVectorEngine acVectorEnginee) { + super(branch, acVectorEnginee); variables = List.of(variableSet.getVariable(bus.getNum(), variableType)); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractOpenSide2BranchAcFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractOpenSide2BranchAcFlowEquationTerm.java index db44644a72..e84f27f957 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractOpenSide2BranchAcFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AbstractOpenSide2BranchAcFlowEquationTerm.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -7,6 +7,7 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBranch; @@ -22,8 +23,8 @@ abstract class AbstractOpenSide2BranchAcFlowEquationTerm extends AbstractBranchA protected final List> variables; protected AbstractOpenSide2BranchAcFlowEquationTerm(LfBranch branch, AcVariableType variableType, - LfBus bus, VariableSet variableSet) { - super(branch); + LfBus bus, VariableSet variableSet, AcVectorEngine acVectorEngine) { + super(branch, acVectorEngine); variables = List.of(variableSet.getVariable(bus.getNum(), variableType)); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystemCreator.java b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystemCreator.java index afef8792a9..2854a22dc0 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystemCreator.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystemCreator.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -9,6 +9,7 @@ import com.powsybl.commons.PowsyblException; import com.powsybl.iidm.network.TwoSides; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.*; import com.powsybl.openloadflow.network.*; import com.powsybl.openloadflow.network.TransformerPhaseControl.Mode; @@ -82,9 +83,9 @@ private void createLoadEquations(LfBus bus, EquationSystem equationSystem) { + private void createVoltageControlEquations(EquationSystem equationSystem, AcVectorEngine acVectorEnginee) { for (LfBus bus : network.getBuses()) { - createGeneratorVoltageControlEquations(bus, equationSystem); + createGeneratorVoltageControlEquations(bus, equationSystem, acVectorEnginee); createTransformerVoltageControlEquations(bus, equationSystem); createShuntVoltageControlEquations(bus, equationSystem); } @@ -97,16 +98,17 @@ private void createBusesEquations(EquationSystem } private void createGeneratorVoltageControlEquations(LfBus bus, - EquationSystem equationSystem) { + EquationSystem equationSystem, + AcVectorEngine acVectorEnginee) { bus.getGeneratorVoltageControl() .filter(voltageControl -> voltageControl.getMergeStatus() == VoltageControl.MergeStatus.MAIN) .ifPresent(voltageControl -> { if (bus.isGeneratorVoltageControlled()) { if (voltageControl.isLocalControl()) { - createGeneratorLocalVoltageControlEquation(bus, equationSystem); + createGeneratorLocalVoltageControlEquation(bus, equationSystem, acVectorEnginee); } else { // create reactive power distribution equations at voltage controller buses - createGeneratorReactivePowerDistributionEquations(voltageControl, equationSystem, creationParameters); + createGeneratorReactivePowerDistributionEquations(voltageControl, equationSystem, creationParameters, acVectorEnginee); } updateGeneratorVoltageControl(voltageControl, equationSystem); } @@ -114,7 +116,7 @@ private void createGeneratorVoltageControlEquations(LfBus bus, } private void createGeneratorLocalVoltageControlEquation(LfBus bus, - EquationSystem equationSystem) { + EquationSystem equationSystem, AcVectorEngine acVectorEnginee) { if (bus.hasGeneratorsWithSlope()) { // take first generator with slope: network loading ensures that there's only one generator with slope double slope = bus.getGeneratorsControllingVoltageWithSlope().get(0).getSlope(); @@ -123,7 +125,7 @@ private void createGeneratorLocalVoltageControlEquation(LfBus bus, // equation is: V + slope * qSVC = targetV // which is modeled here with: V + slope * (sum_branch qBranch) = TargetV - slope * qLoads + slope * qGenerators equationSystem.getEquation(bus.getNum(), AcEquationType.BUS_TARGET_V).orElseThrow() - .addTerms(createReactiveTerms(bus, equationSystem.getVariableSet(), creationParameters) + .addTerms(createReactiveTerms(bus, equationSystem.getVariableSet(), creationParameters, acVectorEnginee) .stream() .map(term -> term.multiply(slope)) .collect(Collectors.toList())); @@ -135,15 +137,15 @@ private void createGeneratorLocalVoltageControlEquation(LfBus bus, } protected void createGeneratorReactivePowerControlBranchEquation(LfBranch branch, LfBus bus1, LfBus bus2, EquationSystem equationSystem, - boolean deriveA1, boolean deriveR1) { + boolean deriveA1, boolean deriveR1, AcVectorEngine acVectorEnginee) { if (bus1 != null && bus2 != null) { branch.getGeneratorReactivePowerControl().ifPresent(rpc -> { EquationTerm q = rpc.getControlledSide() == TwoSides.ONE - ? new ClosedBranchSide1ReactiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1) - : new ClosedBranchSide2ReactiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1); + ? new ClosedBranchSide1ReactiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, acVectorEnginee) + : new ClosedBranchSide2ReactiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, acVectorEnginee); equationSystem.createEquation(branch, AcEquationType.BRANCH_TARGET_Q) .addTerm(q); - createGeneratorReactivePowerDistributionEquations(rpc, equationSystem, creationParameters); + createGeneratorReactivePowerDistributionEquations(rpc, equationSystem, creationParameters, acVectorEnginee); updateGeneratorReactivePowerControlBranchEquations(rpc, equationSystem); }); } @@ -216,7 +218,7 @@ private static void createShuntEquations(LfBus bus, EquationSystem equationSystem, - AcEquationSystemCreationParameters creationParameters) { + AcEquationSystemCreationParameters creationParameters, AcVectorEngine acVectorEnginee) { List controllerBuses = null; if (control instanceof GeneratorVoltageControl generatorVoltageControl) { controllerBuses = generatorVoltageControl.getMergedControllerElements(); @@ -233,7 +235,7 @@ private static void createGeneratorReactivePowerDistributionEquations(Control co // which can be rewritten in a more simple way // 0 = (qPercent_i - 1) * q_i + qPercent_i * sum_j(q_j) where j are all the voltage controller buses except i Equation zero = equationSystem.createEquation(controllerBus, AcEquationType.DISTR_Q) - .addTerms(createReactiveTerms(controllerBus, equationSystem.getVariableSet(), creationParameters).stream() + .addTerms(createReactiveTerms(controllerBus, equationSystem.getVariableSet(), creationParameters, acVectorEnginee).stream() .map(term -> term.multiply(() -> controllerBus.getRemoteControlReactivePercent() - 1)) .collect(Collectors.toList())); // to update open/close terms activation @@ -242,7 +244,7 @@ private static void createGeneratorReactivePowerDistributionEquations(Control co } for (LfBus otherControllerBus : controllerBuses) { if (otherControllerBus != controllerBus) { - zero.addTerms(createReactiveTerms(otherControllerBus, equationSystem.getVariableSet(), creationParameters).stream() + zero.addTerms(createReactiveTerms(otherControllerBus, equationSystem.getVariableSet(), creationParameters, acVectorEnginee).stream() .map(term -> term.multiply(controllerBus::getRemoteControlReactivePercent)) .collect(Collectors.toList())); } @@ -266,12 +268,13 @@ private static void removeEquationAndCleanElement(LfNetwork network, EquationSys public static void recreateReactivePowerDistributionEquations(LfNetwork network, GeneratorVoltageControl voltageControl, EquationSystem equationSystem, - AcEquationSystemCreationParameters parameters) { + AcEquationSystemCreationParameters parameters, + AcVectorEngine acVectorEnginee) { for (LfBus controllerBus : voltageControl.getMergedControllerElements()) { removeEquationAndCleanElement(network, equationSystem, controllerBus.getNum(), AcEquationType.DISTR_Q); } if (!voltageControl.isLocalControl()) { - createGeneratorReactivePowerDistributionEquations(voltageControl, equationSystem, parameters); + createGeneratorReactivePowerDistributionEquations(voltageControl, equationSystem, parameters, acVectorEnginee); } updateGeneratorVoltageControl(voltageControl, equationSystem); } @@ -346,7 +349,8 @@ static void updateRemoteVoltageControlEquations(VoltageCon private static List> createReactiveTerms(LfBus controllerBus, VariableSet variableSet, - AcEquationSystemCreationParameters creationParameters) { + AcEquationSystemCreationParameters creationParameters, + AcVectorEngine acVectorEnginee) { List> terms = new ArrayList<>(); for (LfBranch branch : controllerBus.getBranches()) { EquationTerm q; @@ -367,27 +371,27 @@ private static List> createReactive if (branch.getBus1() == controllerBus) { LfBus otherSideBus = branch.getBus2(); if (otherSideBus != null) { - q = new ClosedBranchSide1ReactiveFlowEquationTerm(branch, controllerBus, otherSideBus, variableSet, deriveA1, deriveR1); + q = new ClosedBranchSide1ReactiveFlowEquationTerm(branch, controllerBus, otherSideBus, variableSet, deriveA1, deriveR1, acVectorEnginee); branch.addAdditionalClosedQ1(q); if (branch.isDisconnectionAllowedSide2()) { - openQ = new OpenBranchSide2ReactiveFlowEquationTerm(branch, controllerBus, variableSet); + openQ = new OpenBranchSide2ReactiveFlowEquationTerm(branch, controllerBus, variableSet, acVectorEnginee); branch.addAdditionalOpenQ1(openQ); } } else { - q = new OpenBranchSide2ReactiveFlowEquationTerm(branch, controllerBus, variableSet); + q = new OpenBranchSide2ReactiveFlowEquationTerm(branch, controllerBus, variableSet, acVectorEnginee); branch.addAdditionalOpenQ1(q); } } else { LfBus otherSideBus = branch.getBus1(); if (otherSideBus != null) { - q = new ClosedBranchSide2ReactiveFlowEquationTerm(branch, otherSideBus, controllerBus, variableSet, deriveA1, deriveR1); + q = new ClosedBranchSide2ReactiveFlowEquationTerm(branch, otherSideBus, controllerBus, variableSet, deriveA1, deriveR1, acVectorEnginee); branch.addAdditionalClosedQ2(q); if (branch.isDisconnectionAllowedSide1()) { - openQ = new OpenBranchSide1ReactiveFlowEquationTerm(branch, controllerBus, variableSet); + openQ = new OpenBranchSide1ReactiveFlowEquationTerm(branch, controllerBus, variableSet, acVectorEnginee); branch.addAdditionalOpenQ2(openQ); } } else { - q = new OpenBranchSide1ReactiveFlowEquationTerm(branch, controllerBus, variableSet); + q = new OpenBranchSide1ReactiveFlowEquationTerm(branch, controllerBus, variableSet, acVectorEnginee); branch.addAdditionalOpenQ2(q); } } @@ -503,7 +507,7 @@ private static void createNonImpedantBranch(LfBranch branch, LfBus bus1, LfBus b } protected static void createTransformerPhaseControlEquations(LfBranch branch, LfBus bus1, LfBus bus2, EquationSystem equationSystem, - boolean deriveA1, boolean deriveR1) { + boolean deriveA1, boolean deriveR1, AcVectorEngine acVectorEnginee) { if (deriveA1) { EquationTerm a1 = equationSystem.getVariable(branch.getNum(), AcVariableType.BRANCH_ALPHA1) .createTerm(); @@ -520,8 +524,8 @@ protected static void createTransformerPhaseControlEquations(LfBranch branch, Lf } EquationTerm p = phaseControl.getControlledSide() == TwoSides.ONE - ? new ClosedBranchSide1ActiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1) - : new ClosedBranchSide2ActiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1); + ? new ClosedBranchSide1ActiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, acVectorEnginee) + : new ClosedBranchSide2ActiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, acVectorEnginee); equationSystem.createEquation(branch, AcEquationType.BRANCH_TARGET_P) .addTerm(p) .setActive(false); // by default BRANCH_TARGET_ALPHA1 is active and BRANCH_TARGET_P inactive @@ -680,7 +684,7 @@ protected static boolean isDeriveR1(LfBranch branch) { } protected void createImpedantBranch(LfBranch branch, LfBus bus1, LfBus bus2, - EquationSystem equationSystem) { + EquationSystem equationSystem, AcVectorEngine acVectorEnginee) { // effective equations, could be closed one or open one Evaluable p1 = null; Evaluable q1 = null; @@ -708,21 +712,21 @@ protected void createImpedantBranch(LfBranch branch, LfBus bus1, LfBus bus2, boolean deriveA1 = isDeriveA1(branch, creationParameters); boolean deriveR1 = isDeriveR1(branch); if (bus1 != null && bus2 != null) { - closedP1 = new ClosedBranchSide1ActiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1); - closedQ1 = new ClosedBranchSide1ReactiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1); - closedP2 = new ClosedBranchSide2ActiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1); - closedQ2 = new ClosedBranchSide2ReactiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1); - closedI1 = new ClosedBranchSide1CurrentMagnitudeEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1); - closedI2 = new ClosedBranchSide2CurrentMagnitudeEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1); + closedP1 = new ClosedBranchSide1ActiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, acVectorEnginee); + closedQ1 = new ClosedBranchSide1ReactiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, acVectorEnginee); + closedP2 = new ClosedBranchSide2ActiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, acVectorEnginee); + closedQ2 = new ClosedBranchSide2ReactiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, acVectorEnginee); + closedI1 = new ClosedBranchSide1CurrentMagnitudeEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, acVectorEnginee); + closedI2 = new ClosedBranchSide2CurrentMagnitudeEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, acVectorEnginee); if (branch.isDisconnectionAllowedSide1()) { - openP2 = new OpenBranchSide1ActiveFlowEquationTerm(branch, bus2, equationSystem.getVariableSet()); - openQ2 = new OpenBranchSide1ReactiveFlowEquationTerm(branch, bus2, equationSystem.getVariableSet()); - openI2 = new OpenBranchSide1CurrentMagnitudeEquationTerm(branch, bus2, equationSystem.getVariableSet()); + openP2 = new OpenBranchSide1ActiveFlowEquationTerm(branch, bus2, equationSystem.getVariableSet(), acVectorEnginee); + openQ2 = new OpenBranchSide1ReactiveFlowEquationTerm(branch, bus2, equationSystem.getVariableSet(), acVectorEnginee); + openI2 = new OpenBranchSide1CurrentMagnitudeEquationTerm(branch, bus2, equationSystem.getVariableSet(), acVectorEnginee); } if (branch.isDisconnectionAllowedSide2()) { - openP1 = new OpenBranchSide2ActiveFlowEquationTerm(branch, bus1, equationSystem.getVariableSet()); - openQ1 = new OpenBranchSide2ReactiveFlowEquationTerm(branch, bus1, equationSystem.getVariableSet()); - openI1 = new OpenBranchSide2CurrentMagnitudeEquationTerm(branch, bus1, equationSystem.getVariableSet(), deriveR1); + openP1 = new OpenBranchSide2ActiveFlowEquationTerm(branch, bus1, equationSystem.getVariableSet(), acVectorEnginee); + openQ1 = new OpenBranchSide2ReactiveFlowEquationTerm(branch, bus1, equationSystem.getVariableSet(), acVectorEnginee); + openI1 = new OpenBranchSide2CurrentMagnitudeEquationTerm(branch, bus1, equationSystem.getVariableSet(), deriveR1, acVectorEnginee); } p1 = closedP1; q1 = closedQ1; @@ -731,9 +735,9 @@ protected void createImpedantBranch(LfBranch branch, LfBus bus1, LfBus bus2, q2 = closedQ2; i2 = closedI2; } else if (bus1 != null) { - openP1 = new OpenBranchSide2ActiveFlowEquationTerm(branch, bus1, equationSystem.getVariableSet()); - openQ1 = new OpenBranchSide2ReactiveFlowEquationTerm(branch, bus1, equationSystem.getVariableSet()); - openI1 = new OpenBranchSide2CurrentMagnitudeEquationTerm(branch, bus1, equationSystem.getVariableSet(), deriveR1); + openP1 = new OpenBranchSide2ActiveFlowEquationTerm(branch, bus1, equationSystem.getVariableSet(), acVectorEnginee); + openQ1 = new OpenBranchSide2ReactiveFlowEquationTerm(branch, bus1, equationSystem.getVariableSet(), acVectorEnginee); + openI1 = new OpenBranchSide2CurrentMagnitudeEquationTerm(branch, bus1, equationSystem.getVariableSet(), deriveR1, acVectorEnginee); p1 = openP1; q1 = openQ1; i1 = openI1; @@ -741,9 +745,9 @@ protected void createImpedantBranch(LfBranch branch, LfBus bus1, LfBus bus2, q2 = EvaluableConstants.ZERO; i2 = EvaluableConstants.ZERO; } else if (bus2 != null) { - openP2 = new OpenBranchSide1ActiveFlowEquationTerm(branch, bus2, equationSystem.getVariableSet()); - openQ2 = new OpenBranchSide1ReactiveFlowEquationTerm(branch, bus2, equationSystem.getVariableSet()); - openI2 = new OpenBranchSide1CurrentMagnitudeEquationTerm(branch, bus2, equationSystem.getVariableSet()); + openP2 = new OpenBranchSide1ActiveFlowEquationTerm(branch, bus2, equationSystem.getVariableSet(), acVectorEnginee); + openQ2 = new OpenBranchSide1ReactiveFlowEquationTerm(branch, bus2, equationSystem.getVariableSet(), acVectorEnginee); + openI2 = new OpenBranchSide1CurrentMagnitudeEquationTerm(branch, bus2, equationSystem.getVariableSet(), acVectorEnginee); p1 = EvaluableConstants.ZERO; q1 = EvaluableConstants.ZERO; i1 = EvaluableConstants.ZERO; @@ -760,9 +764,9 @@ protected void createImpedantBranch(LfBranch branch, LfBus bus1, LfBus bus2, openP1, openQ1, openI1, openP2, openQ2, openI2); - createGeneratorReactivePowerControlBranchEquation(branch, bus1, bus2, equationSystem, deriveA1, deriveR1); + createGeneratorReactivePowerControlBranchEquation(branch, bus1, bus2, equationSystem, deriveA1, deriveR1, acVectorEnginee); - createTransformerPhaseControlEquations(branch, bus1, bus2, equationSystem, deriveA1, deriveR1); + createTransformerPhaseControlEquations(branch, bus1, bus2, equationSystem, deriveA1, deriveR1, acVectorEnginee); updateBranchEquations(branch); @@ -953,7 +957,7 @@ private static void createHvdcAcEmulationEquations(LfHvdc hvdc, EquationSystem equationSystem) { + EquationSystem equationSystem, AcVectorEngine acVectorEnginee) { branch.getAdditionalOpenP1().clear(); branch.getAdditionalOpenQ1().clear(); branch.getAdditionalClosedP1().clear(); @@ -967,18 +971,19 @@ private void createImpedantBranchEquations(LfBranch branch, if (branch.isZeroImpedance(LoadFlowModel.AC)) { createNonImpedantBranch(branch, branch.getBus1(), branch.getBus2(), equationSystem, branch.isSpanningTreeEdge(LoadFlowModel.AC)); } else { - createImpedantBranch(branch, branch.getBus1(), branch.getBus2(), equationSystem); + createImpedantBranch(branch, branch.getBus1(), branch.getBus2(), equationSystem, acVectorEnginee); } } - private void createBranchesEquations(EquationSystem equationSystem) { + private void createBranchesEquations(EquationSystem equationSystem, AcVectorEngine acVectorEnginee) { for (LfBranch branch : network.getBranches()) { - createImpedantBranchEquations(branch, equationSystem); + createImpedantBranchEquations(branch, equationSystem, acVectorEnginee); } } private List> createActiveInjectionTerms(LfBus bus, - VariableSet variableSet) { + VariableSet variableSet, + AcVectorEngine acVectorEnginee) { List> terms = new ArrayList<>(); for (LfBranch branch : bus.getBranches()) { if (branch.isZeroImpedance(LoadFlowModel.AC)) { @@ -997,27 +1002,27 @@ private List> createActiveInjection if (branch.getBus1() == bus) { LfBus otherSideBus = branch.getBus2(); if (otherSideBus != null) { - p = new ClosedBranchSide1ActiveFlowEquationTerm(branch, bus, otherSideBus, variableSet, deriveA1, deriveR1); + p = new ClosedBranchSide1ActiveFlowEquationTerm(branch, bus, otherSideBus, variableSet, deriveA1, deriveR1, acVectorEnginee); branch.addAdditionalClosedP1(p); if (branch.isDisconnectionAllowedSide2()) { - openP = new OpenBranchSide2ActiveFlowEquationTerm(branch, bus, variableSet); + openP = new OpenBranchSide2ActiveFlowEquationTerm(branch, bus, variableSet, acVectorEnginee); branch.addAdditionalOpenP1(openP); } } else { - p = new OpenBranchSide2ActiveFlowEquationTerm(branch, bus, variableSet); + p = new OpenBranchSide2ActiveFlowEquationTerm(branch, bus, variableSet, acVectorEnginee); branch.addAdditionalOpenP1(p); } } else { LfBus otherSideBus = branch.getBus1(); if (otherSideBus != null) { - p = new ClosedBranchSide2ActiveFlowEquationTerm(branch, otherSideBus, bus, variableSet, deriveA1, deriveR1); + p = new ClosedBranchSide2ActiveFlowEquationTerm(branch, otherSideBus, bus, variableSet, deriveA1, deriveR1, acVectorEnginee); branch.addAdditionalClosedP2(p); if (branch.isDisconnectionAllowedSide1()) { - openP = new OpenBranchSide1ActiveFlowEquationTerm(branch, bus, variableSet); + openP = new OpenBranchSide1ActiveFlowEquationTerm(branch, bus, variableSet, acVectorEnginee); branch.addAdditionalOpenP2(openP); } } else { - p = new OpenBranchSide1ActiveFlowEquationTerm(branch, bus, variableSet); + p = new OpenBranchSide1ActiveFlowEquationTerm(branch, bus, variableSet, acVectorEnginee); branch.addAdditionalOpenP2(p); } } @@ -1030,7 +1035,7 @@ private List> createActiveInjection return terms; } - private void createMultipleSlackBusesEquations(EquationSystem equationSystem) { + private void createMultipleSlackBusesEquations(EquationSystem equationSystem, AcVectorEngine acVectorEnginee) { List slackBuses = network.getSlackBuses(); if (slackBuses.size() > 1) { LfBus firstSlackBus = slackBuses.get(0); @@ -1040,10 +1045,10 @@ private void createMultipleSlackBusesEquations(EquationSystem create() { EquationSystem equationSystem = new EquationSystem<>(); + AcVectorEngine acVectorEnginee = new AcVectorEngine(this.network, equationSystem); createBusesEquations(equationSystem); - createMultipleSlackBusesEquations(equationSystem); - createBranchesEquations(equationSystem); + createMultipleSlackBusesEquations(equationSystem, acVectorEnginee); + createBranchesEquations(equationSystem, acVectorEnginee); for (LfHvdc hvdc : network.getHvdcs()) { createHvdcAcEmulationEquations(hvdc, equationSystem); } - createVoltageControlEquations(equationSystem); + createVoltageControlEquations(equationSystem, acVectorEnginee); EquationSystemPostProcessor.findAll().forEach(pp -> pp.onCreate(equationSystem)); - network.addListener(LfNetworkListenerTracer.trace(new AcEquationSystemUpdater(equationSystem, creationParameters))); + network.addListener(LfNetworkListenerTracer.trace(new AcEquationSystemUpdater(equationSystem, creationParameters, acVectorEnginee))); return equationSystem; } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystemUpdater.java b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystemUpdater.java index a8773a17a7..454ab66fdd 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystemUpdater.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/AcEquationSystemUpdater.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2021, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2021-2025, 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/. @@ -8,6 +8,7 @@ package com.powsybl.openloadflow.ac.equations; import com.powsybl.iidm.network.TwoSides; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.EquationSystem; import com.powsybl.openloadflow.lf.AbstractEquationSystemUpdater; import com.powsybl.openloadflow.network.*; @@ -22,11 +23,13 @@ public class AcEquationSystemUpdater extends AbstractEquationSystemUpdater { private final AcEquationSystemCreationParameters parameters; + private final AcVectorEngine acVectorEnginee; public AcEquationSystemUpdater(EquationSystem equationSystem, - AcEquationSystemCreationParameters parameters) { + AcEquationSystemCreationParameters parameters, AcVectorEngine acVectorEnginee) { super(equationSystem, LoadFlowModel.AC); this.parameters = Objects.requireNonNull(parameters); + this.acVectorEnginee = acVectorEnginee; } private void updateVoltageControls(LfBus bus) { @@ -131,7 +134,8 @@ private void recreateDistributionEquations(LfZeroImpedanceNetwork network) { for (LfBus bus : network.getGraph().vertexSet()) { bus.getGeneratorVoltageControl() .filter(voltageControl -> voltageControl.getMergeStatus() == VoltageControl.MergeStatus.MAIN) - .ifPresent(voltageControl -> AcEquationSystemCreator.recreateReactivePowerDistributionEquations(bus.getNetwork(), voltageControl, equationSystem, parameters)); + .ifPresent(voltageControl -> AcEquationSystemCreator + .recreateReactivePowerDistributionEquations(bus.getNetwork(), voltageControl, equationSystem, parameters, acVectorEnginee)); bus.getTransformerVoltageControl() .filter(voltageControl -> voltageControl.getMergeStatus() == VoltageControl.MergeStatus.MAIN) .ifPresent(voltageControl -> AcEquationSystemCreator.recreateR1DistributionEquations(bus.getNetwork(), voltageControl, equationSystem)); diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchI1xFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchI1xFlowEquationTerm.java index c9fea8a908..c4ace73a4b 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchI1xFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchI1xFlowEquationTerm.java @@ -1,6 +1,5 @@ -/** - * Copyright (c) 2023, Jean-Baptiste Heyberger - * Copyright (c) 2023, Geoffroy Jamgotchian +/* + * Copyright (c) 2023-2025, 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/. @@ -8,6 +7,7 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBranch; @@ -24,8 +24,8 @@ public class ClosedBranchI1xFlowEquationTerm extends AbstractClosedBranchAcFlowEquationTerm { public ClosedBranchI1xFlowEquationTerm(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet, - boolean deriveA1, boolean deriveR1, Fortescue.SequenceType sequenceType) { - super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, sequenceType); + boolean deriveA1, boolean deriveR1, Fortescue.SequenceType sequenceType, AcVectorEngine acVectorEnginee) { + super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, sequenceType, acVectorEnginee); } public double calculateSensi(double dph1, double dph2, double dv1, double dv2, double da1, double dr1) { @@ -61,20 +61,20 @@ private static double di1xdph2(double v2, double ph2, double g12, double b12) { @Override public double eval() { - return i1x(g1, b1, v1(), ph1(), v2(), ph2(), g12, b12); + return i1x(g1(), b1(), v1(), ph1(), v2(), ph2(), g12(), b12()); } @Override public double der(Variable variable) { Objects.requireNonNull(variable); if (variable.equals(v1Var)) { - return di1xdv1(g1, b1, ph1(), g12, b12); + return di1xdv1(g1(), b1(), ph1(), g12(), b12()); } else if (variable.equals(v2Var)) { - return di1xdv2(ph2(), g12, b12); + return di1xdv2(ph2(), g12(), b12()); } else if (variable.equals(ph1Var)) { - return di1xdph1(g1, b1, v1(), ph1(), g12, b12); + return di1xdph1(g1(), b1(), v1(), ph1(), g12(), b12()); } else if (variable.equals(ph2Var)) { - return di1xdph2(v2(), ph2(), g12, b12); + return di1xdph2(v2(), ph2(), g12(), b12()); } else { throw new IllegalStateException("Unexpected variable: " + variable); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchI1yFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchI1yFlowEquationTerm.java index 8418373a14..03a1ae8a40 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchI1yFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchI1yFlowEquationTerm.java @@ -1,6 +1,5 @@ -/** - * Copyright (c) 2023, Jean-Baptiste Heyberger - * Copyright (c) 2023, Geoffroy Jamgotchian +/* + * Copyright (c) 2023-2025, 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/. @@ -8,6 +7,7 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBranch; @@ -24,8 +24,8 @@ public class ClosedBranchI1yFlowEquationTerm extends AbstractClosedBranchAcFlowEquationTerm { public ClosedBranchI1yFlowEquationTerm(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet, - boolean deriveA1, boolean deriveR1, Fortescue.SequenceType sequenceType) { - super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, sequenceType); + boolean deriveA1, boolean deriveR1, Fortescue.SequenceType sequenceType, AcVectorEngine acVectorEnginee) { + super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, sequenceType, acVectorEnginee); } public double calculateSensi(double dph1, double dph2, double dv1, double dv2, double da1, double dr1) { @@ -61,20 +61,20 @@ private static double di1ydph2(double v2, double ph2, double g12, double b12) { @Override public double eval() { - return i1y(g1, b1, v1(), ph1(), v2(), ph2(), g12, b12); + return i1y(g1(), b1(), v1(), ph1(), v2(), ph2(), g12(), b12()); } @Override public double der(Variable variable) { Objects.requireNonNull(variable); if (variable.equals(v1Var)) { - return di1ydv1(g1, b1, ph1(), g12, b12); + return di1ydv1(g1(), b1(), ph1(), g12(), b12()); } else if (variable.equals(v2Var)) { - return di1ydv2(ph2(), g12, b12); + return di1ydv2(ph2(), g12(), b12()); } else if (variable.equals(ph1Var)) { - return di1ydph1(g1, b1, v1(), ph1(), g12, b12); + return di1ydph1(g1(), b1(), v1(), ph1(), g12(), b12()); } else if (variable.equals(ph2Var)) { - return di1ydph2(v2(), ph2(), g12, b12); + return di1ydph2(v2(), ph2(), g12(), b12()); } else { throw new IllegalStateException("Unexpected variable: " + variable); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchI2xFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchI2xFlowEquationTerm.java index f7b684f3e4..16c38b57ae 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchI2xFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchI2xFlowEquationTerm.java @@ -1,6 +1,5 @@ -/** - * Copyright (c) 2023, Jean-Baptiste Heyberger - * Copyright (c) 2023, Geoffroy Jamgotchian +/* + * Copyright (c) 2023-2025, 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/. @@ -8,6 +7,7 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBranch; @@ -24,8 +24,8 @@ public class ClosedBranchI2xFlowEquationTerm extends AbstractClosedBranchAcFlowEquationTerm { public ClosedBranchI2xFlowEquationTerm(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet, - boolean deriveA1, boolean deriveR1, Fortescue.SequenceType sequenceType) { - super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, sequenceType); + boolean deriveA1, boolean deriveR1, Fortescue.SequenceType sequenceType, AcVectorEngine acVectorEnginee) { + super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, sequenceType, acVectorEnginee); } public double calculateSensi(double dph1, double dph2, double dv1, double dv2, double da1, double dr1) { @@ -71,20 +71,20 @@ private static double di2xdph2(double g2, double b2, double v2, double ph2, doub @Override public double eval() { - return i2x(g2, b2, v1(), ph1(), v2(), ph2(), g12, b12); + return i2x(g2(), b2(), v1(), ph1(), v2(), ph2(), g12(), b12()); } @Override public double der(Variable variable) { Objects.requireNonNull(variable); if (variable.equals(v1Var)) { - return di2xdv1(ph1(), g12, b12); + return di2xdv1(ph1(), g12(), b12()); } else if (variable.equals(v2Var)) { - return di2xdv2(g2, b2, ph2(), g12, b12); + return di2xdv2(g2(), b2(), ph2(), g12(), b12()); } else if (variable.equals(ph1Var)) { - return di2xdph1(v1(), ph1(), g12, b12); + return di2xdph1(v1(), ph1(), g12(), b12()); } else if (variable.equals(ph2Var)) { - return di2xdph2(g2, b2, v2(), ph2(), g12, b12); + return di2xdph2(g2(), b2(), v2(), ph2(), g12(), b12()); } else { throw new IllegalStateException("Unexpected variable: " + variable); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchI2yFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchI2yFlowEquationTerm.java index 670c551bcd..84b438d073 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchI2yFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchI2yFlowEquationTerm.java @@ -1,6 +1,5 @@ -/** - * Copyright (c) 2023, Jean-Baptiste Heyberger - * Copyright (c) 2023, Geoffroy Jamgotchian +/* + * Copyright (c) 2023-2025, 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/. @@ -8,6 +7,7 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBranch; @@ -24,8 +24,8 @@ public class ClosedBranchI2yFlowEquationTerm extends AbstractClosedBranchAcFlowEquationTerm { public ClosedBranchI2yFlowEquationTerm(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet, - boolean deriveA1, boolean deriveR1, Fortescue.SequenceType sequenceType) { - super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, sequenceType); + boolean deriveA1, boolean deriveR1, Fortescue.SequenceType sequenceType, AcVectorEngine acVectorEnginee) { + super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, sequenceType, acVectorEnginee); } public double calculateSensi(double dph1, double dph2, double dv1, double dv2, double da1, double dr1) { @@ -71,20 +71,20 @@ private static double di2ydph2(double g2, double b2, double v2, double ph2, doub @Override public double eval() { - return i2y(g2, b2, v1(), ph1(), v2(), ph2(), g12, b12); + return i2y(g2(), b2(), v1(), ph1(), v2(), ph2(), g12(), b12()); } @Override public double der(Variable variable) { Objects.requireNonNull(variable); if (variable.equals(v1Var)) { - return di2ydv1(ph1(), g12, b12); + return di2ydv1(ph1(), g12(), b12()); } else if (variable.equals(v2Var)) { - return di2ydv2(g2, b2, ph2(), g12, b12); + return di2ydv2(g2(), b2(), ph2(), g12(), b12()); } else if (variable.equals(ph1Var)) { - return di2ydph1(v1(), ph1(), g12, b12); + return di2ydph1(v1(), ph1(), g12(), b12()); } else if (variable.equals(ph2Var)) { - return di2ydph2(g2, b2, v2(), ph2(), g12, b12); + return di2ydph2(g2(), b2(), v2(), ph2(), g12(), b12()); } else { throw new IllegalStateException("Unexpected variable: " + variable); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide1ActiveFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide1ActiveFlowEquationTerm.java index 664cba38b6..c9d7310a1e 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide1ActiveFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide1ActiveFlowEquationTerm.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -7,8 +7,10 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; +import com.powsybl.openloadflow.equations.VectorEngine; import com.powsybl.openloadflow.network.LfBranch; import com.powsybl.openloadflow.network.LfBus; import com.powsybl.openloadflow.util.Fortescue; @@ -25,13 +27,29 @@ public class ClosedBranchSide1ActiveFlowEquationTerm extends AbstractClosedBranchAcFlowEquationTerm { public ClosedBranchSide1ActiveFlowEquationTerm(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet, - boolean deriveA1, boolean deriveR1) { - super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, Fortescue.SequenceType.POSITIVE); + boolean deriveA1, boolean deriveR1, AcVectorEngine acVectorEnginee) { + super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, Fortescue.SequenceType.POSITIVE, acVectorEnginee); } public ClosedBranchSide1ActiveFlowEquationTerm(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet, - boolean deriveA1, boolean deriveR1, Fortescue.SequenceType sequenceType) { - super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, sequenceType); + boolean deriveA1, boolean deriveR1, Fortescue.SequenceType sequenceType, AcVectorEngine acVectorEnginee) { + super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, sequenceType, acVectorEnginee); + } + + @Override + public VectorEngine.VecToVal getVecToVal(Variable v) { + if (v == v1Var) { + return ClosedBranchSide1ActiveFlowEquationTerm::vec2dp1dv1; + } else if (v == v2Var) { + return ClosedBranchSide1ActiveFlowEquationTerm::vec2dp1dv2; + } else if (v == ph1Var) { + return ClosedBranchSide1ActiveFlowEquationTerm::vec2dp1dph1; + } else if (v == ph2Var) { + return ClosedBranchSide1ActiveFlowEquationTerm::vec2dp1dph2; + } else if (v == null) { + return ClosedBranchSide1ActiveFlowEquationTerm::vec2p1; + } + return null; } public static double calculateSensi(double g1, double y, double ksi, @@ -50,25 +68,60 @@ public static double calculateSensi(double g1, double y, double ksi, } protected double calculateSensi(double dph1, double dph2, double dv1, double dv2, double da1, double dr1) { - return calculateSensi(g1, y, ksi, v1(), ph1(), a1(), r1(), v2(), ph2(), dph1, dph2, dv1, dv2, da1, dr1); + return calculateSensi(g1(), y(), ksi(), v1(), ph1(), a1(), r1(), v2(), ph2(), dph1, dph2, dv1, dv2, da1, dr1); + } + + public static double vec2p1(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, + double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return p1(y, sinKsi, g1, v1, r1, v2, sinTheta1); } public static double p1(double y, double sinKsi, double g1, double v1, double r1, double v2, double sinTheta) { return r1 * v1 * (g1 * r1 * v1 + y * r1 * v1 * sinKsi - y * R2 * v2 * sinTheta); } + public static double vec2dp1dv1(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, + double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return dp1dv1(y, sinKsi, g1, v1, r1, v2, sinTheta1); + } + public static double dp1dv1(double y, double sinKsi, double g1, double v1, double r1, double v2, double sinTheta) { return r1 * (2 * g1 * r1 * v1 + 2 * y * r1 * v1 * sinKsi - y * R2 * v2 * sinTheta); } + public static double vec2dp1dv2(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, + double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return dp1dv2(y, v1, r1, sinTheta1); + } + public static double dp1dv2(double y, double v1, double r1, double sinTheta) { return -y * r1 * R2 * v1 * sinTheta; } + public static double vec2dp1dph1(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, + double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return dp1dph1(y, v1, r1, v2, cosTheta1); + } + public static double dp1dph1(double y, double v1, double r1, double v2, double cosTheta) { return y * r1 * R2 * v1 * v2 * cosTheta; } + public static double vec2dp1dph2(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, + double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return dp1dph2(y, v1, r1, v2, cosTheta1); + } + public static double dp1dph2(double y, double v1, double r1, double v2, double cosTheta) { return -dp1dph1(y, v1, r1, v2, cosTheta); } @@ -83,25 +136,25 @@ public static double dp1dr1(double y, double sinKsi, double g1, double v1, doubl @Override public double eval() { - return p1(y, FastMath.sin(ksi), g1, v1(), r1(), v2(), FastMath.sin(theta1(ksi, ph1(), a1(), ph2()))); + return p1(y(), FastMath.sin(ksi()), g1(), v1(), r1(), v2(), FastMath.sin(theta1(ksi(), ph1(), a1(), ph2()))); } @Override public double der(Variable variable) { Objects.requireNonNull(variable); - double theta = theta1(ksi, ph1(), a1(), ph2()); + double theta = theta1(ksi(), ph1(), a1(), ph2()); if (variable.equals(v1Var)) { - return dp1dv1(y, FastMath.sin(ksi), g1, v1(), r1(), v2(), FastMath.sin(theta)); + return dp1dv1(y(), FastMath.sin(ksi()), g1(), v1(), r1(), v2(), FastMath.sin(theta)); } else if (variable.equals(v2Var)) { - return dp1dv2(y, v1(), r1(), FastMath.sin(theta)); + return dp1dv2(y(), v1(), r1(), FastMath.sin(theta)); } else if (variable.equals(ph1Var)) { - return dp1dph1(y, v1(), r1(), v2(), FastMath.cos(theta)); + return dp1dph1(y(), v1(), r1(), v2(), FastMath.cos(theta)); } else if (variable.equals(ph2Var)) { - return dp1dph2(y, v1(), r1(), v2(), FastMath.cos(theta)); + return dp1dph2(y(), v1(), r1(), v2(), FastMath.cos(theta)); } else if (variable.equals(a1Var)) { - return dp1da1(y, v1(), r1(), v2(), FastMath.cos(theta)); + return dp1da1(y(), v1(), r1(), v2(), FastMath.cos(theta)); } else if (variable.equals(r1Var)) { - return dp1dr1(y, FastMath.sin(ksi), g1, v1(), r1(), v2(), FastMath.sin(theta)); + return dp1dr1(y(), FastMath.sin(ksi()), g1(), v1(), r1(), v2(), FastMath.sin(theta)); } else { throw new IllegalStateException("Unknown variable: " + variable); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide1CurrentMagnitudeEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide1CurrentMagnitudeEquationTerm.java index a6a972b92b..2d0a422162 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide1CurrentMagnitudeEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide1CurrentMagnitudeEquationTerm.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -7,6 +7,7 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBranch; @@ -26,8 +27,8 @@ public class ClosedBranchSide1CurrentMagnitudeEquationTerm extends AbstractClosedBranchAcFlowEquationTerm { public ClosedBranchSide1CurrentMagnitudeEquationTerm(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet, - boolean deriveA1, boolean deriveR1) { - super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, Fortescue.SequenceType.POSITIVE); + boolean deriveA1, boolean deriveR1, AcVectorEngine acVectorEnginee) { + super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, Fortescue.SequenceType.POSITIVE, acVectorEnginee); } public static double calculateSensi(double y, double ksi, double g1, double b1, @@ -45,7 +46,7 @@ public static double calculateSensi(double y, double ksi, double g1, double b1, @Override protected double calculateSensi(double dph1, double dph2, double dv1, double dv2, double da1, double dr1) { - return calculateSensi(y, ksi, g1, b1, v1(), ph1(), r1(), a1(), v2(), ph2(), dph1, dph2, dv1, dv2, da1, dr1); + return calculateSensi(y(), ksi(), g1(), b1(), v1(), ph1(), r1(), a1(), v2(), ph2(), dph1, dph2, dv1, dv2, da1, dr1); } private static double theta(double ksi, double a1, double ph2) { @@ -135,22 +136,22 @@ public static double di1da1(double y, double ksi, double g1, double b1, double v @Override public double eval() { - return i1(y, ksi, g1, b1, v1(), ph1(), r1(), a1(), v2(), ph2()); + return i1(y(), ksi(), g1(), b1(), v1(), ph1(), r1(), a1(), v2(), ph2()); } @Override public double der(Variable variable) { Objects.requireNonNull(variable); if (variable.equals(v1Var)) { - return di1dv1(y, ksi, g1, b1, v1(), ph1(), r1(), a1(), v2(), ph2()); + return di1dv1(y(), ksi(), g1(), b1(), v1(), ph1(), r1(), a1(), v2(), ph2()); } else if (variable.equals(v2Var)) { - return di1dv2(y, ksi, g1, b1, v1(), ph1(), r1(), a1(), v2(), ph2()); + return di1dv2(y(), ksi(), g1(), b1(), v1(), ph1(), r1(), a1(), v2(), ph2()); } else if (variable.equals(ph1Var)) { - return di1dph1(y, ksi, g1, b1, v1(), ph1(), r1(), a1(), v2(), ph2()); + return di1dph1(y(), ksi(), g1(), b1(), v1(), ph1(), r1(), a1(), v2(), ph2()); } else if (variable.equals(ph2Var)) { - return di1dph2(y, ksi, g1, b1, v1(), ph1(), r1(), a1(), v2(), ph2()); + return di1dph2(y(), ksi(), g1(), b1(), v1(), ph1(), r1(), a1(), v2(), ph2()); } else if (variable.equals(a1Var)) { - return di1da1(y, ksi, g1, b1, v1(), ph1(), r1(), a1(), v2(), ph2()); + return di1da1(y(), ksi(), g1(), b1(), v1(), ph1(), r1(), a1(), v2(), ph2()); } else if (variable.equals(r1Var)) { throw new IllegalArgumentException("Derivative with respect to r1 not implemented"); } else { diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide1ReactiveFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide1ReactiveFlowEquationTerm.java index b87af1e860..d31b8874fd 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide1ReactiveFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide1ReactiveFlowEquationTerm.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -7,8 +7,10 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; +import com.powsybl.openloadflow.equations.VectorEngine; import com.powsybl.openloadflow.network.LfBranch; import com.powsybl.openloadflow.network.LfBus; import com.powsybl.openloadflow.util.Fortescue; @@ -25,13 +27,29 @@ public class ClosedBranchSide1ReactiveFlowEquationTerm extends AbstractClosedBranchAcFlowEquationTerm { public ClosedBranchSide1ReactiveFlowEquationTerm(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet, - boolean deriveA1, boolean deriveR1) { - super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, Fortescue.SequenceType.POSITIVE); + boolean deriveA1, boolean deriveR1, AcVectorEngine acVectorEnginee) { + super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, Fortescue.SequenceType.POSITIVE, acVectorEnginee); } public ClosedBranchSide1ReactiveFlowEquationTerm(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet, - boolean deriveA1, boolean deriveR1, Fortescue.SequenceType sequenceType) { - super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, sequenceType); + boolean deriveA1, boolean deriveR1, Fortescue.SequenceType sequenceType, AcVectorEngine acVectorEnginee) { + super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, sequenceType, acVectorEnginee); + } + + @Override + public VectorEngine.VecToVal getVecToVal(Variable v) { + if (v == v1Var) { + return ClosedBranchSide1ReactiveFlowEquationTerm::vec2dq1dv1; + } else if (v == v2Var) { + return ClosedBranchSide1ReactiveFlowEquationTerm::vec2dq1dv2; + } else if (v == ph1Var) { + return ClosedBranchSide1ReactiveFlowEquationTerm::vec2dq1dph1; + } else if (v == ph2Var) { + return ClosedBranchSide1ReactiveFlowEquationTerm::vec2dq1dph2; + } else if (v == null) { + return ClosedBranchSide1ReactiveFlowEquationTerm::vec2q1; + } + return null; } public static double calculateSensi(double y, double ksi, double b1, @@ -51,7 +69,14 @@ public static double calculateSensi(double y, double ksi, double b1, @Override protected double calculateSensi(double dph1, double dph2, double dv1, double dv2, double da1, double dr1) { - return calculateSensi(y, ksi, b1, v1(), ph1(), r1(), a1(), v2(), ph2(), dph1, dph2, dv1, dv2, da1, dr1); + return calculateSensi(y(), ksi(), b1(), v1(), ph1(), r1(), a1(), v2(), ph2(), dph1, dph2, dv1, dv2, da1, dr1); + } + + public static double vec2q1(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, + double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return q1(y, cosKsi, b1, v1, r1, v2, cosTheta1); } public static double q1(double y, double cosKsi, double b1, double v1, double r1, double v2, double cosTheta) { @@ -59,19 +84,47 @@ public static double q1(double y, double cosKsi, double b1, double v1, double r1 - y * R2 * v2 * cosTheta); } + public static double vec2dq1dv1(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, + double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return dq1dv1(y, cosKsi, b1, v1, r1, v2, cosTheta1); + } + public static double dq1dv1(double y, double cosKsi, double b1, double v1, double r1, double v2, double cosTheta) { return r1 * (-2 * b1 * r1 * v1 + 2 * y * r1 * v1 * cosKsi - y * R2 * v2 * cosTheta); } + public static double vec2dq1dv2(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, + double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return dq1dv2(y, v1, r1, cosTheta1); + } + public static double dq1dv2(double y, double v1, double r1, double cosTheta) { return -y * r1 * R2 * v1 * cosTheta; } + public static double vec2dq1dph1(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, + double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return dq1dph1(y, v1, r1, v2, sinTheta1); + } + public static double dq1dph1(double y, double v1, double r1, double v2, double sinTheta) { return -y * r1 * R2 * v1 * v2 * sinTheta; } + public static double vec2dq1dph2(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, + double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return dq1dph2(y, v1, r1, v2, sinTheta1); + } + public static double dq1dph2(double y, double v1, double r1, double v2, double sinTheta) { return -dq1dph1(y, v1, r1, v2, sinTheta); } @@ -86,25 +139,25 @@ public static double dq1dr1(double y, double cosKsi, double b1, double v1, doubl @Override public double eval() { - return q1(y, FastMath.cos(ksi), b1, v1(), r1(), v2(), FastMath.cos(theta1(ksi, ph1(), a1(), ph2()))); + return q1(y(), FastMath.cos(ksi()), b1(), v1(), r1(), v2(), FastMath.cos(theta1(ksi(), ph1(), a1(), ph2()))); } @Override public double der(Variable variable) { Objects.requireNonNull(variable); - double theta = theta1(ksi, ph1(), a1(), ph2()); + double theta = theta1(ksi(), ph1(), a1(), ph2()); if (variable.equals(v1Var)) { - return dq1dv1(y, FastMath.cos(ksi), b1, v1(), r1(), v2(), FastMath.cos(theta)); + return dq1dv1(y(), FastMath.cos(ksi()), b1(), v1(), r1(), v2(), FastMath.cos(theta)); } else if (variable.equals(v2Var)) { - return dq1dv2(y, v1(), r1(), FastMath.cos(theta)); + return dq1dv2(y(), v1(), r1(), FastMath.cos(theta)); } else if (variable.equals(ph1Var)) { - return dq1dph1(y, v1(), r1(), v2(), FastMath.sin(theta)); + return dq1dph1(y(), v1(), r1(), v2(), FastMath.sin(theta)); } else if (variable.equals(ph2Var)) { - return dq1dph2(y, v1(), r1(), v2(), FastMath.sin(theta)); + return dq1dph2(y(), v1(), r1(), v2(), FastMath.sin(theta)); } else if (variable.equals(a1Var)) { - return dq1da1(y, v1(), r1(), v2(), FastMath.sin(theta)); + return dq1da1(y(), v1(), r1(), v2(), FastMath.sin(theta)); } else if (variable.equals(r1Var)) { - return dq1dr1(y, FastMath.cos(ksi), b1, v1(), r1(), v2(), FastMath.cos(theta)); + return dq1dr1(y(), FastMath.cos(ksi()), b1(), v1(), r1(), v2(), FastMath.cos(theta)); } else { throw new IllegalStateException("Unknown variable: " + variable); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide2ActiveFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide2ActiveFlowEquationTerm.java index 0a24164834..fbd1888454 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide2ActiveFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide2ActiveFlowEquationTerm.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -7,8 +7,10 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; +import com.powsybl.openloadflow.equations.VectorEngine; import com.powsybl.openloadflow.network.LfBranch; import com.powsybl.openloadflow.network.LfBus; import com.powsybl.openloadflow.util.Fortescue; @@ -25,13 +27,32 @@ public class ClosedBranchSide2ActiveFlowEquationTerm extends AbstractClosedBranchAcFlowEquationTerm { public ClosedBranchSide2ActiveFlowEquationTerm(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet, - boolean deriveA1, boolean deriveR1) { - super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, Fortescue.SequenceType.POSITIVE); + boolean deriveA1, boolean deriveR1, AcVectorEngine acVectorEnginee) { + this(branch, bus1, bus2, variableSet, deriveA1, deriveR1, Fortescue.SequenceType.POSITIVE, acVectorEnginee); } public ClosedBranchSide2ActiveFlowEquationTerm(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet, - boolean deriveA1, boolean deriveR1, Fortescue.SequenceType sequenceType) { - super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, sequenceType); + boolean deriveA1, boolean deriveR1, Fortescue.SequenceType sequenceType, AcVectorEngine acVectorEnginee) { + super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, sequenceType, acVectorEnginee); + } + + @Override + public VectorEngine.VecToVal getVecToVal(Variable v) { + if (v == v1Var) { + return ClosedBranchSide2ActiveFlowEquationTerm::vec2dp2dv1; + } + if (v == v2Var) { + return ClosedBranchSide2ActiveFlowEquationTerm::vec2dp2dv2; + } + if (v == ph1Var) { + return ClosedBranchSide2ActiveFlowEquationTerm::vec2dp2dph1; + } + if (v == ph2Var) { + return ClosedBranchSide2ActiveFlowEquationTerm::vec2dp2dph2; + } else if (v == null) { + return ClosedBranchSide2ActiveFlowEquationTerm::vec2p2; + } + return null; } public static double calculateSensi(double y, double ksi, double g2, @@ -50,25 +71,57 @@ public static double calculateSensi(double y, double ksi, double g2, @Override protected double calculateSensi(double dph1, double dph2, double dv1, double dv2, double da1, double dr1) { - return calculateSensi(y, ksi, g2, v1(), ph1(), r1(), a1(), v2(), ph2(), dph1, dph2, dv1, dv2, da1, dr1); + return calculateSensi(y(), ksi(), g2(), v1(), ph1(), r1(), a1(), v2(), ph2(), dph1, dph2, dv1, dv2, da1, dr1); + } + + public static double vec2p2(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, + double sinTheta1, double cosTheta1, double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return p2(y, sinKsi, g2, v1, r1, v2, sinTheta2); } public static double p2(double y, double sinKsi, double g2, double v1, double r1, double v2, double sinTheta) { return R2 * v2 * (g2 * R2 * v2 - y * r1 * v1 * sinTheta + y * R2 * v2 * sinKsi); } + public static double vec2dp2dv1(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, + double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return dp2dv1(y, r1, v2, sinTheta2); + } + public static double dp2dv1(double y, double r1, double v2, double sinTheta) { return -y * r1 * R2 * v2 * sinTheta; } + public static double vec2dp2dv2(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, + double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return dp2dv2(y, sinKsi, g2, v1, r1, v2, sinTheta2); + } + public static double dp2dv2(double y, double sinKsi, double g2, double v1, double r1, double v2, double sinTheta) { return R2 * (2 * g2 * R2 * v2 - y * r1 * v1 * sinTheta + 2 * y * R2 * v2 * sinKsi); } + public static double vec2dp2dph1(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return dp2dph1(y, v1, r1, v2, cosTheta2); + } + public static double dp2dph1(double y, double v1, double r1, double v2, double cosTheta) { return -y * r1 * R2 * v1 * v2 * cosTheta; } + public static double vec2dp2dph2(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return dp2dph2(y, v1, r1, v2, cosTheta2); + } + public static double dp2dph2(double y, double v1, double r1, double v2, double cosTheta) { return -dp2dph1(y, v1, r1, v2, cosTheta); } @@ -83,25 +136,25 @@ public static double dp2dr1(double y, double v1, double v2, double sinTheta) { @Override public double eval() { - return p2(y, FastMath.sin(ksi), g2, v1(), r1(), v2(), FastMath.sin(theta2(ksi, ph1(), a1(), ph2()))); + return p2(y(), FastMath.sin(ksi()), g2(), v1(), r1(), v2(), FastMath.sin(theta2(ksi(), ph1(), a1(), ph2()))); } @Override public double der(Variable variable) { Objects.requireNonNull(variable); - double theta = theta2(ksi, ph1(), a1(), ph2()); + double theta = theta2(ksi(), ph1(), a1(), ph2()); if (variable.equals(v1Var)) { - return dp2dv1(y, r1(), v2(), FastMath.sin(theta)); + return dp2dv1(y(), r1(), v2(), FastMath.sin(theta)); } else if (variable.equals(v2Var)) { - return dp2dv2(y, FastMath.sin(ksi), g2, v1(), r1(), v2(), FastMath.sin(theta)); + return dp2dv2(y(), FastMath.sin(ksi()), g2(), v1(), r1(), v2(), FastMath.sin(theta)); } else if (variable.equals(ph1Var)) { - return dp2dph1(y, v1(), r1(), v2(), FastMath.cos(theta)); + return dp2dph1(y(), v1(), r1(), v2(), FastMath.cos(theta)); } else if (variable.equals(ph2Var)) { - return dp2dph2(y, v1(), r1(), v2(), FastMath.cos(theta)); + return dp2dph2(y(), v1(), r1(), v2(), FastMath.cos(theta)); } else if (variable.equals(a1Var)) { - return dp2da1(y, v1(), r1(), v2(), FastMath.cos(theta)); + return dp2da1(y(), v1(), r1(), v2(), FastMath.cos(theta)); } else if (variable.equals(r1Var)) { - return dp2dr1(y, v1(), v2(), FastMath.sin(theta)); + return dp2dr1(y(), v1(), v2(), FastMath.sin(theta)); } else { throw new IllegalStateException("Unknown variable: " + variable); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide2CurrentMagnitudeEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide2CurrentMagnitudeEquationTerm.java index 1afe071a49..c30719551d 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide2CurrentMagnitudeEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide2CurrentMagnitudeEquationTerm.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -7,6 +7,7 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBranch; @@ -26,8 +27,8 @@ public class ClosedBranchSide2CurrentMagnitudeEquationTerm extends AbstractClosedBranchAcFlowEquationTerm { public ClosedBranchSide2CurrentMagnitudeEquationTerm(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet, - boolean deriveA1, boolean deriveR1) { - super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, Fortescue.SequenceType.POSITIVE); + boolean deriveA1, boolean deriveR1, AcVectorEngine acVectorEnginee) { + super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, Fortescue.SequenceType.POSITIVE, acVectorEnginee); } public static double calculateSensi(double y, double ksi, double g2, double b2, @@ -45,7 +46,7 @@ public static double calculateSensi(double y, double ksi, double g2, double b2, @Override protected double calculateSensi(double dph1, double dph2, double dv1, double dv2, double da1, double dr1) { - return calculateSensi(y, ksi, g2, b2, v1(), ph1(), r1(), a1(), v2(), ph2(), dph1, dph2, dv1, dv2, da1, dr1); + return calculateSensi(y(), ksi(), g2(), b2(), v1(), ph1(), r1(), a1(), v2(), ph2(), dph1, dph2, dv1, dv2, da1, dr1); } private static double theta(double ksi, double ph1, double a1) { @@ -135,22 +136,22 @@ public static double di2da1(double y, double ksi, double g2, double b2, double v @Override public double eval() { - return i2(y, ksi, g2, b2, v1(), ph1(), r1(), a1(), v2(), ph2()); + return i2(y(), ksi(), g2(), b2(), v1(), ph1(), r1(), a1(), v2(), ph2()); } @Override public double der(Variable variable) { Objects.requireNonNull(variable); if (variable.equals(v1Var)) { - return di2dv1(y, ksi, g2, b2, v1(), ph1(), r1(), a1(), v2(), ph2()); + return di2dv1(y(), ksi(), g2(), b2(), v1(), ph1(), r1(), a1(), v2(), ph2()); } else if (variable.equals(v2Var)) { - return di2dv2(y, ksi, g2, b2, v1(), ph1(), r1(), a1(), v2(), ph2()); + return di2dv2(y(), ksi(), g2(), b2(), v1(), ph1(), r1(), a1(), v2(), ph2()); } else if (variable.equals(ph1Var)) { - return di2dph1(y, ksi, g2, b2, v1(), ph1(), r1(), a1(), v2(), ph2()); + return di2dph1(y(), ksi(), g2(), b2(), v1(), ph1(), r1(), a1(), v2(), ph2()); } else if (variable.equals(ph2Var)) { - return di2dph2(y, ksi, g2, b2, v1(), ph1(), r1(), a1(), v2(), ph2()); + return di2dph2(y(), ksi(), g2(), b2(), v1(), ph1(), r1(), a1(), v2(), ph2()); } else if (variable.equals(a1Var)) { - return di2da1(y, ksi, g2, b2, v1(), ph1(), r1(), a1(), v2(), ph2()); + return di2da1(y(), ksi(), g2(), b2(), v1(), ph1(), r1(), a1(), v2(), ph2()); } else if (variable.equals(r1Var)) { throw new IllegalArgumentException("Derivative with respect to r1 not implemented"); } else { diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide2ReactiveFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide2ReactiveFlowEquationTerm.java index 11c9f0a5d5..cc17b58782 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide2ReactiveFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/ClosedBranchSide2ReactiveFlowEquationTerm.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -7,8 +7,10 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; +import com.powsybl.openloadflow.equations.VectorEngine; import com.powsybl.openloadflow.network.LfBranch; import com.powsybl.openloadflow.network.LfBus; import com.powsybl.openloadflow.util.Fortescue; @@ -25,13 +27,31 @@ public class ClosedBranchSide2ReactiveFlowEquationTerm extends AbstractClosedBranchAcFlowEquationTerm { public ClosedBranchSide2ReactiveFlowEquationTerm(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet, - boolean deriveA1, boolean deriveR1) { - super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, Fortescue.SequenceType.POSITIVE); + boolean deriveA1, boolean deriveR1, AcVectorEngine acVectorEnginee) { + super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, Fortescue.SequenceType.POSITIVE, acVectorEnginee); } public ClosedBranchSide2ReactiveFlowEquationTerm(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet, - boolean deriveA1, boolean deriveR1, Fortescue.SequenceType sequenceType) { - super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, sequenceType); + boolean deriveA1, boolean deriveR1, Fortescue.SequenceType sequenceType, AcVectorEngine acVectorEnginee) { + super(branch, bus1, bus2, variableSet, deriveA1, deriveR1, sequenceType, acVectorEnginee); + } + + @Override + public VectorEngine.VecToVal getVecToVal(Variable v) { + if (v == v1Var) { + return ClosedBranchSide2ReactiveFlowEquationTerm::vec2dq2dv1; + } else if (v == v2Var) { + return ClosedBranchSide2ReactiveFlowEquationTerm::vec2dq2dv2; + } else if (v == ph1Var) { + return ClosedBranchSide2ReactiveFlowEquationTerm::vec2dq2dph1; + } else if (v == ph2Var) { + return ClosedBranchSide2ReactiveFlowEquationTerm::vec2dq2dph2; + } else if (v == null) { + return ClosedBranchSide2ReactiveFlowEquationTerm::vec2q2; + } + return null; + // TODO return for eval + // acVectorEnginee.vecToP2[element.getNum()] = ClosedBranchSide2ActiveFlowEquationTerm::vec2p2;} } public static double calculateSensi(double y, double ksi, double b2, @@ -50,25 +70,60 @@ public static double calculateSensi(double y, double ksi, double b2, @Override protected double calculateSensi(double dph1, double dph2, double dv1, double dv2, double da1, double dr1) { - return calculateSensi(y, ksi, b2, v1(), ph1(), r1(), a1(), v2(), ph2(), dph1, dph2, dv1, dv2, da1, dr1); + return calculateSensi(y(), ksi(), b2(), v1(), ph1(), r1(), a1(), v2(), ph2(), dph1, dph2, dv1, dv2, da1, dr1); + } + + public static double vec2q2(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, + double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return q2(y, cosKsi, b2, v1, r1, v2, cosTheta2); } public static double q2(double y, double cosKsi, double b2, double v1, double r1, double v2, double cosTheta) { return R2 * v2 * (-b2 * R2 * v2 - y * r1 * v1 * cosTheta + y * R2 * v2 * cosKsi); } + public static double vec2dq2dv1(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, + double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return dq2dv1(y, r1, v2, cosTheta2); + } + public static double dq2dv1(double y, double r1, double v2, double cosTheta) { return -y * r1 * R2 * v2 * cosTheta; } + public static double vec2dq2dv2(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, + double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return dq2dv2(y, cosKsi, b2, v1, r1, v2, cosTheta2); + } + public static double dq2dv2(double y, double cosKsi, double b2, double v1, double r1, double v2, double cosTheta) { return R2 * (-2 * b2 * R2 * v2 - y * r1 * v1 * cosTheta + 2 * y * R2 * v2 * cosKsi); } + public static double vec2dq2dph1(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, + double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return dq2dph1(y, v1, r1, v2, sinTheta2); + } + public static double dq2dph1(double y, double v1, double r1, double v2, double sinTheta) { return y * r1 * R2 * v1 * v2 * sinTheta; } + public static double vec2dq2dph2(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, + double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1) { + return dq2dph2(y, v1, r1, v2, sinTheta2); + } + public static double dq2dph2(double y, double v1, double r1, double v2, double sinTheta) { return -dq2dph1(y, v1, r1, v2, sinTheta); } @@ -83,25 +138,25 @@ public static double dq2dr1(double y, double v1, double v2, double cosTheta) { @Override public double eval() { - return q2(y, FastMath.cos(ksi), b2, v1(), r1(), v2(), FastMath.cos(theta2(ksi, ph1(), a1(), ph2()))); + return q2(y(), FastMath.cos(ksi()), b2(), v1(), r1(), v2(), FastMath.cos(theta2(ksi(), ph1(), a1(), ph2()))); } @Override public double der(Variable variable) { Objects.requireNonNull(variable); - double theta = theta2(ksi, ph1(), a1(), ph2()); + double theta = theta2(ksi(), ph1(), a1(), ph2()); if (variable.equals(v1Var)) { - return dq2dv1(y, r1(), v2(), FastMath.cos(theta)); + return dq2dv1(y(), r1(), v2(), FastMath.cos(theta)); } else if (variable.equals(v2Var)) { - return dq2dv2(y, FastMath.cos(ksi), b2, v1(), r1(), v2(), FastMath.cos(theta)); + return dq2dv2(y(), FastMath.cos(ksi()), b2(), v1(), r1(), v2(), FastMath.cos(theta)); } else if (variable.equals(ph1Var)) { - return dq2dph1(y, v1(), r1(), v2(), FastMath.sin(theta)); + return dq2dph1(y(), v1(), r1(), v2(), FastMath.sin(theta)); } else if (variable.equals(ph2Var)) { - return dq2dph2(y, v1(), r1(), v2(), FastMath.sin(theta)); + return dq2dph2(y(), v1(), r1(), v2(), FastMath.sin(theta)); } else if (variable.equals(a1Var)) { - return dq2da1(y, v1(), r1(), v2(), FastMath.sin(theta)); + return dq2da1(y(), v1(), r1(), v2(), FastMath.sin(theta)); } else if (variable.equals(r1Var)) { - return dq2dr1(y, v1(), v2(), FastMath.cos(theta)); + return dq2dr1(y(), v1(), v2(), FastMath.cos(theta)); } else { throw new IllegalStateException("Unknown variable: " + variable); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide1ActiveFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide1ActiveFlowEquationTerm.java index 6a69132089..3ec6fb0181 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide1ActiveFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide1ActiveFlowEquationTerm.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -7,6 +7,7 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBranch; @@ -24,8 +25,8 @@ public class OpenBranchSide1ActiveFlowEquationTerm extends AbstractOpenSide1Bran private final Variable v2Var; - public OpenBranchSide1ActiveFlowEquationTerm(LfBranch branch, LfBus bus2, VariableSet variableSet) { - super(branch, AcVariableType.BUS_V, bus2, variableSet); + public OpenBranchSide1ActiveFlowEquationTerm(LfBranch branch, LfBus bus2, VariableSet variableSet, AcVectorEngine acVectorEnginee) { + super(branch, AcVariableType.BUS_V, bus2, variableSet, acVectorEnginee); v2Var = variableSet.getVariable(bus2.getNum(), AcVariableType.BUS_V); } @@ -45,14 +46,14 @@ public static double dp2dv2(double y, double cosKsi, double sinKsi, double g1, d @Override public double eval() { - return p2(y, FastMath.cos(ksi), FastMath.sin(ksi), g1, b1, g2, v2()); + return p2(y(), FastMath.cos(ksi()), FastMath.sin(ksi()), g1(), b1(), g2(), v2()); } @Override public double der(Variable variable) { Objects.requireNonNull(variable); if (variable.equals(v2Var)) { - return dp2dv2(y, FastMath.cos(ksi), FastMath.sin(ksi), g1, b1, g2, v2()); + return dp2dv2(y(), FastMath.cos(ksi()), FastMath.sin(ksi()), g1(), b1(), g2(), v2()); } else { throw new IllegalStateException("Unknown variable: " + variable); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide1CurrentMagnitudeEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide1CurrentMagnitudeEquationTerm.java index fe87d06d04..886bc3c87d 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide1CurrentMagnitudeEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide1CurrentMagnitudeEquationTerm.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -7,6 +7,7 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBranch; @@ -27,8 +28,8 @@ public class OpenBranchSide1CurrentMagnitudeEquationTerm extends AbstractOpenSid private final Variable ph2Var; - public OpenBranchSide1CurrentMagnitudeEquationTerm(LfBranch branch, LfBus bus2, VariableSet variableSet) { - super(branch, AcVariableType.BUS_V, bus2, variableSet); + public OpenBranchSide1CurrentMagnitudeEquationTerm(LfBranch branch, LfBus bus2, VariableSet variableSet, AcVectorEngine acVectorEnginee) { + super(branch, AcVariableType.BUS_V, bus2, variableSet, acVectorEnginee); v2Var = variableSet.getVariable(bus2.getNum(), AcVariableType.BUS_V); ph2Var = variableSet.getVariable(bus2.getNum(), AcVariableType.BUS_PHI); } @@ -80,14 +81,14 @@ public static double di2dv2(double y, double cosKsi, double sinKsi, double g1, d @Override public double eval() { - return i2(y, FastMath.cos(ksi), FastMath.sin(ksi), g1, b1, g2, b2, v2(), ph2()); + return i2(y(), FastMath.cos(ksi()), FastMath.sin(ksi()), g1(), b1(), g2(), b2(), v2(), ph2()); } @Override public double der(Variable variable) { Objects.requireNonNull(variable); if (variable.equals(v2Var)) { - return di2dv2(y, FastMath.cos(ksi), FastMath.sin(ksi), g1, b1, g2, b2, v2(), ph2()); + return di2dv2(y(), FastMath.cos(ksi()), FastMath.sin(ksi()), g1(), b1(), g2(), b2(), v2(), ph2()); } else if (variable.equals(ph2Var)) { throw new IllegalArgumentException("Derivative with respect to ph2 not implemented"); } else { diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide1ReactiveFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide1ReactiveFlowEquationTerm.java index 100eeed490..a37d4d9fa4 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide1ReactiveFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide1ReactiveFlowEquationTerm.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -7,6 +7,7 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBranch; @@ -24,8 +25,8 @@ public class OpenBranchSide1ReactiveFlowEquationTerm extends AbstractOpenSide1Br private final Variable v2Var; - public OpenBranchSide1ReactiveFlowEquationTerm(LfBranch branch, LfBus bus2, VariableSet variableSet) { - super(branch, AcVariableType.BUS_V, bus2, variableSet); + public OpenBranchSide1ReactiveFlowEquationTerm(LfBranch branch, LfBus bus2, VariableSet variableSet, AcVectorEngine acVectorEnginee) { + super(branch, AcVariableType.BUS_V, bus2, variableSet, acVectorEnginee); v2Var = variableSet.getVariable(bus2.getNum(), AcVariableType.BUS_V); } @@ -45,14 +46,14 @@ public static double dq2dv2(double y, double cosKsi, double sinKsi, double g1, d @Override public double eval() { - return q2(y, FastMath.cos(ksi), FastMath.sin(ksi), g1, b1, b2, v2()); + return q2(y(), FastMath.cos(ksi()), FastMath.sin(ksi()), g1(), b1(), b2(), v2()); } @Override public double der(Variable variable) { Objects.requireNonNull(variable); if (variable.equals(v2Var)) { - return dq2dv2(y, FastMath.cos(ksi), FastMath.sin(ksi), g1, b1, b2, v2()); + return dq2dv2(y(), FastMath.cos(ksi()), FastMath.sin(ksi()), g1(), b1(), b2(), v2()); } else { throw new IllegalStateException("Unknown variable: " + variable); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide2ActiveFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide2ActiveFlowEquationTerm.java index 16072989ac..48e7aace5e 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide2ActiveFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide2ActiveFlowEquationTerm.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -7,6 +7,7 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBranch; @@ -22,8 +23,8 @@ public class OpenBranchSide2ActiveFlowEquationTerm extends AbstractOpenSide2Bran private final Variable v1Var; - public OpenBranchSide2ActiveFlowEquationTerm(LfBranch branch, LfBus bus1, VariableSet variableSet) { - super(branch, AcVariableType.BUS_V, bus1, variableSet); + public OpenBranchSide2ActiveFlowEquationTerm(LfBranch branch, LfBus bus1, VariableSet variableSet, AcVectorEngine acVectorEnginee) { + super(branch, AcVariableType.BUS_V, bus1, variableSet, acVectorEnginee); v1Var = variableSet.getVariable(bus1.getNum(), AcVariableType.BUS_V); } @@ -47,14 +48,14 @@ public static double dp1dv1(double y, double cosKsi, double sinKsi, double g1, d @Override public double eval() { - return p1(y, FastMath.cos(ksi), FastMath.sin(ksi), g1, g2, b2, v1(), r1()); + return p1(y(), FastMath.cos(ksi()), FastMath.sin(ksi()), g1(), g2(), b2(), v1(), r1()); } @Override public double der(Variable variable) { Objects.requireNonNull(variable); if (variable.equals(v1Var)) { - return dp1dv1(y, FastMath.cos(ksi), FastMath.sin(ksi), g1, g2, b2, v1(), r1()); + return dp1dv1(y(), FastMath.cos(ksi()), FastMath.sin(ksi()), g1(), g2(), b2(), v1(), r1()); } else { throw new IllegalStateException("Unknown variable: " + variable); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide2CurrentMagnitudeEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide2CurrentMagnitudeEquationTerm.java index 5ff72b0a13..3229eb3aa4 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide2CurrentMagnitudeEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide2CurrentMagnitudeEquationTerm.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -7,6 +7,7 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBranch; @@ -28,8 +29,8 @@ public class OpenBranchSide2CurrentMagnitudeEquationTerm extends AbstractOpenSid private Variable r1Var; public OpenBranchSide2CurrentMagnitudeEquationTerm(LfBranch branch, LfBus bus1, VariableSet variableSet, - boolean deriveR1) { - super(branch, AcVariableType.BUS_V, bus1, variableSet); + boolean deriveR1, AcVectorEngine acVectorEnginee) { + super(branch, AcVariableType.BUS_V, bus1, variableSet, acVectorEnginee); v1Var = variableSet.getVariable(bus1.getNum(), AcVariableType.BUS_V); ph1Var = variableSet.getVariable(bus1.getNum(), AcVariableType.BUS_PHI); if (deriveR1) { @@ -88,14 +89,14 @@ public static double di1dv1(double y, double cosKsi, double sinKsi, double g1, d @Override public double eval() { - return i1(y, FastMath.cos(ksi), FastMath.sin(ksi), g1, b1, g2, b2, v1(), ph1(), r1()); + return i1(y(), FastMath.cos(ksi()), FastMath.sin(ksi()), g1(), b1(), g2(), b2(), v1(), ph1(), r1()); } @Override public double der(Variable variable) { Objects.requireNonNull(variable); if (variable.equals(v1Var)) { - return di1dv1(y, FastMath.cos(ksi), FastMath.sin(ksi), g1, b1, g2, b2, v1(), ph1(), r1()); + return di1dv1(y(), FastMath.cos(ksi()), FastMath.sin(ksi()), g1(), b1(), g2(), b2(), v1(), ph1(), r1()); } else if (variable.equals(ph1Var) || variable.equals(r1Var)) { throw new IllegalArgumentException("Derivative with respect to ph1 or r1 not implemented"); } else { diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide2ReactiveFlowEquationTerm.java b/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide2ReactiveFlowEquationTerm.java index 610a3067c4..039e09e82a 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide2ReactiveFlowEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/OpenBranchSide2ReactiveFlowEquationTerm.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -7,6 +7,7 @@ */ package com.powsybl.openloadflow.ac.equations; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.Variable; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.network.LfBranch; @@ -22,8 +23,8 @@ public class OpenBranchSide2ReactiveFlowEquationTerm extends AbstractOpenSide2Br private final Variable v1Var; - public OpenBranchSide2ReactiveFlowEquationTerm(LfBranch branch, LfBus bus1, VariableSet variableSet) { - super(branch, AcVariableType.BUS_V, bus1, variableSet); + public OpenBranchSide2ReactiveFlowEquationTerm(LfBranch branch, LfBus bus1, VariableSet variableSet, AcVectorEngine acVectorEnginee) { + super(branch, AcVariableType.BUS_V, bus1, variableSet, acVectorEnginee); v1Var = variableSet.getVariable(bus1.getNum(), AcVariableType.BUS_V); } @@ -47,14 +48,14 @@ public static double dq1dv1(double y, double cosKsi, double sinKsi, double b1, d @Override public double eval() { - return q1(y, FastMath.cos(ksi), FastMath.sin(ksi), b1, g2, b2, v1(), r1()); + return q1(y(), FastMath.cos(ksi()), FastMath.sin(ksi()), b1(), g2(), b2(), v1(), r1()); } @Override public double der(Variable variable) { Objects.requireNonNull(variable); if (variable.equals(v1Var)) { - return dq1dv1(y, FastMath.cos(ksi), FastMath.sin(ksi), b1, g2, b2, v1(), r1()); + return dq1dv1(y(), FastMath.cos(ksi()), FastMath.sin(ksi()), b1(), g2(), b2(), v1(), r1()); } else { throw new IllegalStateException("Unknown variable: " + variable); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/asym/AsymmetricalAcEquationSystemCreator.java b/src/main/java/com/powsybl/openloadflow/ac/equations/asym/AsymmetricalAcEquationSystemCreator.java index 62492095d9..debd1294b6 100644 --- a/src/main/java/com/powsybl/openloadflow/ac/equations/asym/AsymmetricalAcEquationSystemCreator.java +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/asym/AsymmetricalAcEquationSystemCreator.java @@ -1,6 +1,5 @@ -/** - * Copyright (c) 2023, Jean-Baptiste Heyberger - * Copyright (c) 2023, Geoffroy Jamgotchian +/* + * Copyright (c) 2023-2025, 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/. @@ -10,6 +9,7 @@ import com.powsybl.iidm.network.TwoSides; import com.powsybl.openloadflow.ac.equations.*; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.EquationSystem; import com.powsybl.openloadflow.equations.EquationTerm; import com.powsybl.openloadflow.network.*; @@ -98,7 +98,8 @@ protected void createBusEquation(LfBus bus, EquationSystem equationSystem) { + protected void createImpedantBranch(LfBranch branch, LfBus bus1, LfBus bus2, EquationSystem equationSystem, AcVectorEngine acVectorEnginee) { // positive sequence EquationTerm p1 = null; EquationTerm q1 = null; @@ -126,24 +127,24 @@ protected void createImpedantBranch(LfBranch branch, LfBus bus1, LfBus bus2, Equ if (!branch.isAsymmetric()) { // no asymmetry is detected with this line, we handle the equations as decoupled // positive - p1 = new ClosedBranchSide1ActiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.POSITIVE); - q1 = new ClosedBranchSide1ReactiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.POSITIVE); - p2 = new ClosedBranchSide2ActiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.POSITIVE); - q2 = new ClosedBranchSide2ReactiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.POSITIVE); - i1 = new ClosedBranchSide1CurrentMagnitudeEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1); - i2 = new ClosedBranchSide2CurrentMagnitudeEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1); + p1 = new ClosedBranchSide1ActiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.POSITIVE, acVectorEnginee); + q1 = new ClosedBranchSide1ReactiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.POSITIVE, acVectorEnginee); + p2 = new ClosedBranchSide2ActiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.POSITIVE, acVectorEnginee); + q2 = new ClosedBranchSide2ReactiveFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.POSITIVE, acVectorEnginee); + i1 = new ClosedBranchSide1CurrentMagnitudeEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, acVectorEnginee); + i2 = new ClosedBranchSide2CurrentMagnitudeEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, acVectorEnginee); // zero - ixz1 = new ClosedBranchI1xFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.ZERO); - iyz1 = new ClosedBranchI1yFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.ZERO); - ixz2 = new ClosedBranchI2xFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.ZERO); - iyz2 = new ClosedBranchI2yFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.ZERO); + ixz1 = new ClosedBranchI1xFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.ZERO, acVectorEnginee); + iyz1 = new ClosedBranchI1yFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.ZERO, acVectorEnginee); + ixz2 = new ClosedBranchI2xFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.ZERO, acVectorEnginee); + iyz2 = new ClosedBranchI2yFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.ZERO, acVectorEnginee); // negative - ixn1 = new ClosedBranchI1xFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.NEGATIVE); - iyn1 = new ClosedBranchI1yFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.NEGATIVE); - ixn2 = new ClosedBranchI2xFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.NEGATIVE); - iyn2 = new ClosedBranchI2yFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.NEGATIVE); + ixn1 = new ClosedBranchI1xFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.NEGATIVE, acVectorEnginee); + iyn1 = new ClosedBranchI1yFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.NEGATIVE, acVectorEnginee); + ixn2 = new ClosedBranchI2xFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.NEGATIVE, acVectorEnginee); + iyn2 = new ClosedBranchI2yFlowEquationTerm(branch, bus1, bus2, equationSystem.getVariableSet(), deriveA1, deriveR1, SequenceType.NEGATIVE, acVectorEnginee); } else { // assymmetry is detected with this line, we handle the equations as coupled between the different sequences // positive @@ -217,9 +218,9 @@ protected void createImpedantBranch(LfBranch branch, LfBus bus1, LfBus bus2, Equ .addTerm(iyn2); } - createGeneratorReactivePowerControlBranchEquation(branch, bus1, bus2, equationSystem, deriveA1, deriveR1); + createGeneratorReactivePowerControlBranchEquation(branch, bus1, bus2, equationSystem, deriveA1, deriveR1, acVectorEnginee); - createTransformerPhaseControlEquations(branch, bus1, bus2, equationSystem, deriveA1, deriveR1); + createTransformerPhaseControlEquations(branch, bus1, bus2, equationSystem, deriveA1, deriveR1, acVectorEnginee); createTransformerReactivePowerControlEquations(branch, equationSystem); } diff --git a/src/main/java/com/powsybl/openloadflow/ac/equations/vector/AcVectorEngine.java b/src/main/java/com/powsybl/openloadflow/ac/equations/vector/AcVectorEngine.java new file mode 100644 index 0000000000..bf1faaf56b --- /dev/null +++ b/src/main/java/com/powsybl/openloadflow/ac/equations/vector/AcVectorEngine.java @@ -0,0 +1,552 @@ +/* + * Copyright (c) 2025, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ + +package com.powsybl.openloadflow.ac.equations.vector; +import com.powsybl.math.matrix.Matrix; +import com.powsybl.openloadflow.ac.equations.AbstractClosedBranchAcFlowEquationTerm; +import com.powsybl.openloadflow.ac.equations.AcEquationType; +import com.powsybl.openloadflow.ac.equations.AcVariableType; +import com.powsybl.openloadflow.equations.*; +import com.powsybl.openloadflow.network.AbstractLfNetworkListener; +import com.powsybl.openloadflow.network.ElementType; +import com.powsybl.openloadflow.network.LfBranch; +import com.powsybl.openloadflow.network.LfNetwork; +import net.jafama.FastMath; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.function.DoubleSupplier; +import java.util.stream.IntStream; + +/** + * @author Didier Vidal {@literal } + * + * A data container that contains primitive type arrays that can be iterrated + * efficiently to avoid memory cache misses + * foccusses on P and Q derived by V and Phi. Other combinations are not vectorized. + */ +public class AcVectorEngine implements StateVectorListener, EquationSystemListener, VectorEngine { + + private static final Logger LOGGER = LoggerFactory.getLogger(AcVectorEngine.class); + + private final EquationSystem equationSystem; + + public final boolean[] networkDataInitialized; + public final double[] b1; + public final double[] b2; + public final double[] g1; + public final double[] g2; + public final double[] y; + public final double[] ksi; + public final double[] g12; + public final double[] b12; + + // possibly computed input values + private final ArrayList supplyingTerms = new ArrayList<>(); + public final double[] a1; + public final double[] r1; + + // variables + public final Variable[] v1Var; + private final double[] v1; + public final Variable[] v2Var; + private final double[] v2; + public final Variable[] ph1Var; + private final double[] ph1; + public final Variable[] ph2Var; + private final double[] ph2; + + // indexes to compute derivatives + private boolean equationDataValid; + private boolean equationOrderValid; + private int[] sortedEquationIndexArray; + private int[] variableCountPerEquation; + private int[] variablePerEquationIndex; + private Variable[] variablesPerEquation; + private double[] deriveResultPerVariableAndEquation; + private int[] matrixIndexPerVariableAndEquation; + private EquationTerm[] termsByVariableAndEquation; + + // term data ordered by branch + record TermData(EquationTerm term, + boolean isBranch, + int branchNum, + int busNum, + int indexForResult, + Variable v) { + } + + // equation replicated data for quick access + private boolean[] equationActiveStatus; + private int[] equationColumn; + private double[] evalResultPerEquation; + + // term replicated data for quick access + private boolean[] termActiveStatus; + private int[] termBranchNum; + public DoubleSupplier[] a1TermSupplier; + public DoubleSupplier[] r1TermSupplier; + + // sorted term data per equation (for eval) + private EquationTerm[] sortedTermsForEval; + private int[] termActiveStatusIndexForEval; + private int[] termEquationActiveStatusIndexForEval; + private int[] termByEvalResultIndex; + private int[] termByEquationBranchNumForEval; + private VecToVal[] sortedTermsVecToValForEval; + + // sorted term data per equation and variable (for der) + private EquationTerm[] sortedTermsForDer; + private int[] termActiveStatusIndexForDer; + private int[] termEquationActiveStatusIndexForDer; + private Variable[] termVariable; + private int[] termByVariableDeriveResultIndex; + private int[] termByVariableBranchNumForDer; + private VecToVal[] sortedTermsVecToValForDer; + + public AcVectorEngine(LfNetwork network, EquationSystem equationSystem) { + this.equationSystem = equationSystem; + if (equationSystem != null) { + equationSystem.setVectorEngine(this); + } + + if (network != null) { + network.addListener(new AbstractLfNetworkListener() { + @Override + public void onTapPositionChange(LfBranch branch, int oldPosition, int newPosition) { + a1[branch.getNum()] = branch.getPiModel().getA1(); + r1[branch.getNum()] = branch.getPiModel().getR1(); + } + }); + } + + int branchCount = network == null ? 1 : network.getBranches().size(); + + b1 = new double[branchCount]; + b2 = new double[branchCount]; + g1 = new double[branchCount]; + g2 = new double[branchCount]; + y = new double[branchCount]; + ksi = new double[branchCount]; + g12 = new double[branchCount]; + b12 = new double[branchCount]; + networkDataInitialized = new boolean[branchCount]; + + a1 = new double[branchCount]; + + r1 = new double[branchCount]; + + v1Var = new Variable[branchCount]; + v1 = new double[branchCount]; + v2Var = new Variable[branchCount]; + v2 = new double[branchCount]; + ph1Var = new Variable[branchCount]; + ph1 = new double[branchCount]; + ph2Var = new Variable[branchCount]; + ph2 = new double[branchCount]; + + if (equationSystem != null) { + equationSystem.getStateVector().addListener(this); + equationSystem.addListener(this); + } + } + + @Override + public void onStateUpdate() { + updateVariables(); + } + + @Override + public void onEquationChange(Equation equation, EquationEventType eventType) { + switch (eventType) { + case EQUATION_CREATED: + case EQUATION_REMOVED: + equationDataValid = false; + break; + case EQUATION_ACTIVATED: + case EQUATION_DEACTIVATED: + if (equation.getVectorIndex() >= 0) { + equationActiveStatus[equation.getVectorIndex()] = equation.isActive(); + } + case EQUATION_COLUMN_CHANGED: + if (equation.getVectorIndex() >= 0) { + equationColumn[equation.getVectorIndex()] = equation.getColumn(); + } + equationOrderValid = false; + break; + } + } + + @Override + public void onEquationTermChange(EquationTerm term, EquationTermEventType eventType) { + if (eventType == EquationTermEventType.EQUATION_TERM_ACTIVATED || eventType == EquationTermEventType.EQUATION_TERM_DEACTIVATED) { + if (term.getVectorIndex() >= 0) { + termActiveStatus[term.getVectorIndex()] = term.isActive(); + } + } + } + + @Override + public void evalLhs(double[] array) { + if (!equationDataValid) { + initEquationData(); + } + + evalSortedTerms(); + + for (int eqIndex = 0; eqIndex < equationActiveStatus.length; eqIndex++) { + if (equationActiveStatus[eqIndex]) { + int col = equationColumn[eqIndex]; + array[col] = evalResultPerEquation[eqIndex]; + } + } + } + + public void addSupplyingTerm(AbstractClosedBranchAcFlowEquationTerm t) { + supplyingTerms.add(t); + equationDataValid = false; + } + + private void updateVariables() { + StateVector stateVector = equationSystem.getStateVector(); + for (int i = 0; i < v1Var.length; i++) { + v1[i] = v1Var[i] != null && v1Var[i].getRow() >= 0 ? stateVector.get(v1Var[i].getRow()) : Double.NaN; + v2[i] = v2Var[i] != null && v2Var[i].getRow() >= 0 ? stateVector.get(v2Var[i].getRow()) : Double.NaN; + ph1[i] = ph1Var[i] != null && ph1Var[i].getRow() >= 0 ? stateVector.get(ph1Var[i].getRow()) : Double.NaN; + ph2[i] = ph2Var[i] != null && ph2Var[i].getRow() >= 0 ? stateVector.get(ph2Var[i].getRow()) : Double.NaN; + } + } + + private void initEquationData() { + // reset all term vector index + if (termsByVariableAndEquation != null) { + Arrays.stream(termsByVariableAndEquation).forEach(t -> t.setVectorIndex(-1)); + } + + Collection> equationList = equationSystem.getEquations() + .stream().sorted(Comparator.comparingInt(Equation::getElementNum)).toList(); + int equationCount = equationList.size(); + sortedEquationIndexArray = new int[equationCount]; + variableCountPerEquation = new int[equationCount]; + equationActiveStatus = new boolean[equationCount]; + equationColumn = new int[equationCount]; + evalResultPerEquation = new double[equationCount]; + int index = 0; + int variableIndexSize = 0; + int termCount = 0; + for (Equation e : equationList) { + e.setVectorIndex(index); + equationActiveStatus[index] = e.isActive(); + equationColumn[index] = e.getColumn(); + int equationVariableCount = e.getVariableCount(); + variableIndexSize += equationVariableCount; + variableCountPerEquation[index] = equationVariableCount; + termCount += e.getTerms().size(); + index += 1; + } + termActiveStatus = new boolean[termCount]; + termBranchNum = new int[termCount]; + a1TermSupplier = new DoubleSupplier[termCount]; + r1TermSupplier = new DoubleSupplier[termCount]; + variablePerEquationIndex = new int[equationCount]; + variablesPerEquation = new Variable[variableIndexSize]; + matrixIndexPerVariableAndEquation = new int[variableIndexSize]; + deriveResultPerVariableAndEquation = new double[variableIndexSize]; + List> termsByVariableAndEquationList = new ArrayList<>(); + List termDataListForDer = new ArrayList<>(); + List termDataListForEval = new ArrayList<>(); + int indexVar = 0; + int indexEq = 0; + int indexForTermStatus = 0; + for (Equation e : equationList) { + for (EquationTerm t : e.getTerms()) { + t.setVectorIndex(indexForTermStatus); + termActiveStatus[indexForTermStatus] = t.isActive(); + if (t instanceof AbstractClosedBranchAcFlowEquationTerm brTerm) { + termBranchNum[indexForTermStatus] = brTerm.getElementNum(); + a1TermSupplier[indexForTermStatus] = brTerm.getA1Supplier(); + r1TermSupplier[indexForTermStatus] = brTerm.getR1Supplier(); + r1[brTerm.getElementNum()] = brTerm.r1(); + a1[brTerm.getElementNum()] = brTerm.a1(); + } + termDataListForEval.add(new TermData(t, + t.getElementType() == ElementType.BRANCH, + t.getElementNum(), + t.getEquation().getElementNum(), + indexEq, + null)); + indexForTermStatus += 1; + } + variablePerEquationIndex[indexEq] = indexVar; + for (Variable v : e.getVariables()) { + variablesPerEquation[indexVar] = v; + for (EquationTerm t : e.getTerms(v)) { + termsByVariableAndEquationList.add(t); + termDataListForDer.add(new TermData(t, + t.getElementType() == ElementType.BRANCH, + t.getElementNum(), + e.getElementNum(), + indexVar, + v)); + } + indexVar += 1; + } + indexEq += 1; + } + termsByVariableAndEquation = termsByVariableAndEquationList.toArray(new EquationTerm[0]); + for (int eqIndex = 0; eqIndex < equationActiveStatus.length; eqIndex++) { + if (equationActiveStatus[eqIndex]) { + int varEnd = variablePerEquationIndex[eqIndex] + variableCountPerEquation[eqIndex]; + for (int varIndex = variablePerEquationIndex[eqIndex]; varIndex < varEnd; varIndex++) { + Variable v = variablesPerEquation[varIndex]; + } + } + } + termDataListForDer.sort((t1, t2) -> { + // Branch elements together, sorted by branchNum then by bus, then by variable + int compare = -Boolean.compare(t1.isBranch, t2.isBranch); // Put branch terms first + if (compare != 0) { + return compare; + } + + compare = t1.branchNum - t2.branchNum; + if (compare != 0) { + return compare; + } + + compare = t1.busNum - t2.busNum; + if (compare != 0) { + return compare; + } + + return t1.v.compareTo(t2.v); + + }); + + int termByVariableCount = termDataListForDer.size(); + sortedTermsForDer = new EquationTerm[termByVariableCount]; + termActiveStatusIndexForDer = new int[termByVariableCount]; + termEquationActiveStatusIndexForDer = new int[termByVariableCount]; + termVariable = new Variable[termByVariableCount]; + termByVariableDeriveResultIndex = new int[termByVariableCount]; + termByVariableBranchNumForDer = new int[termByVariableCount]; + sortedTermsVecToValForDer = new VecToVal[termByVariableCount]; + int sortedTermIndex = 0; + for (TermData termData : termDataListForDer) { + sortedTermsForDer[sortedTermIndex] = termData.term; + termActiveStatusIndexForDer[sortedTermIndex] = termData.term.getVectorIndex(); + termEquationActiveStatusIndexForDer[sortedTermIndex] = termData.term.getEquation().getVectorIndex(); + termVariable[sortedTermIndex] = termData.v; + termByVariableBranchNumForDer[sortedTermIndex] = termData.isBranch ? termData.branchNum : -1; + sortedTermsVecToValForDer[sortedTermIndex] = termData.term.getVecToVal(termData.v); + termByVariableDeriveResultIndex[sortedTermIndex] = termData.indexForResult; + sortedTermIndex += 1; + } + + termDataListForEval.sort((t1, t2) -> { + // Branch elements together, sorted by branchNum then by bus, then by variable + int compare = -Boolean.compare(t1.isBranch, t2.isBranch); // Put branch terms first + if (compare != 0) { + return compare; + } + + compare = t1.branchNum - t2.branchNum; + if (compare != 0) { + return compare; + } + + return t1.busNum - t2.busNum; + + }); + + int termByEquationCount = termDataListForEval.size(); + sortedTermsForEval = new EquationTerm[termByEquationCount]; + termActiveStatusIndexForEval = new int[termByEquationCount]; + termEquationActiveStatusIndexForEval = new int[termByEquationCount]; + termByEvalResultIndex = new int[termByEquationCount]; + termByEquationBranchNumForEval = new int[termByEquationCount]; + sortedTermsVecToValForEval = new VecToVal[termByEquationCount]; + sortedTermIndex = 0; + for (TermData termData : termDataListForEval) { + sortedTermsForEval[sortedTermIndex] = termData.term; + termActiveStatusIndexForEval[sortedTermIndex] = termData.term.getVectorIndex(); + termEquationActiveStatusIndexForEval[sortedTermIndex] = termData.term.getEquation().getVectorIndex(); + termByEquationBranchNumForEval[sortedTermIndex] = termData.term instanceof AbstractClosedBranchAcFlowEquationTerm ? termData.branchNum : -1; + sortedTermsVecToValForEval[sortedTermIndex] = termData.term.getVecToVal(null); + termByEvalResultIndex[sortedTermIndex] = termData.indexForResult; + sortedTermIndex += 1; + } + + equationDataValid = true; + } + + private void sortEquations() { + Iterator it = IntStream.range(0, equationColumn.length).boxed() + .sorted((i1, i2) -> equationColumn[i1] - equationColumn[i2]).iterator(); + int i = 0; + while (it.hasNext()) { + sortedEquationIndexArray[i] = it.next(); + i += 1; + } + equationOrderValid = true; + } + + @Override + public void der(boolean update, Matrix matrix) { + + if (!equationDataValid) { + initEquationData(); + equationOrderValid = false; + } + + if (!equationOrderValid) { + sortEquations(); + } + + updateVariables(); // do not depend on listener call order + + derSortedTerms(); + + for (int sortedEqIndex = 0; sortedEqIndex < equationActiveStatus.length; sortedEqIndex++) { + int eqIndex = sortedEquationIndexArray[sortedEqIndex]; + if (equationActiveStatus[eqIndex]) { + int col = equationColumn[eqIndex]; + int varEnd = variablePerEquationIndex[eqIndex] + variableCountPerEquation[eqIndex]; + for (int varIndex = variablePerEquationIndex[eqIndex]; varIndex < varEnd; varIndex++) { + Variable v = variablesPerEquation[varIndex]; + int row = v.getRow(); + if (row >= 0) { + if (update) { + matrix.addAtIndex(matrixIndexPerVariableAndEquation[varIndex], deriveResultPerVariableAndEquation[varIndex]); + } else { + matrixIndexPerVariableAndEquation[varIndex] = matrix.addAndGetIndex(row, col, deriveResultPerVariableAndEquation[varIndex]); + } + } + } + } + } + } + + private void evalSortedTerms() { + Arrays.fill(evalResultPerEquation, 0); + evalSortedTermsVec(); + evalSortedTermsObj(); + } + + private void evalSortedTermsVec() { + int branchNum = -1; + double a1Evaluated = Double.NaN; + double r1Evaluated = Double.NaN; + double sinKsi = Double.NaN; + double cosKsi = Double.NaN; + double theta2 = Double.NaN; + double sinTheta2 = Double.NaN; + double cosTheta2 = Double.NaN; + double theta1 = Double.NaN; + double sinTheta1 = Double.NaN; + double cosTheta1 = Double.NaN; + for (int termIndex = 0; termIndex < sortedTermsForEval.length; termIndex++) { + if (equationActiveStatus[termEquationActiveStatusIndexForEval[termIndex]] && + termActiveStatus[termActiveStatusIndexForEval[termIndex]]) { + int termStatusIndex = termActiveStatusIndexForEval[termIndex]; + if (termByEquationBranchNumForEval[termIndex] != branchNum && termByEquationBranchNumForEval[termIndex] != -1) { + branchNum = termByEquationBranchNumForEval[termIndex]; + sinKsi = FastMath.sin(ksi[branchNum]); + cosKsi = FastMath.cos(ksi[branchNum]); + a1Evaluated = a1TermSupplier[termStatusIndex] == null ? a1[branchNum] : a1TermSupplier[termStatusIndex].getAsDouble(); + r1Evaluated = r1TermSupplier[termStatusIndex] == null ? r1[branchNum] : r1TermSupplier[termStatusIndex].getAsDouble(); + theta2 = AbstractClosedBranchAcFlowEquationTerm.theta2(ksi[branchNum], ph1[branchNum], a1Evaluated, ph2[branchNum]); + sinTheta2 = FastMath.sin(theta2); + cosTheta2 = FastMath.cos(theta2); + theta1 = AbstractClosedBranchAcFlowEquationTerm.theta1(ksi[branchNum], ph1[branchNum], a1Evaluated, ph2[branchNum]); + sinTheta1 = FastMath.sin(theta1); + cosTheta1 = FastMath.cos(theta1); + } + if (sortedTermsVecToValForEval[termIndex] != null) { + evalResultPerEquation[termByEvalResultIndex[termIndex]] += + sortedTermsVecToValForEval[termIndex].value(v1[branchNum], v2[branchNum], sinKsi, cosKsi, sinTheta2, cosTheta2, sinTheta1, cosTheta1, + b1[branchNum], b2[branchNum], + g1[branchNum], g2[branchNum], y[branchNum], g12[branchNum], b12[branchNum], a1Evaluated, r1Evaluated); + } + } + } + } + + private void evalSortedTermsObj() { + for (int termIndex = 0; termIndex < sortedTermsForEval.length; termIndex++) { + if (equationActiveStatus[termEquationActiveStatusIndexForEval[termIndex]] && + termActiveStatus[termActiveStatusIndexForEval[termIndex]]) { + if (sortedTermsVecToValForEval[termIndex] == null) { + evalResultPerEquation[termByEvalResultIndex[termIndex]] += sortedTermsForEval[termIndex].evalLhs(); + } + + } + } + } + + private void derSortedTerms() { + Arrays.fill(deriveResultPerVariableAndEquation, 0); + derSortedTermsVec(); + derSortedTermsObj(); + } + + private void derSortedTermsVec() { + int branchNum = -1; + double a1Evaluated = Double.NaN; + double r1Evaluated = Double.NaN; + double sinKsi = Double.NaN; + double cosKsi = Double.NaN; + double theta2 = Double.NaN; + double sinTheta2 = Double.NaN; + double cosTheta2 = Double.NaN; + double theta1 = Double.NaN; + double sinTheta1 = Double.NaN; + double cosTheta1 = Double.NaN; + for (int termIndex = 0; termIndex < sortedTermsForDer.length; termIndex++) { + if (equationActiveStatus[termEquationActiveStatusIndexForDer[termIndex]] && + termActiveStatus[termActiveStatusIndexForDer[termIndex]]) { + int termStatusIndex = termActiveStatusIndexForDer[termIndex]; + if (termByVariableBranchNumForDer[termIndex] != branchNum && termByVariableBranchNumForDer[termIndex] != -1) { + branchNum = termByVariableBranchNumForDer[termIndex]; + sinKsi = FastMath.sin(ksi[branchNum]); + cosKsi = FastMath.cos(ksi[branchNum]); + a1Evaluated = a1TermSupplier[termStatusIndex] == null ? a1[branchNum] : a1TermSupplier[termStatusIndex].getAsDouble(); + r1Evaluated = r1TermSupplier[termStatusIndex] == null ? r1[branchNum] : r1TermSupplier[termStatusIndex].getAsDouble(); + theta2 = AbstractClosedBranchAcFlowEquationTerm.theta2(ksi[branchNum], ph1[branchNum], a1Evaluated, ph2[branchNum]); + sinTheta2 = FastMath.sin(theta2); + cosTheta2 = FastMath.cos(theta2); + theta1 = AbstractClosedBranchAcFlowEquationTerm.theta1(ksi[branchNum], ph1[branchNum], a1Evaluated, ph2[branchNum]); + sinTheta1 = FastMath.sin(theta1); + cosTheta1 = FastMath.cos(theta1); + // TODO: incrementalPhaseShifterActovePowerControlTest fails if those terms are shared per branch + // Add a listener on tap position change + } + if (sortedTermsVecToValForDer[termIndex] != null) { + deriveResultPerVariableAndEquation[termByVariableDeriveResultIndex[termIndex]] += + sortedTermsVecToValForDer[termIndex].value(v1[branchNum], v2[branchNum], sinKsi, cosKsi, sinTheta2, cosTheta2, sinTheta1, cosTheta1, + b1[branchNum], b2[branchNum], + g1[branchNum], g2[branchNum], y[branchNum], g12[branchNum], b12[branchNum], a1Evaluated, r1Evaluated); + } + } + } + } + + private void derSortedTermsObj() { + for (int termIndex = 0; termIndex < sortedTermsForDer.length; termIndex++) { + if (equationActiveStatus[termEquationActiveStatusIndexForDer[termIndex]] && + termActiveStatus[termActiveStatusIndexForDer[termIndex]]) { + if (sortedTermsVecToValForDer[termIndex] == null) { + deriveResultPerVariableAndEquation[termByVariableDeriveResultIndex[termIndex]] += sortedTermsForDer[termIndex].der(termVariable[termIndex]); + } + + } + } + } + +} diff --git a/src/main/java/com/powsybl/openloadflow/equations/AbstractEquationTerm.java b/src/main/java/com/powsybl/openloadflow/equations/AbstractEquationTerm.java index 25685f1e6f..a7ca124723 100644 --- a/src/main/java/com/powsybl/openloadflow/equations/AbstractEquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/equations/AbstractEquationTerm.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -22,6 +22,8 @@ public abstract class AbstractEquationTerm & Quantity, E exten private boolean active; + private int vectorIndex = -1; + protected StateVector sv; protected EquationTerm self = this; @@ -60,6 +62,10 @@ public void setActive(boolean active) { this.active = active; equation.getEquationSystem().notifyEquationTermChange(self, active ? EquationTermEventType.EQUATION_TERM_ACTIVATED : EquationTermEventType.EQUATION_TERM_DEACTIVATED); + // TODO: Remove the trace + if (getVectorIndex() == 0) { + System.out.println(Thread.currentThread().getName() + " Active Status " + getClass().getSimpleName() + " " + getVectorIndex() + " " + active); + } } } @@ -68,6 +74,16 @@ public boolean isActive() { return active; } + @Override + public void setVectorIndex(int n) { + this.vectorIndex = n; + } + + @Override + public int getVectorIndex() { + return vectorIndex; + } + @Override public void setSelf(EquationTerm self) { this.self = Objects.requireNonNull(self); diff --git a/src/main/java/com/powsybl/openloadflow/equations/Equation.java b/src/main/java/com/powsybl/openloadflow/equations/Equation.java index b0a75ecad2..c0818a1bc1 100644 --- a/src/main/java/com/powsybl/openloadflow/equations/Equation.java +++ b/src/main/java/com/powsybl/openloadflow/equations/Equation.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -30,6 +30,8 @@ public class Equation & Quantity, E extends Enum & Quantity private int column = -1; + private int vectorIndex = -1; + /** * true if this equation term active, false otherwise */ @@ -81,6 +83,18 @@ public int getColumn() { public void setColumn(int column) { this.column = column; + + if (equationSystem != null) { + equationSystem.notifyEquationChange(this, EquationEventType.EQUATION_COLUMN_CHANGED); + } + } + + public int getVectorIndex() { + return vectorIndex; + } + + public void setVectorIndex(int vectorIndex) { + this.vectorIndex = vectorIndex; } public boolean isActive() { @@ -96,6 +110,19 @@ public Equation setActive(boolean active) { return this; } + public int getVariableCount() { + return termsByVariable.size(); + } + + public List> getVariables() { + return termsByVariable.keySet().stream().toList(); + } + + public List> getTerms(Variable v) { + List> list = termsByVariable.get(v); + return list == null ? Collections.emptyList() : Collections.unmodifiableList(list); + } + public Equation addTerm(EquationTerm term) { Objects.requireNonNull(term); checkNotRemoved(); @@ -146,10 +173,6 @@ private void addLeafTerms(EquationTerm term, List> leaf } } - public Map, List>> getTermsByVariable() { - return termsByVariable; - } - @Override public double eval() { double value = 0; diff --git a/src/main/java/com/powsybl/openloadflow/equations/EquationEventType.java b/src/main/java/com/powsybl/openloadflow/equations/EquationEventType.java index b426a04c81..d997c6045a 100644 --- a/src/main/java/com/powsybl/openloadflow/equations/EquationEventType.java +++ b/src/main/java/com/powsybl/openloadflow/equations/EquationEventType.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -14,5 +14,6 @@ public enum EquationEventType { EQUATION_CREATED, EQUATION_REMOVED, EQUATION_ACTIVATED, - EQUATION_DEACTIVATED; + EQUATION_DEACTIVATED, + EQUATION_COLUMN_CHANGED; } diff --git a/src/main/java/com/powsybl/openloadflow/equations/EquationSystem.java b/src/main/java/com/powsybl/openloadflow/equations/EquationSystem.java index fcdda2b7c5..b3a5255608 100644 --- a/src/main/java/com/powsybl/openloadflow/equations/EquationSystem.java +++ b/src/main/java/com/powsybl/openloadflow/equations/EquationSystem.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -39,6 +39,8 @@ public class EquationSystem & Quantity, E extends Enum & Qu private final EquationSystemIndex index; + private VectorEngine vectorEngine; + public EquationSystem() { this(new VariableSet<>()); } @@ -230,6 +232,14 @@ void notifyEquationTermChange(EquationTerm term, EquationTermEventType eve listeners.forEach(listener -> listener.onEquationTermChange(term, eventType)); } + public VectorEngine getVectorEngine() { + return vectorEngine; + } + + public void setVectorEngine(VectorEngine vectorEngine) { + this.vectorEngine = vectorEngine; + } + public void write(Writer writer, boolean writeInactiveEquations) { try { for (Equation equation : equations.values().stream().sorted().collect(Collectors.toList())) { diff --git a/src/main/java/com/powsybl/openloadflow/equations/EquationSystemIndex.java b/src/main/java/com/powsybl/openloadflow/equations/EquationSystemIndex.java index 4950728be4..c5f3899d66 100644 --- a/src/main/java/com/powsybl/openloadflow/equations/EquationSystemIndex.java +++ b/src/main/java/com/powsybl/openloadflow/equations/EquationSystemIndex.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2022, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2022-2025, 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/. @@ -160,6 +160,9 @@ public void onEquationChange(Equation equation, EquationEventType eventTyp addEquation(equation); break; + case EQUATION_COLUMN_CHANGED: + break; + default: throw new IllegalStateException("Event type not supported: " + eventType); } diff --git a/src/main/java/com/powsybl/openloadflow/equations/EquationTerm.java b/src/main/java/com/powsybl/openloadflow/equations/EquationTerm.java index 3f280fd95f..9bcb72b453 100644 --- a/src/main/java/com/powsybl/openloadflow/equations/EquationTerm.java +++ b/src/main/java/com/powsybl/openloadflow/equations/EquationTerm.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -77,6 +77,16 @@ public boolean isActive() { return term.isActive(); } + @Override + public void setVectorIndex(int n) { + term.setVectorIndex(n); + } + + @Override + public int getVectorIndex() { + return term.getVectorIndex(); + } + @Override public void setSelf(EquationTerm self) { term.setSelf(self); @@ -133,6 +143,7 @@ public void write(Writer writer) throws IOException { writer.write(" * "); term.write(writer); } + } static & Quantity, E extends Enum & Quantity> EquationTerm multiply(EquationTerm term, DoubleSupplier scalarSupplier) { @@ -221,4 +232,16 @@ default EquationTerm multiply(double scalar) { default EquationTerm minus() { return multiply(-1); } + + default VectorEngine.VecToVal getVecToVal(Variable v) { + return null; + } + + default int getVectorIndex(Variable v) { + return -1; + } + + void setVectorIndex(int n); + + int getVectorIndex(); } diff --git a/src/main/java/com/powsybl/openloadflow/equations/EquationVector.java b/src/main/java/com/powsybl/openloadflow/equations/EquationVector.java index 3a52ae1409..9359103d6f 100644 --- a/src/main/java/com/powsybl/openloadflow/equations/EquationVector.java +++ b/src/main/java/com/powsybl/openloadflow/equations/EquationVector.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2022, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2022-2025, 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/. @@ -44,8 +44,12 @@ protected double[] createArray() { private void evalLhs(double[] array, List> equations) { Arrays.fill(array, 0); // necessary? - for (Equation equation : equations) { - array[equation.getColumn()] = equation.evalLhs(); + if (equationSystem.getVectorEngine() != null) { + equationSystem.getVectorEngine().evalLhs(array); + } else { + for (Equation equation : equations) { + array[equation.getColumn()] = equation.evalLhs(); + } } } diff --git a/src/main/java/com/powsybl/openloadflow/equations/JacobianMatrix.java b/src/main/java/com/powsybl/openloadflow/equations/JacobianMatrix.java index 61b718e32a..630f7080c1 100644 --- a/src/main/java/com/powsybl/openloadflow/equations/JacobianMatrix.java +++ b/src/main/java/com/powsybl/openloadflow/equations/JacobianMatrix.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -38,6 +38,8 @@ public class JacobianMatrix & Quantity, E extends Enum & Qu private LUDecomposition lu; + private final VectorEngine vectorEngine; + protected enum Status { VALID, VALUES_INVALID, // same structure but values have to be updated @@ -52,6 +54,7 @@ public JacobianMatrix(EquationSystem equationSystem, MatrixFactory matrixF this.matrixFactory = Objects.requireNonNull(matrixFactory); equationSystem.getIndex().addListener(this); equationSystem.getStateVector().addListener(this); + vectorEngine = equationSystem.getVectorEngine(); } protected void updateStatus(Status status) { @@ -93,12 +96,16 @@ private void initDer() { int estimatedNonZeroValueCount = rowCount * 3; matrix = matrixFactory.create(rowCount, columnCount, estimatedNonZeroValueCount); - for (Equation eq : equationSystem.getIndex().getSortedEquationsToSolve()) { - int column = eq.getColumn(); - eq.der((variable, value, matrixElementIndex) -> { - int row = variable.getRow(); - return matrix.addAndGetIndex(row, column, value); - }); + if (vectorEngine != null) { + vectorEngine.der(false, matrix); + } else { + for (Equation eq : equationSystem.getIndex().getSortedEquationsToSolve()) { + int column = eq.getColumn(); + eq.der((variable, value, matrixElementIndex) -> { + int row = variable.getRow(); + return matrix.addAndGetIndex(row, column, value); + }); + } } LOGGER.debug(PERFORMANCE_MARKER, "Jacobian matrix built in {} us", stopwatch.elapsed(TimeUnit.MICROSECONDS)); @@ -120,11 +127,16 @@ private void updateDer() { Stopwatch stopwatch = Stopwatch.createStarted(); matrix.reset(); - for (Equation eq : equationSystem.getIndex().getSortedEquationsToSolve()) { - eq.der((variable, value, matrixElementIndex) -> { - matrix.addAtIndex(matrixElementIndex, value); - return matrixElementIndex; // don't change element index - }); + + if (vectorEngine != null) { + vectorEngine.der(true, matrix); + } else { + for (Equation eq : equationSystem.getIndex().getSortedEquationsToSolve()) { + eq.der((variable, value, matrixElementIndex) -> { + matrix.addAtIndex(matrixElementIndex, value); + return matrixElementIndex; // don't change element index + }); + } } LOGGER.debug(PERFORMANCE_MARKER, "Jacobian matrix values updated in {} us", stopwatch.elapsed(TimeUnit.MICROSECONDS)); diff --git a/src/main/java/com/powsybl/openloadflow/equations/VectorEngine.java b/src/main/java/com/powsybl/openloadflow/equations/VectorEngine.java new file mode 100644 index 0000000000..282ff69598 --- /dev/null +++ b/src/main/java/com/powsybl/openloadflow/equations/VectorEngine.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ + +package com.powsybl.openloadflow.equations; + +import com.powsybl.math.matrix.Matrix; + +public interface VectorEngine & Quantity> { + + interface VecToVal { + double value(double v1, double v2, double sinKsi, double cosKsi, double sinTheta2, double cosTheta2, + double sinTheta1, double cosTheta1, + double b1, double b2, double g1, double g2, double y, + double g12, double b12, double a1, double r1); + } + + void der(boolean update, Matrix matrix); + + void evalLhs(double[] array); +} diff --git a/src/test/java/com/powsybl/openloadflow/EquationsTest.java b/src/test/java/com/powsybl/openloadflow/EquationsTest.java index 6cc9e27816..7f3efe9587 100644 --- a/src/test/java/com/powsybl/openloadflow/EquationsTest.java +++ b/src/test/java/com/powsybl/openloadflow/EquationsTest.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2022, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2022-2025, 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/. @@ -10,6 +10,7 @@ import com.powsybl.commons.PowsyblException; import com.powsybl.math.matrix.DenseMatrix; import com.powsybl.openloadflow.ac.equations.*; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.dc.equations.ClosedBranchSide1DcFlowEquationTerm; import com.powsybl.openloadflow.dc.equations.ClosedBranchSide2DcFlowEquationTerm; import com.powsybl.openloadflow.dc.equations.DcApproximationType; @@ -96,6 +97,8 @@ private static & Quantity, E extends Enum & Quantity> doub return values; } + private AcVectorEngine acVectorEnginee; + private LfBranch branch; private LfBus bus1; @@ -104,6 +107,7 @@ private static & Quantity, E extends Enum & Quantity> doub @BeforeEach void setUp() { + acVectorEnginee = new AcVectorEngine(null, null); branch = Mockito.mock(LfBranch.class, ANSWER); Mockito.doReturn(0).when(branch).getNum(); Mockito.doReturn(false).when(branch).isDisabled(); @@ -118,6 +122,7 @@ void setUp() { Mockito.doReturn(B_2).when(piModel).getB2(); Mockito.doReturn(KSI).when(piModel).getKsi(); Mockito.doReturn(R_1).when(piModel).getR1(); + Mockito.doReturn(A_1).when(piModel).getA1(); bus1 = Mockito.mock(LfBus.class, ANSWER); bus2 = Mockito.mock(LfBus.class, ANSWER); @@ -149,51 +154,51 @@ void branchTest() { // closed branch equations assertArrayEquals(new double[] {41.78173051479356, 48.66261692116701, 138.21343172859858, 29.31710523088579, -138.21343172859858, 54.62161149356045, 138.21343172859858, Double.NaN, 270.81476537421185}, - eval(new ClosedBranchSide1ActiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true), variables, sv)); + eval(new ClosedBranchSide1ActiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true, acVectorEnginee), variables, sv)); assertArrayEquals(new double[] {-3.500079625302254, 122.46444997806617, 31.42440177840898, -128.9449438332101, -31.42440177840898, 137.46086897280827, 31.42440177840898, Double.NaN, 162.40477689607334}, - eval(new ClosedBranchSide1ReactiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true), variables, sv)); + eval(new ClosedBranchSide1ReactiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true, acVectorEnginee), variables, sv)); assertArrayEquals(new double[] {39.13246485286217, -0.8052805161189096, 126.09926753871545, 37.31322159867258, -126.09926753871542, Double.NaN, 126.09926753871542, Double.NaN, Double.NaN}, - eval(new ClosedBranchSide1CurrentMagnitudeEquationTerm(branch, bus1, bus2, variableSet, true, true), variables, sv)); + eval(new ClosedBranchSide1CurrentMagnitudeEquationTerm(branch, bus1, bus2, variableSet, true, true, acVectorEnginee), variables, sv)); assertArrayEquals(new double[] {-40.6365773800554, -48.52391742324069, -131.8614376204652, -27.319027760225953, 131.8614376204652, -54.4659275092331, -131.8614376204652, Double.NaN, -262.1703103131649}, - eval(new ClosedBranchSide2ActiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true), variables, sv)); + eval(new ClosedBranchSide2ActiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true, acVectorEnginee), variables, sv)); assertArrayEquals(new double[] {16.04980301110306, -123.06939783256767, 51.99045110393844, 152.96594042215764, -51.99045110393844, -138.1398958886022, 51.99045110393844, Double.NaN, -56.2529021950738}, - eval(new ClosedBranchSide2ReactiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true), variables, sv)); + eval(new ClosedBranchSide2ReactiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true, acVectorEnginee), variables, sv)); assertArrayEquals(new double[] {40.7613721648136, -0.07246503940372644, 132.23571821183896, 38.10038077658943, -132.23571821183896, Double.NaN, 132.23571821183896, Double.NaN, Double.NaN}, - eval(new ClosedBranchSide2CurrentMagnitudeEquationTerm(branch, bus1, bus2, variableSet, true, true), variables, sv)); + eval(new ClosedBranchSide2CurrentMagnitudeEquationTerm(branch, bus1, bus2, variableSet, true, true, acVectorEnginee), variables, sv)); // open branch equations assertArrayEquals(new double[] {0.1717595025847833, Double.NaN, Double.NaN, 0.3204828812456483, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN}, - eval(new OpenBranchSide1ActiveFlowEquationTerm(branch, bus2, variableSet), variables, sv)); + eval(new OpenBranchSide1ActiveFlowEquationTerm(branch, bus2, variableSet, acVectorEnginee), variables, sv)); assertArrayEquals(new double[] {-0.36364935827807376, Double.NaN, Double.NaN, -0.6785266162875639, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN}, - eval(new OpenBranchSide1ReactiveFlowEquationTerm(branch, bus2, variableSet), variables, sv)); + eval(new OpenBranchSide1ReactiveFlowEquationTerm(branch, bus2, variableSet, acVectorEnginee), variables, sv)); assertArrayEquals(new double[] {0.37520249405559764, Double.NaN, Double.NaN, 0.3500416993992393, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN}, - eval(new OpenBranchSide1CurrentMagnitudeEquationTerm(branch, bus2, variableSet), variables, sv)); + eval(new OpenBranchSide1CurrentMagnitudeEquationTerm(branch, bus2, variableSet, acVectorEnginee), variables, sv)); assertArrayEquals(new double[] {0.15652310047954035, Double.NaN, Double.NaN, 0.2920535601715773, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN}, - eval(new OpenBranchSide2ActiveFlowEquationTerm(branch, bus2, variableSet), variables, sv)); + eval(new OpenBranchSide2ActiveFlowEquationTerm(branch, bus2, variableSet, acVectorEnginee), variables, sv)); assertArrayEquals(new double[] {-0.331495628053771, Double.NaN, Double.NaN, -0.6185315653587614, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN}, - eval(new OpenBranchSide2ReactiveFlowEquationTerm(branch, bus2, variableSet), variables, sv)); + eval(new OpenBranchSide2ReactiveFlowEquationTerm(branch, bus2, variableSet, acVectorEnginee), variables, sv)); assertArrayEquals(new double[] {0.3420075216110214, Double.NaN, Double.NaN, 0.31907275662806295, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN}, - eval(new OpenBranchSide2CurrentMagnitudeEquationTerm(branch, bus2, variableSet, false), variables, sv)); + eval(new OpenBranchSide2CurrentMagnitudeEquationTerm(branch, bus2, variableSet, false, acVectorEnginee), variables, sv)); // assert current equation is consistent with active and reactive power ones - var p1Eq = new ClosedBranchSide1ActiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true); + var p1Eq = new ClosedBranchSide1ActiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true, acVectorEnginee); p1Eq.setStateVector(sv); double p1 = p1Eq.eval(); - var q1Eq = new ClosedBranchSide1ReactiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true); + var q1Eq = new ClosedBranchSide1ReactiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true, acVectorEnginee); q1Eq.setStateVector(sv); double q1 = q1Eq.eval(); - var i1Eq = new ClosedBranchSide1CurrentMagnitudeEquationTerm(branch, bus1, bus2, variableSet, true, true); + var i1Eq = new ClosedBranchSide1CurrentMagnitudeEquationTerm(branch, bus1, bus2, variableSet, true, true, acVectorEnginee); i1Eq.setStateVector(sv); double i1 = i1Eq.eval(); assertEquals(i1, Math.hypot(p1, q1) / V_1, 10e-14); - var p2Eq = new ClosedBranchSide2ActiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true); + var p2Eq = new ClosedBranchSide2ActiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true, acVectorEnginee); p2Eq.setStateVector(sv); double p2 = p2Eq.eval(); - var q2Eq = new ClosedBranchSide2ReactiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true); + var q2Eq = new ClosedBranchSide2ReactiveFlowEquationTerm(branch, bus1, bus2, variableSet, true, true, acVectorEnginee); q2Eq.setStateVector(sv); double q2 = q2Eq.eval(); - var i2Eq = new ClosedBranchSide2CurrentMagnitudeEquationTerm(branch, bus1, bus2, variableSet, true, true); + var i2Eq = new ClosedBranchSide2CurrentMagnitudeEquationTerm(branch, bus1, bus2, variableSet, true, true, acVectorEnginee); i2Eq.setStateVector(sv); double i2 = i2Eq.eval(); assertEquals(i2, Math.hypot(p2, q2) / V_2, 10e-14); diff --git a/src/test/java/com/powsybl/openloadflow/ac/AcLoadFlowPhaseShifterTest.java b/src/test/java/com/powsybl/openloadflow/ac/AcLoadFlowPhaseShifterTest.java index 5df56127ec..391722ed69 100644 --- a/src/test/java/com/powsybl/openloadflow/ac/AcLoadFlowPhaseShifterTest.java +++ b/src/test/java/com/powsybl/openloadflow/ac/AcLoadFlowPhaseShifterTest.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. diff --git a/src/test/java/com/powsybl/openloadflow/equations/EquationSystemTest.java b/src/test/java/com/powsybl/openloadflow/equations/EquationSystemTest.java index 48441d8009..5184d9cf3e 100644 --- a/src/test/java/com/powsybl/openloadflow/equations/EquationSystemTest.java +++ b/src/test/java/com/powsybl/openloadflow/equations/EquationSystemTest.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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/. @@ -53,8 +53,10 @@ void test() { equationSystem.addListener(new EquationSystemListener<>() { @Override public void onEquationChange(Equation equation, EquationEventType eventType) { - equations.add(equation); - equationEventTypes.add(eventType); + if (eventType != EquationEventType.EQUATION_COLUMN_CHANGED) { + equations.add(equation); + equationEventTypes.add(eventType); + } } @Override diff --git a/src/test/java/com/powsybl/openloadflow/network/impl/LfSwitchTest.java b/src/test/java/com/powsybl/openloadflow/network/impl/LfSwitchTest.java index 0d1d3e8b13..2960ddc0c6 100644 --- a/src/test/java/com/powsybl/openloadflow/network/impl/LfSwitchTest.java +++ b/src/test/java/com/powsybl/openloadflow/network/impl/LfSwitchTest.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2021, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2021-2025, 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/. @@ -15,6 +15,7 @@ import com.powsybl.openloadflow.OpenLoadFlowParameters; import com.powsybl.openloadflow.ac.AcLoadFlowParameters; import com.powsybl.openloadflow.ac.equations.*; +import com.powsybl.openloadflow.ac.equations.vector.AcVectorEngine; import com.powsybl.openloadflow.equations.EquationTerm; import com.powsybl.openloadflow.equations.VariableSet; import com.powsybl.openloadflow.graph.EvenShiloachGraphDecrementalConnectivityFactory; @@ -43,6 +44,8 @@ class LfSwitchTest { private AcLoadFlowParameters acLoadFlowParameters; + private AcVectorEngine acVectorEnginee; + @BeforeEach void setUp() { network = NodeBreakerNetworkFactory.create(); @@ -52,6 +55,7 @@ void setUp() { assertEquals(1, lfNetworks.size()); lfNetwork = lfNetworks.get(0); lfSwitch = (LfSwitch) lfNetwork.getBranchById("B3"); + acVectorEnginee = new AcVectorEngine(lfNetwork, null); } @Test @@ -71,15 +75,15 @@ void setterTest() { lfSwitch.getPiModel().setX(LfNetworkParameters.LOW_IMPEDANCE_THRESHOLD_DEFAULT_VALUE); VariableSet variableSet = new VariableSet<>(); - EquationTerm p1 = new ClosedBranchSide1ActiveFlowEquationTerm(lfSwitch, lfSwitch.getBus1(), lfSwitch.getBus2(), variableSet, false, false); - EquationTerm p2 = new ClosedBranchSide2ActiveFlowEquationTerm(lfSwitch, lfSwitch.getBus1(), lfSwitch.getBus2(), variableSet, false, false); + EquationTerm p1 = new ClosedBranchSide1ActiveFlowEquationTerm(lfSwitch, lfSwitch.getBus1(), lfSwitch.getBus2(), variableSet, false, false, acVectorEnginee); + EquationTerm p2 = new ClosedBranchSide2ActiveFlowEquationTerm(lfSwitch, lfSwitch.getBus1(), lfSwitch.getBus2(), variableSet, false, false, acVectorEnginee); lfSwitch.setP1(p1); assertEquals(Double.NaN, lfSwitch.getP1().eval()); lfSwitch.setP2(p2); assertEquals(Double.NaN, lfSwitch.getP2().eval()); - EquationTerm i1 = new ClosedBranchSide1CurrentMagnitudeEquationTerm(lfSwitch, lfSwitch.getBus1(), lfSwitch.getBus2(), variableSet, false, false); - EquationTerm i2 = new ClosedBranchSide2CurrentMagnitudeEquationTerm(lfSwitch, lfSwitch.getBus1(), lfSwitch.getBus2(), variableSet, false, false); + EquationTerm i1 = new ClosedBranchSide1CurrentMagnitudeEquationTerm(lfSwitch, lfSwitch.getBus1(), lfSwitch.getBus2(), variableSet, false, false, acVectorEnginee); + EquationTerm i2 = new ClosedBranchSide2CurrentMagnitudeEquationTerm(lfSwitch, lfSwitch.getBus1(), lfSwitch.getBus2(), variableSet, false, false, acVectorEnginee); lfSwitch.setI1(i1); assertEquals(Double.NaN, lfSwitch.getP1().eval()); lfSwitch.setI2(i2); diff --git a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java index c2d989f9af..fc2ccd4450 100644 --- a/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java +++ b/src/test/java/com/powsybl/openloadflow/sa/OpenSecurityAnalysisTest.java @@ -1336,6 +1336,8 @@ void testPhaseShifterNecessaryForConnectivity() { LoadFlowParameters parameters = new LoadFlowParameters() .setPhaseShifterRegulationOn(true); + // Set slack mismatch equal to comparison epsilon + parameters.addExtension(OpenLoadFlowParameters.class, new OpenLoadFlowParameters().setSlackBusPMaxMismatch(0.001)); List contingencies = List.of(Contingency.line("L2"), Contingency.twoWindingsTransformer("PS1"), Contingency.line("L1")); // I added L2 and PS1 before to assert there is no impact on L1 contingency