diff --git a/ampl-converter/src/main/java/com/powsybl/ampl/converter/AmplNetworkReader.java b/ampl-converter/src/main/java/com/powsybl/ampl/converter/AmplNetworkReader.java index 957ceaad05..e2be25c15c 100644 --- a/ampl-converter/src/main/java/com/powsybl/ampl/converter/AmplNetworkReader.java +++ b/ampl-converter/src/main/java/com/powsybl/ampl/converter/AmplNetworkReader.java @@ -6,6 +6,7 @@ */ package com.powsybl.ampl.converter; +import com.powsybl.commons.PowsyblException; import com.powsybl.commons.datasource.ReadOnlyDataSource; import com.powsybl.commons.util.StringToIntMapper; import com.powsybl.iidm.network.*; @@ -277,6 +278,9 @@ private Void readShunt(String[] tokens) { throw new AmplException("Invalid shunt compensator id '" + id + "'"); } + if (ShuntCompensatorModelType.NON_LINEAR.equals(sc.getModelType())) { + throw new PowsyblException("non linear shunt not supported yet"); + } sc.setCurrentSectionCount(Math.max(0, Math.min(sc.getMaximumSectionCount(), sections))); Terminal t = sc.getTerminal(); t.setQ(q); diff --git a/ampl-converter/src/main/java/com/powsybl/ampl/converter/AmplNetworkWriter.java b/ampl-converter/src/main/java/com/powsybl/ampl/converter/AmplNetworkWriter.java index 19e94af26a..4e35d0d256 100644 --- a/ampl-converter/src/main/java/com/powsybl/ampl/converter/AmplNetworkWriter.java +++ b/ampl-converter/src/main/java/com/powsybl/ampl/converter/AmplNetworkWriter.java @@ -20,6 +20,7 @@ import java.util.Objects; import java.util.Set; +import com.powsybl.commons.PowsyblException; import com.powsybl.iidm.network.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -1310,6 +1311,9 @@ private void writeShunts(AmplExportContext context) throws IOException { new Column("sections count"))) { List skipped = new ArrayList<>(); for (ShuntCompensator sc : network.getShuntCompensators()) { + if (ShuntCompensatorModelType.NON_LINEAR.equals(sc.getModelType())) { + throw new PowsyblException("Non linear shunt compensator not yet supported"); + } Terminal t = sc.getTerminal(); Bus bus = AmplUtil.getBus(t); String busId = null; @@ -1336,7 +1340,7 @@ private void writeShunts(AmplExportContext context) throws IOException { double vb = t.getVoltageLevel().getNominalV(); double zb = vb * vb / AmplConstants.SB; double b1 = 0; - double b2 = sc.getbPerSection() * sc.getMaximumSectionCount() * zb; + double b2 = sc.getModel(ShuntCompensatorLinearModel.class).getbPerSection() * sc.getMaximumSectionCount() * zb; double minB = Math.min(b1, b2); double maxB = Math.max(b1, b2); double b = sc.getCurrentB() * zb; diff --git a/cgmes/cgmes-conformity/src/test/java/com/powsybl/cgmes/conformity/test/CgmesConformity1NetworkCatalog.java b/cgmes/cgmes-conformity/src/test/java/com/powsybl/cgmes/conformity/test/CgmesConformity1NetworkCatalog.java index da1523bbd5..229d5443f6 100644 --- a/cgmes/cgmes-conformity/src/test/java/com/powsybl/cgmes/conformity/test/CgmesConformity1NetworkCatalog.java +++ b/cgmes/cgmes-conformity/src/test/java/com/powsybl/cgmes/conformity/test/CgmesConformity1NetworkCatalog.java @@ -180,9 +180,11 @@ private static Network microBE(String modelId) { .setName("BE_S2") .setConnectableBus(busBrussels380.getId()) .setBus(busBrussels380.getId()) - .setbPerSection(3.46e-4) - .setMaximumSectionCount(1) .setCurrentSectionCount(1) + .newLinearModel() + .setbPerSection(3.46e-4) + .setMaximumSectionCount(1) + .add() .add(); shBrussels380.getTerminal().setQ(-59.058144); DanglingLine be3 = vlBrussels380.newDanglingLine() @@ -268,9 +270,11 @@ private static Network microBE(String modelId) { .setName("BE_S1") .setConnectableBus(busBrussels110.getId()) .setBus(busBrussels110.getId()) - .setbPerSection(0.024793) - .setMaximumSectionCount(1) .setCurrentSectionCount(1) + .newLinearModel() + .setbPerSection(0.024793) + .setMaximumSectionCount(1) + .add() .add(); shBrussels110.getTerminal().setQ(-330.75); Bus busBrussels21 = vlBrussels21.getBusBreakerView().newBus() diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/EquivalentShuntConversion.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/EquivalentShuntConversion.java index ba04147052..fba99208ba 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/EquivalentShuntConversion.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/EquivalentShuntConversion.java @@ -22,9 +22,11 @@ public EquivalentShuntConversion(PropertyBag p, Context context) { @Override public void convert() { ShuntCompensatorAdder adder = voltageLevel().newShuntCompensator() - .setbPerSection(p.asDouble("b")) - .setMaximumSectionCount(1) - .setCurrentSectionCount(terminalConnected() ? 1 : 0); + .setCurrentSectionCount(terminalConnected() ? 1 : 0) + .newLinearModel() + .setbPerSection(p.asDouble("b")) + .setMaximumSectionCount(1) + .add(); identify(adder); connect(adder); adder.add(); diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/ShuntConversion.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/ShuntConversion.java index 434af24f32..c7929f8208 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/ShuntConversion.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/ShuntConversion.java @@ -66,8 +66,10 @@ public void convert() { ShuntCompensatorAdder adder = voltageLevel().newShuntCompensator() .setCurrentSectionCount(sections) - .setbPerSection(bPerSection) - .setMaximumSectionCount(maximumSections); + .newLinearModel() + .setbPerSection(bPerSection) + .setMaximumSectionCount(maximumSections) + .add(); identify(adder); connect(adder); ShuntCompensator shunt = adder.add(); diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/conformity/modified/CgmesConformity1ModifiedConversionTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/conformity/modified/CgmesConformity1ModifiedConversionTest.java index e2a2a63fd1..0464f0634e 100644 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/conformity/modified/CgmesConformity1ModifiedConversionTest.java +++ b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/conformity/modified/CgmesConformity1ModifiedConversionTest.java @@ -267,7 +267,7 @@ public void microBEEquivalentShunt() { ShuntCompensator shunt = network.getShuntCompensator("_d771118f-36e9-4115-a128-cc3d9ce3e3da"); assertNotNull(shunt); assertEquals(1, shunt.getMaximumSectionCount()); - assertEquals(0.0012, shunt.getbPerSection(), 0.0); + assertEquals(0.0012, shunt.getModel(ShuntCompensatorLinearModel.class).getbPerSection(), 0.0); assertEquals(1, shunt.getCurrentSectionCount()); } diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/network/compare/Comparison.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/network/compare/Comparison.java index b4e7786864..1f2f4b1c2e 100644 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/network/compare/Comparison.java +++ b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/network/compare/Comparison.java @@ -13,31 +13,8 @@ import java.util.stream.Stream; import com.powsybl.cgmes.model.CgmesNames; -import com.powsybl.iidm.network.Bus; -import com.powsybl.iidm.network.CurrentLimits; -import com.powsybl.iidm.network.DanglingLine; -import com.powsybl.iidm.network.Generator; -import com.powsybl.iidm.network.Identifiable; -import com.powsybl.iidm.network.Line; -import com.powsybl.iidm.network.Load; -import com.powsybl.iidm.network.MinMaxReactiveLimits; -import com.powsybl.iidm.network.Network; -import com.powsybl.iidm.network.PhaseTapChanger; -import com.powsybl.iidm.network.PhaseTapChangerStep; -import com.powsybl.iidm.network.RatioTapChanger; -import com.powsybl.iidm.network.RatioTapChangerStep; -import com.powsybl.iidm.network.ReactiveCapabilityCurve; +import com.powsybl.iidm.network.*; import com.powsybl.iidm.network.ReactiveCapabilityCurve.Point; -import com.powsybl.iidm.network.ReactiveLimits; -import com.powsybl.iidm.network.ShuntCompensator; -import com.powsybl.iidm.network.StaticVarCompensator; -import com.powsybl.iidm.network.Substation; -import com.powsybl.iidm.network.Switch; -import com.powsybl.iidm.network.TapChanger; -import com.powsybl.iidm.network.TapChangerStep; -import com.powsybl.iidm.network.ThreeWindingsTransformer; -import com.powsybl.iidm.network.TwoWindingsTransformer; -import com.powsybl.iidm.network.VoltageLevel; import com.powsybl.iidm.network.extensions.CoordinatedReactiveControl; import com.powsybl.iidm.network.extensions.TwoWindingsTransformerPhaseAngleClock; import com.powsybl.iidm.network.extensions.ThreeWindingsTransformerPhaseAngleClock; @@ -233,8 +210,8 @@ private void compareShunts(ShuntCompensator expected, ShuntCompensator actual) { expected.getMaximumSectionCount(), actual.getMaximumSectionCount()); compare("bPerSection", - expected.getbPerSection(), - actual.getbPerSection()); + expected.getModel(ShuntCompensatorLinearModel.class).getbPerSection(), + actual.getModel(ShuntCompensatorLinearModel.class).getbPerSection()); compare("voltageRegulationOn", expected.isVoltageRegulatorOn(), actual.isVoltageRegulatorOn()); diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/update/NetworkChanges.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/update/NetworkChanges.java index 261ab691f7..a62130d4c0 100644 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/update/NetworkChanges.java +++ b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/update/NetworkChanges.java @@ -6,20 +6,12 @@ */ package com.powsybl.cgmes.conversion.test.update; +import com.powsybl.iidm.network.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.powsybl.cgmes.conversion.update.elements16.GeneratorToSynchronousMachine; import com.powsybl.cgmes.conversion.update.elements16.TwoWindingsTransformerToPowerTransformer; -import com.powsybl.iidm.network.Generator; -import com.powsybl.iidm.network.Line; -import com.powsybl.iidm.network.Load; -import com.powsybl.iidm.network.MinMaxReactiveLimits; -import com.powsybl.iidm.network.Network; -import com.powsybl.iidm.network.ReactiveLimitsKind; -import com.powsybl.iidm.network.ShuntCompensator; -import com.powsybl.iidm.network.TwoWindingsTransformer; -import com.powsybl.iidm.network.VoltageLevel; /** * @author Luma Zamarreño @@ -91,8 +83,8 @@ public static void modifyEquipmentCharacteristics(Network network) { if (network.getShuntCompensatorCount() > 0) { ShuntCompensator sh = network.getShuntCompensators().iterator().next(); - sh.setbPerSection(sh.getbPerSection() + 0.2); - sh.setMaximumSectionCount(sh.getMaximumSectionCount() + 5); + sh.getModel(ShuntCompensatorLinearModel.class).setbPerSection(sh.getModel(ShuntCompensatorLinearModel.class).getbPerSection() + 0.2); + sh.getModel(ShuntCompensatorLinearModel.class).setMaximumSectionCount(sh.getMaximumSectionCount() + 5); } } diff --git a/ieee-cdf/ieee-cdf-converter/src/main/java/com/powsybl/ieeecdf/converter/IeeeCdfImporter.java b/ieee-cdf/ieee-cdf-converter/src/main/java/com/powsybl/ieeecdf/converter/IeeeCdfImporter.java index d04fce9aef..99767b497f 100644 --- a/ieee-cdf/ieee-cdf-converter/src/main/java/com/powsybl/ieeecdf/converter/IeeeCdfImporter.java +++ b/ieee-cdf/ieee-cdf-converter/src/main/java/com/powsybl/ieeecdf/converter/IeeeCdfImporter.java @@ -249,9 +249,11 @@ private static void createShuntCompensator(IeeeCdfBus ieeeCdfBus, PerUnitContext .setId(busId + "-SH") .setConnectableBus(busId) .setBus(busId) - .setbPerSection(ieeeCdfBus.getShuntSusceptance() / zb) .setCurrentSectionCount(1) - .setMaximumSectionCount(1) + .newLinearModel() + .setMaximumSectionCount(1) + .setbPerSection(ieeeCdfBus.getShuntSusceptance() / zb) + .add() .add(); } } diff --git a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensator.java b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensator.java index 80a0be9979..1a41d276fb 100644 --- a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensator.java +++ b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensator.java @@ -16,19 +16,6 @@ */ public interface ShuntCompensator extends Injection { - /** - * Get the maximum section count. - */ - int getMaximumSectionCount(); - - /** - * Set the maximum number of section. - * - * @param maximumSectionCount the maximum number of section - * @return the shunt compensator to chain method calls. - */ - ShuntCompensator setMaximumSectionCount(int maximumSectionCount); - /** * Get the current section count. *

@@ -40,6 +27,11 @@ public interface ShuntCompensator extends Injection { */ int getCurrentSectionCount(); + /** + * Get the maximum number of sections. + */ + int getMaximumSectionCount(); + /** * Change the number of section. * @@ -53,35 +45,32 @@ public interface ShuntCompensator extends Injection { ShuntCompensator setCurrentSectionCount(int currentSectionCount); /** - * Get the susceptance per section in S. + * Get the susceptance for the current section count. + *

+ * Depends on the working variant. + * @see VariantManager */ - double getbPerSection(); + double getCurrentB(); /** - * Set the susceptance per section in S. - * - * @param bPerSection the susceptance per section - * @return the shunt compensator to chain method calls. + * Get the conductance for the current section count. + *

+ * Depends on the working variant. + * @see VariantManager */ - ShuntCompensator setbPerSection(double bPerSection); + double getCurrentG(); /** - * Get the susceptance for the maximum section count. - * - * @deprecated Use {@link #getbPerSection()} * {@link #getMaximumSectionCount()} instead. + * Get the model type of the shunt compensator (linear or non-linear) */ - @Deprecated - default double getMaximumB() { - return getbPerSection() * getMaximumSectionCount(); - } + ShuntCompensatorModelType getModelType(); /** - * Get the susceptance for the current section counts. - *

- * Depends on the working variant. - * @see VariantManager + * Get the shunt model. */ - double getCurrentB(); + ShuntCompensatorModel getModel(); + + M getModel(Class modelType); /** * Get the terminal used for regulation. diff --git a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorAdder.java b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorAdder.java index ca8eff070e..d5312c36aa 100644 --- a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorAdder.java +++ b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorAdder.java @@ -26,9 +26,9 @@ */ public interface ShuntCompensatorAdder extends InjectionAdder { - ShuntCompensatorAdder setbPerSection(double bPerSection); + ShuntCompensatorLinearModelAdder newLinearModel(); - ShuntCompensatorAdder setMaximumSectionCount(int maximumSectionCount); + ShuntCompensatorNonLinearModelAdder newNonLinearModel(); ShuntCompensatorAdder setCurrentSectionCount(int currentSectionCount); diff --git a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorLinearModel.java b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorLinearModel.java new file mode 100644 index 0000000000..b02bce5004 --- /dev/null +++ b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorLinearModel.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2020, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package com.powsybl.iidm.network; + +/** + * @author Miora Ralambotiana + */ +public interface ShuntCompensatorLinearModel extends ShuntCompensatorModel { + + /** + * Get the susceptance per section in S. + */ + double getbPerSection(); + + /** + * Set the susceptance per section in S. + */ + ShuntCompensatorLinearModel setbPerSection(double bPerSection); + + /** + * Get the conductance per section in S. + */ + double getgPerSection(); + + /** + * Set the conductance per section in S. + */ + ShuntCompensatorLinearModel setgPerSection(double gPerSection); + + /** + * Set the maximum number of sections. + */ + ShuntCompensatorLinearModel setMaximumSectionCount(int maximumSectionCount); +} diff --git a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorLinearModelAdder.java b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorLinearModelAdder.java new file mode 100644 index 0000000000..eeaa78433f --- /dev/null +++ b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorLinearModelAdder.java @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2020, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package com.powsybl.iidm.network; + +/** + * @author Miora Ralambotiana + */ +public interface ShuntCompensatorLinearModelAdder { + + ShuntCompensatorLinearModelAdder setbPerSection(double bPerSection); + + ShuntCompensatorLinearModelAdder setgPerSection(double gPerSection); + + ShuntCompensatorLinearModelAdder setMaximumSectionCount(int maximumSectionCount); + + ShuntCompensatorAdder add(); +} diff --git a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorModel.java b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorModel.java new file mode 100644 index 0000000000..2865795544 --- /dev/null +++ b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorModel.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2020, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package com.powsybl.iidm.network; + +/** + * @author Miora Ralambotiana + */ +public interface ShuntCompensatorModel { + + /** + * Get the susceptance in S of the section with a given section number if it exists. + * Throw an exception if such a section does not exist. + */ + double getB(int sectionNum); + + /** + * Get the conductance in S of the section with a given section number if it exists. + * Throw an exception if such a section does not exist. + */ + double getG(int sectionNum); +} diff --git a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorModelType.java b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorModelType.java new file mode 100644 index 0000000000..9b9ef563e5 --- /dev/null +++ b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorModelType.java @@ -0,0 +1,15 @@ +/** + * Copyright (c) 2020, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package com.powsybl.iidm.network; + +/** + * @author Miora Ralambotiana + */ +public enum ShuntCompensatorModelType { + LINEAR, + NON_LINEAR +} diff --git a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorNonLinearModel.java b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorNonLinearModel.java new file mode 100644 index 0000000000..a0f8ac691c --- /dev/null +++ b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorNonLinearModel.java @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2020, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package com.powsybl.iidm.network; + +import java.util.Map; +import java.util.Optional; + +/** + * @author Miora Ralambotiana + */ +public interface ShuntCompensatorNonLinearModel extends ShuntCompensatorModel { + + interface Section { + + /** + * Get the susceptance in S of the section. + */ + double getB(); + + /** + * Get the conductance in S of the section. + */ + double getG(); + } + + /** + * Get the maximum susceptance for a section in S. + */ + double getMaximumB(); + + /** + * Get the maximum conductance for a section in S. + */ + double getMaximumG(); + + /** + * Get an optional of the section associated with a given section number if it exists. + * If such a section does not exist, return an empty optional. + * + */ + Optional

getSection(int sectionNum); + + /** + * Get all the sections associated with their section number. + */ + Map getSections(); + + /** + * For a given section number, add a section with a given susceptance and conductance in S to the model. + * If a section already exists for this section number, respectively replace its susceptance and conductance with the given susceptance and conductance. + */ + ShuntCompensatorNonLinearModel addOrReplaceSection(int sectionNum, double b, double g); + + /** + * Remove the section associated with a given section number if it exists and the current section count is different of the given section number. + * Else, throw an exception. + */ + ShuntCompensatorNonLinearModel removeSection(int sectionNum); +} diff --git a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorNonLinearModelAdder.java b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorNonLinearModelAdder.java new file mode 100644 index 0000000000..031c8c5679 --- /dev/null +++ b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ShuntCompensatorNonLinearModelAdder.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2020, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package com.powsybl.iidm.network; + +/** + * @author Miora Ralambotiana + */ +public interface ShuntCompensatorNonLinearModelAdder { + + interface SectionAdder { + + SectionAdder setSectionNum(int sectionNum); + + SectionAdder setB(double b); + + SectionAdder setG(double g); + + ShuntCompensatorNonLinearModelAdder endSection(); + } + + SectionAdder beginSection(); + + ShuntCompensatorAdder add(); +} diff --git a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ValidationUtil.java b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ValidationUtil.java index c61c1684b0..f8a160a635 100644 --- a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ValidationUtil.java +++ b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/ValidationUtil.java @@ -228,26 +228,42 @@ public static void checkForecastDistance(Validable validable, int forecastDistan } } - public static void checkbPerSection(Validable validable, double bPerSection) { - if (Double.isNaN(bPerSection)) { - throw new ValidationException(validable, "susceptance per section is invalid"); + public static void checkSectionNumber(Validable validable, int sectionNum) { + if (sectionNum < 0) { + throw new ValidationException(validable, + "this number of section (" + sectionNum + + ") should be greater than or equal to 0"); } + } + + public static void checkbPerSection(Validable validable, double bPerSection) { + checkSectionB(validable, bPerSection); if (bPerSection == 0) { throw new ValidationException(validable, "susceptance per section is equal to zero"); } } + public static void checkSectionB(Validable validable, double sectionB) { + if (Double.isNaN(sectionB)) { + throw new ValidationException(validable, "section susceptance is invalid"); + } + } + + public static void checkMaximumSectionCount(Validable validable, int maximumSectionCount) { + if (maximumSectionCount <= 0) { + throw new ValidationException(validable, + "the maximum number of section (" + maximumSectionCount + + ") should be greater than 0"); + } + } + public static void checkSections(Validable validable, int currentSectionCount, int maximumSectionCount) { if (currentSectionCount < 0) { throw new ValidationException(validable, "the current number of section (" + currentSectionCount + ") should be greater than or equal to 0"); } - if (maximumSectionCount <= 0) { - throw new ValidationException(validable, - "the maximum number of section (" + maximumSectionCount - + ")should be greater than 0"); - } + checkMaximumSectionCount(validable, maximumSectionCount); if (currentSectionCount > maximumSectionCount) { throw new ValidationException(validable, "the current number (" + currentSectionCount @@ -310,7 +326,7 @@ public static void checkBmax(Validable validable, double bMax) { } public static void checkRatioTapChangerRegulation(Validable validable, boolean regulating, - Terminal regulationTerminal, double targetV, Network network) { + Terminal regulationTerminal, double targetV, Network network) { if (regulating) { if (Double.isNaN(targetV)) { throw new ValidationException(validable, @@ -330,8 +346,8 @@ public static void checkRatioTapChangerRegulation(Validable validable, boolean r } public static void checkPhaseTapChangerRegulation(Validable validable, PhaseTapChanger.RegulationMode regulationMode, - double regulationValue, boolean regulating, Terminal regulationTerminal, - Network network) { + double regulationValue, boolean regulating, Terminal regulationTerminal, + Network network) { if (regulationMode == null) { throw new ValidationException(validable, "phase regulation mode is not set"); } @@ -350,7 +366,7 @@ public static void checkPhaseTapChangerRegulation(Validable validable, PhaseTapC } public static void checkOnlyOneTapChangerRegulatingEnabled(Validable validable, - Set tapChangersNotIncludingTheModified, boolean regulating) { + Set tapChangersNotIncludingTheModified, boolean regulating) { if (regulating && tapChangersNotIncludingTheModified.stream().anyMatch(TapChanger::isRegulating)) { throw new ValidationException(validable, "Only one regulating control enabled is allowed"); } diff --git a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/AbstractShuntCompensatorModel.java b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/AbstractShuntCompensatorModel.java new file mode 100644 index 0000000000..2f289340a9 --- /dev/null +++ b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/AbstractShuntCompensatorModel.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2020, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package com.powsybl.iidm.network.impl; + +import com.powsybl.commons.PowsyblException; + +import java.util.Objects; + +/** + * @author Miora Ralambotiana + */ +abstract class AbstractShuntCompensatorModel implements ShuntCompensatorModelWrapper { + + protected ShuntCompensatorImpl shuntCompensator; + + @Override + public void setShuntCompensator(ShuntCompensatorImpl shuntCompensator) { + if (this.shuntCompensator != null) { + throw new PowsyblException("Owner (shunt compensator) already defined"); + } + this.shuntCompensator = Objects.requireNonNull(shuntCompensator); + } +} diff --git a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/ShuntCompensatorAdderImpl.java b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/ShuntCompensatorAdderImpl.java index 10a17d4f97..261f592e4b 100644 --- a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/ShuntCompensatorAdderImpl.java +++ b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/ShuntCompensatorAdderImpl.java @@ -6,23 +6,20 @@ */ package com.powsybl.iidm.network.impl; -import com.powsybl.iidm.network.ShuntCompensatorAdder; -import com.powsybl.iidm.network.ValidationUtil; -import com.powsybl.iidm.network.Terminal; +import com.powsybl.iidm.network.*; + +import java.util.TreeMap; /** - * * @author Geoffroy Jamgotchian */ class ShuntCompensatorAdderImpl extends AbstractInjectionAdder implements ShuntCompensatorAdder { private final VoltageLevelExt voltageLevel; - private double bPerSection; - - private int maximumSectionCount; + private ShuntCompensatorModelWrapper model; - private int currentSectionCount; + private int currentSectionCount = -1; private double targetV = Double.NaN; @@ -46,16 +43,106 @@ protected String getTypeDescription() { return "Shunt compensator"; } + class ShuntCompensatorLinearModelAdderImpl implements ShuntCompensatorLinearModelAdder { + + private double bPerSection = Double.NaN; + + private double gPerSection = Double.NaN; + + private int maximumSectionCount = -1; + + @Override + public ShuntCompensatorLinearModelAdder setbPerSection(double bPerSection) { + this.bPerSection = bPerSection; + return this; + } + + @Override + public ShuntCompensatorLinearModelAdder setgPerSection(double gPerSection) { + this.gPerSection = gPerSection; + return this; + } + + @Override + public ShuntCompensatorLinearModelAdder setMaximumSectionCount(int maximumSectionCount) { + this.maximumSectionCount = maximumSectionCount; + return this; + } + + @Override + public ShuntCompensatorAdder add() { + ValidationUtil.checkbPerSection(ShuntCompensatorAdderImpl.this, bPerSection); + ValidationUtil.checkMaximumSectionCount(ShuntCompensatorAdderImpl.this, maximumSectionCount); + model = new ShuntCompensatorLinearModelImpl(bPerSection, gPerSection, maximumSectionCount); + return ShuntCompensatorAdderImpl.this; + } + } + + class ShuntCompensatorNonLinearModelAdderImpl implements ShuntCompensatorNonLinearModelAdder { + + private final TreeMap sections = new TreeMap<>(); + + class SectionAdderImpl implements SectionAdder { + + private int sectionNum = -1; + + private double b = Double.NaN; + + private double g = Double.NaN; + + @Override + public SectionAdder setSectionNum(int sectionNum) { + this.sectionNum = sectionNum; + return this; + } + + @Override + public SectionAdder setB(double b) { + this.b = b; + return this; + } + + @Override + public SectionAdder setG(double g) { + this.g = g; + return this; + } + + @Override + public ShuntCompensatorNonLinearModelAdder endSection() { + ValidationUtil.checkSectionNumber(ShuntCompensatorAdderImpl.this, sectionNum); + if (sections.containsKey(sectionNum)) { + throw new ValidationException(ShuntCompensatorAdderImpl.this, "a section is already defined at this number"); + } + ValidationUtil.checkSectionB(ShuntCompensatorAdderImpl.this, b); + sections.put(sectionNum, new ShuntCompensatorNonLinearModelImpl.SectionImpl(b, g)); + return ShuntCompensatorNonLinearModelAdderImpl.this; + } + } + + @Override + public SectionAdder beginSection() { + return new SectionAdderImpl(); + } + + @Override + public ShuntCompensatorAdder add() { + if (sections.isEmpty()) { + throw new ValidationException(ShuntCompensatorAdderImpl.this, "a shunt compensator must have at least one section"); + } + model = new ShuntCompensatorNonLinearModelImpl(sections); + return ShuntCompensatorAdderImpl.this; + } + } + @Override - public ShuntCompensatorAdder setbPerSection(double bPerSection) { - this.bPerSection = bPerSection; - return this; + public ShuntCompensatorLinearModelAdder newLinearModel() { + return new ShuntCompensatorLinearModelAdderImpl(); } @Override - public ShuntCompensatorAdder setMaximumSectionCount(int maximumSectionCount) { - this.maximumSectionCount = maximumSectionCount; - return this; + public ShuntCompensatorNonLinearModelAdder newNonLinearModel() { + return new ShuntCompensatorNonLinearModelAdderImpl(); } @Override @@ -92,14 +179,19 @@ public ShuntCompensatorAdder setTargetDeadband(double targetDeadband) { public ShuntCompensatorImpl add() { String id = checkAndGetUniqueId(); TerminalExt terminal = checkAndGetTerminal(); - ValidationUtil.checkbPerSection(this, bPerSection); - ValidationUtil.checkSections(this, currentSectionCount, maximumSectionCount); + if (model == null) { + throw new ValidationException(this, "the shunt compensator model has not been defined"); + } + ValidationUtil.checkSections(this, currentSectionCount, model.getMaximumSectionCount()); + if (!model.containsSection(currentSectionCount)) { + throw new ValidationException(this, "unexpected section number (" + currentSectionCount + "): no existing associated section"); + } ValidationUtil.checkRegulatingTerminal(this, regulatingTerminal, getNetwork()); ValidationUtil.checkVoltageControl(this, voltageRegulatorOn, targetV); ValidationUtil.checkTargetDeadband(this, "shunt compensator", voltageRegulatorOn, targetDeadband); ShuntCompensatorImpl shunt = new ShuntCompensatorImpl(getNetwork().getRef(), - id, getName(), isFictitious(), bPerSection, maximumSectionCount, + id, getName(), isFictitious(), model, currentSectionCount, regulatingTerminal == null ? terminal : regulatingTerminal, voltageRegulatorOn, targetV, targetDeadband); shunt.addTerminal(terminal); diff --git a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/ShuntCompensatorImpl.java b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/ShuntCompensatorImpl.java index e6f7e69569..334b87e345 100644 --- a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/ShuntCompensatorImpl.java +++ b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/ShuntCompensatorImpl.java @@ -7,27 +7,19 @@ package com.powsybl.iidm.network.impl; import com.powsybl.commons.util.trove.TBooleanArrayList; -import com.powsybl.iidm.network.ConnectableType; -import com.powsybl.iidm.network.ShuntCompensator; -import com.powsybl.iidm.network.ValidationUtil; -import com.powsybl.iidm.network.Terminal; +import com.powsybl.iidm.network.*; import com.powsybl.iidm.network.impl.util.Ref; import gnu.trove.list.array.TDoubleArrayList; import gnu.trove.list.array.TIntArrayList; /** - * * @author Geoffroy Jamgotchian */ class ShuntCompensatorImpl extends AbstractConnectable implements ShuntCompensator { private final Ref network; - /* susceptance per section */ - private double bPerSection; - - /* the maximum number of section */ - private int maximumSectionCount; + private final ShuntCompensatorModelWrapper model; /* the regulating terminal */ private TerminalExt regulatingTerminal; @@ -47,13 +39,12 @@ class ShuntCompensatorImpl extends AbstractConnectable impleme private final TDoubleArrayList targetDeadband; ShuntCompensatorImpl(Ref network, - String id, String name, boolean fictitious, double bPerSection, int maximumSectionCount, + String id, String name, boolean fictitious, ShuntCompensatorModelWrapper model, int currentSectionCount, TerminalExt regulatingTerminal, boolean voltageRegulatorOn, double targetV, double targetDeadband) { super(id, name, fictitious); this.network = network; - this.bPerSection = bPerSection; - this.maximumSectionCount = maximumSectionCount; + this.model = attach(model); this.regulatingTerminal = regulatingTerminal; int variantArraySize = network.get().getVariantManager().getVariantArraySize(); this.currentSectionCount = new TIntArrayList(variantArraySize); @@ -68,6 +59,11 @@ class ShuntCompensatorImpl extends AbstractConnectable impleme } } + private ShuntCompensatorModelWrapper attach(ShuntCompensatorModelWrapper model) { + model.setShuntCompensator(this); + return model; + } + @Override public ConnectableType getType() { return ConnectableType.SHUNT_COMPENSATOR; @@ -79,51 +75,58 @@ public TerminalExt getTerminal() { } @Override - public double getbPerSection() { - return bPerSection; + public int getCurrentSectionCount() { + return currentSectionCount.get(network.get().getVariantIndex()); } @Override - public ShuntCompensatorImpl setbPerSection(double bPerSection) { - ValidationUtil.checkbPerSection(this, bPerSection); - double oldValue = this.bPerSection; - this.bPerSection = bPerSection; - notifyUpdate("bPerSection", oldValue, bPerSection); + public int getMaximumSectionCount() { + return model.getMaximumSectionCount(); + } + + @Override + public ShuntCompensatorImpl setCurrentSectionCount(int currentSectionCount) { + ValidationUtil.checkSections(this, currentSectionCount, model.getMaximumSectionCount()); + if (!model.containsSection(currentSectionCount)) { + throw new ValidationException(this, "unexpected section number (" + currentSectionCount + "): no existing associated section"); + } + int variantIndex = network.get().getVariantIndex(); + int oldValue = this.currentSectionCount.set(variantIndex, currentSectionCount); + String variantId = network.get().getVariantManager().getVariantId(variantIndex); + notifyUpdate("currentSectionCount", variantId, oldValue, currentSectionCount); return this; } @Override - public int getMaximumSectionCount() { - return maximumSectionCount; + public double getCurrentB() { + return model.getB(currentSectionCount.get(network.get().getVariantIndex())); } @Override - public ShuntCompensatorImpl setMaximumSectionCount(int maximumSectionCount) { - ValidationUtil.checkSections(this, getCurrentSectionCount(), maximumSectionCount); - int oldValue = this.maximumSectionCount; - this.maximumSectionCount = maximumSectionCount; - notifyUpdate("maximumSectionCount", oldValue, maximumSectionCount); - return this; + public double getCurrentG() { + return model.getG(currentSectionCount.get(network.get().getVariantIndex())); } @Override - public int getCurrentSectionCount() { - return currentSectionCount.get(network.get().getVariantIndex()); + public ShuntCompensatorModelType getModelType() { + return model.getType(); } @Override - public ShuntCompensatorImpl setCurrentSectionCount(int currentSectionCount) { - ValidationUtil.checkSections(this, currentSectionCount, maximumSectionCount); - int variantIndex = network.get().getVariantIndex(); - int oldValue = this.currentSectionCount.set(variantIndex, currentSectionCount); - String variantId = network.get().getVariantManager().getVariantId(variantIndex); - notifyUpdate("currentSectionCount", variantId, oldValue, currentSectionCount); - return this; + public ShuntCompensatorModel getModel() { + return model; } @Override - public double getCurrentB() { - return bPerSection * getCurrentSectionCount(); + public M getModel(Class modelType) { + if (modelType == null) { + throw new IllegalArgumentException("shunt compensator model type is null"); + } + if (modelType.isInstance(model)) { + return modelType.cast(model); + } + throw new ValidationException(this, "incorrect shunt compensator model type " + + modelType.getName() + ", expected " + model.getClass()); } @Override diff --git a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/ShuntCompensatorLinearModelImpl.java b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/ShuntCompensatorLinearModelImpl.java new file mode 100644 index 0000000000..d39995205c --- /dev/null +++ b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/ShuntCompensatorLinearModelImpl.java @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2020, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package com.powsybl.iidm.network.impl; + +import com.powsybl.iidm.network.ShuntCompensatorLinearModel; +import com.powsybl.iidm.network.ShuntCompensatorModelType; +import com.powsybl.iidm.network.ValidationUtil; + +/** + * @author Miora Ralambotiana + */ +class ShuntCompensatorLinearModelImpl extends AbstractShuntCompensatorModel implements ShuntCompensatorLinearModel { + + private double bPerSection; + + private double gPerSection; + + private int maximumSectionCount; + + ShuntCompensatorLinearModelImpl(double bPerSection, double gPerSection, int maximumSectionCount) { + this.bPerSection = bPerSection; + this.gPerSection = gPerSection; + this.maximumSectionCount = maximumSectionCount; + } + + @Override + public double getbPerSection() { + return bPerSection; + } + + @Override + public ShuntCompensatorLinearModel setbPerSection(double bPerSection) { + ValidationUtil.checkbPerSection(shuntCompensator, bPerSection); + double oldValue = this.bPerSection; + this.bPerSection = bPerSection; + shuntCompensator.notifyUpdate("bPerSection", oldValue, bPerSection); + return this; + } + + @Override + public double getgPerSection() { + return gPerSection; + } + + @Override + public ShuntCompensatorLinearModel setgPerSection(double gPerSection) { + double oldValue = this.gPerSection; + this.gPerSection = gPerSection; + shuntCompensator.notifyUpdate("gPerSection", oldValue, gPerSection); + return this; + } + + @Override + public int getMaximumSectionCount() { + return maximumSectionCount; + } + + @Override + public ShuntCompensatorLinearModel setMaximumSectionCount(int maximumSectionCount) { + ValidationUtil.checkSections(shuntCompensator, shuntCompensator.getCurrentSectionCount(), maximumSectionCount); + int oldValue = this.maximumSectionCount; + this.maximumSectionCount = maximumSectionCount; + shuntCompensator.notifyUpdate("maximumSectionCount", oldValue, maximumSectionCount); + return this; + } + + @Override + public ShuntCompensatorModelType getType() { + return ShuntCompensatorModelType.LINEAR; + } + + @Override + public boolean containsSection(int sectionNumber) { + return sectionNumber >= 0 && sectionNumber <= maximumSectionCount; + } + + @Override + public double getB(int sectionNum) { + return bPerSection * sectionNum; + } + + @Override + public double getG(int sectionNum) { + return gPerSection * sectionNum; + } +} diff --git a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/ShuntCompensatorModelWrapper.java b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/ShuntCompensatorModelWrapper.java new file mode 100644 index 0000000000..6bb98f387b --- /dev/null +++ b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/ShuntCompensatorModelWrapper.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2020, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package com.powsybl.iidm.network.impl; + +import com.powsybl.iidm.network.ShuntCompensatorModel; +import com.powsybl.iidm.network.ShuntCompensatorModelType; + +/** + * @author Miora Ralambotiana + */ +interface ShuntCompensatorModelWrapper extends ShuntCompensatorModel { + + ShuntCompensatorModelType getType(); + + void setShuntCompensator(ShuntCompensatorImpl owner); + + boolean containsSection(int sectionNumber); + + int getMaximumSectionCount(); +} diff --git a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/ShuntCompensatorNonLinearModelImpl.java b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/ShuntCompensatorNonLinearModelImpl.java new file mode 100644 index 0000000000..5fca506c08 --- /dev/null +++ b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/ShuntCompensatorNonLinearModelImpl.java @@ -0,0 +1,139 @@ +/** + * Copyright (c) 2020, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package com.powsybl.iidm.network.impl; + +import com.powsybl.commons.PowsyblException; +import com.powsybl.iidm.network.*; + +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.TreeMap; + +/** + * @author Miora Ralambotiana + */ +class ShuntCompensatorNonLinearModelImpl extends AbstractShuntCompensatorModel implements ShuntCompensatorNonLinearModel { + + static class SectionImpl implements Section { + + private final double b; + + private final double g; + + SectionImpl(double b, double g) { + this.b = b; + this.g = g; + } + + @Override + public double getB() { + return b; + } + + @Override + public double getG() { + return g; + } + } + + private final TreeMap sections; + + ShuntCompensatorNonLinearModelImpl(TreeMap sections) { + this.sections = sections; + } + + @Override + public double getMaximumB() { + return sections.values().stream() + .map(SectionImpl::getB) + .max(Double::compare) + .orElseThrow(() -> new PowsyblException("a shunt compensator must have at least one section")); + } + + @Override + public double getMaximumG() { + return sections.values().stream() + .map(SectionImpl::getG) + .filter(g -> !Double.isNaN(g)) + .max(Double::compare) + .orElse(Double.NaN); + } + + @Override + public Optional
getSection(int sectionNum) { + ValidationUtil.checkSectionNumber(shuntCompensator, sectionNum); + return Optional.ofNullable(sections.get(sectionNum)); + } + + @Override + public Map getSections() { + return Collections.unmodifiableMap(sections); + } + + @Override + public ShuntCompensatorNonLinearModel addOrReplaceSection(int sectionNum, double b, double g) { + ValidationUtil.checkSectionNumber(shuntCompensator, sectionNum); + ValidationUtil.checkSectionB(shuntCompensator, b); + SectionImpl oldValue = sections.put(sectionNum, new SectionImpl(b, g)); + shuntCompensator.notifyUpdate(notifyUpdateSection(sectionNum, "b"), Optional.ofNullable(oldValue).map(SectionImpl::getB).orElse(Double.NaN), b); + shuntCompensator.notifyUpdate(notifyUpdateSection(sectionNum, "g"), Optional.ofNullable(oldValue).map(SectionImpl::getG).orElse(Double.NaN), g); + return this; + } + + @Override + public ShuntCompensatorNonLinearModel removeSection(int sectionNum) { + ValidationUtil.checkSectionNumber(shuntCompensator, sectionNum); + if (shuntCompensator.getCurrentSectionCount() == sectionNum) { + throw new ValidationException(shuntCompensator, "the number of section to remove (" + sectionNum + ") is the current section count"); + } + if (!sections.containsKey(sectionNum)) { + throw new ValidationException(shuntCompensator, invalidSectionNumberMessage(sectionNum, "susceptance nor conductance")); + } + SectionImpl oldValue = sections.remove(sectionNum); + shuntCompensator.notifyUpdate(notifyUpdateSection(sectionNum, "b"), oldValue.getB(), Double.NaN); + shuntCompensator.notifyUpdate(notifyUpdateSection(sectionNum, "g"), oldValue.getG(), Double.NaN); + return null; + } + + @Override + public ShuntCompensatorModelType getType() { + return ShuntCompensatorModelType.NON_LINEAR; + } + + @Override + public boolean containsSection(int sectionNumber) { + return sections.containsKey(sectionNumber); + } + + @Override + public int getMaximumSectionCount() { + return sections.lastKey(); + } + + @Override + public double getB(int sectionNum) { + return Optional.ofNullable(sections.get(sectionNum)) + .map(SectionImpl::getB) + .orElseThrow(() -> new PowsyblException(invalidSectionNumberMessage(sectionNum, "susceptance"))); + } + + @Override + public double getG(int sectionNum) { + return Optional.ofNullable(sections.get(sectionNum)) + .map(SectionImpl::getG) + .orElseThrow(() -> new PowsyblException(invalidSectionNumberMessage(sectionNum, "conductance"))); + } + + private static String invalidSectionNumberMessage(int sectionNum, String attributes) { + return "the given number of section (" + sectionNum + ") is not associated with any " + attributes; + } + + private static String notifyUpdateSection(int sectionNum, String attribute) { + return "section" + sectionNum + "." + attribute; + } +} diff --git a/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/ShuntCompensatorAdapter.java b/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/ShuntCompensatorAdapter.java index 4bf4eb2d97..3f793dda21 100644 --- a/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/ShuntCompensatorAdapter.java +++ b/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/ShuntCompensatorAdapter.java @@ -7,6 +7,8 @@ package com.powsybl.iidm.mergingview; import com.powsybl.iidm.network.ShuntCompensator; +import com.powsybl.iidm.network.ShuntCompensatorModel; +import com.powsybl.iidm.network.ShuntCompensatorModelType; import com.powsybl.iidm.network.Terminal; /** @@ -21,42 +23,45 @@ public class ShuntCompensatorAdapter extends AbstractInjectionAdapter M getModel(Class modelType) { + return getDelegate().getModel(modelType); } @Override diff --git a/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/ShuntCompensatorAdderAdapter.java b/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/ShuntCompensatorAdderAdapter.java index 6d63c13d9a..70ea0b4779 100644 --- a/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/ShuntCompensatorAdderAdapter.java +++ b/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/ShuntCompensatorAdderAdapter.java @@ -6,8 +6,7 @@ */ package com.powsybl.iidm.mergingview; -import com.powsybl.iidm.network.ShuntCompensator; -import com.powsybl.iidm.network.ShuntCompensatorAdder; +import com.powsybl.iidm.network.*; /** * @author Thomas Adam @@ -24,24 +23,50 @@ public ShuntCompensator add() { return getIndex().getShuntCompensator(getDelegate().add()); } + @Override + public ShuntCompensatorAdder setRegulatingTerminal(Terminal regulatingTerminal) { + Terminal terminal = regulatingTerminal; + if (terminal instanceof TerminalAdapter) { + terminal = ((TerminalAdapter) terminal).getDelegate(); + } + getDelegate().setRegulatingTerminal(terminal); + return this; + } + + @Override + public ShuntCompensatorLinearModelAdder newLinearModel() { + return new ShuntCompensatorLinearModelAdderAdapter(getDelegate().newLinearModel(), this); + } + + @Override + public ShuntCompensatorNonLinearModelAdder newNonLinearModel() { + return new ShuntCompensatorNonLinearModelAdderAdapter(getDelegate().newNonLinearModel(), this); + } + // ------------------------------- // Simple delegated methods ------ // ------------------------------- @Override - public ShuntCompensatorAdder setbPerSection(final double bPerSection) { - getDelegate().setbPerSection(bPerSection); + public ShuntCompensatorAdder setCurrentSectionCount(final int currentSectionCount) { + getDelegate().setCurrentSectionCount(currentSectionCount); return this; } @Override - public ShuntCompensatorAdder setMaximumSectionCount(final int maximumSectionCount) { - getDelegate().setMaximumSectionCount(maximumSectionCount); + public ShuntCompensatorAdder setVoltageRegulatorOn(boolean voltageRegulatorOn) { + getDelegate().setVoltageRegulatorOn(voltageRegulatorOn); return this; } @Override - public ShuntCompensatorAdder setCurrentSectionCount(final int currentSectionCount) { - getDelegate().setCurrentSectionCount(currentSectionCount); + public ShuntCompensatorAdder setTargetV(double targetV) { + getDelegate().setTargetV(targetV); + return this; + } + + @Override + public ShuntCompensatorAdder setTargetDeadband(double targetDeadband) { + getDelegate().setTargetDeadband(targetDeadband); return this; } } diff --git a/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/ShuntCompensatorLinearModelAdderAdapter.java b/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/ShuntCompensatorLinearModelAdderAdapter.java new file mode 100644 index 0000000000..654e6fbfb5 --- /dev/null +++ b/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/ShuntCompensatorLinearModelAdderAdapter.java @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2020, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package com.powsybl.iidm.mergingview; + +import com.powsybl.iidm.network.ShuntCompensatorAdder; +import com.powsybl.iidm.network.ShuntCompensatorLinearModelAdder; + +import java.util.Objects; + +/** + * @author Miora Ralambotiana + */ +public class ShuntCompensatorLinearModelAdderAdapter implements ShuntCompensatorLinearModelAdder { + + private final ShuntCompensatorLinearModelAdder delegate; + private final ShuntCompensatorAdderAdapter parent; + + ShuntCompensatorLinearModelAdderAdapter(final ShuntCompensatorLinearModelAdder delegate, ShuntCompensatorAdderAdapter parent) { + this.delegate = Objects.requireNonNull(delegate); + this.parent = Objects.requireNonNull(parent); + } + + @Override + public ShuntCompensatorLinearModelAdder setbPerSection(double bPerSection) { + delegate.setbPerSection(bPerSection); + return this; + } + + @Override + public ShuntCompensatorLinearModelAdder setgPerSection(double gPerSection) { + delegate.setgPerSection(gPerSection); + return this; + } + + @Override + public ShuntCompensatorLinearModelAdder setMaximumSectionCount(int maximumSectionCount) { + delegate.setMaximumSectionCount(maximumSectionCount); + return this; + } + + @Override + public ShuntCompensatorAdder add() { + delegate.add(); + return parent; + } +} diff --git a/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/ShuntCompensatorNonLinearModelAdderAdapter.java b/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/ShuntCompensatorNonLinearModelAdderAdapter.java new file mode 100644 index 0000000000..a5e9cb1b0c --- /dev/null +++ b/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/ShuntCompensatorNonLinearModelAdderAdapter.java @@ -0,0 +1,72 @@ +/** + * Copyright (c) 2020, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package com.powsybl.iidm.mergingview; + +import com.powsybl.iidm.network.ShuntCompensatorAdder; +import com.powsybl.iidm.network.ShuntCompensatorNonLinearModelAdder; + +import java.util.Objects; + +/** + * @author Miora Ralambotiana + */ +public class ShuntCompensatorNonLinearModelAdderAdapter implements ShuntCompensatorNonLinearModelAdder { + + private final ShuntCompensatorNonLinearModelAdder delegate; + private final ShuntCompensatorAdderAdapter parent; + + ShuntCompensatorNonLinearModelAdderAdapter(final ShuntCompensatorNonLinearModelAdder delegate, ShuntCompensatorAdderAdapter parent) { + this.delegate = Objects.requireNonNull(delegate); + this.parent = Objects.requireNonNull(parent); + } + + class SectionAdderAdapter implements SectionAdder { + + private final SectionAdder delegate; + private final ShuntCompensatorNonLinearModelAdderAdapter parent; + + SectionAdderAdapter(final SectionAdder delegate, ShuntCompensatorNonLinearModelAdderAdapter parent) { + this.delegate = Objects.requireNonNull(delegate); + this.parent = Objects.requireNonNull(parent); + } + + @Override + public SectionAdder setSectionNum(int sectionNum) { + delegate.setSectionNum(sectionNum); + return this; + } + + @Override + public SectionAdder setB(double b) { + delegate.setB(b); + return this; + } + + @Override + public SectionAdder setG(double g) { + delegate.setG(g); + return this; + } + + @Override + public ShuntCompensatorNonLinearModelAdder endSection() { + delegate.endSection(); + return parent; + } + } + + @Override + public SectionAdder beginSection() { + return new SectionAdderAdapter(delegate.beginSection(), this); + } + + @Override + public ShuntCompensatorAdder add() { + delegate.add(); + return parent; + } +} diff --git a/iidm/iidm-mergingview/src/test/java/com/powsybl/iidm/mergingview/ShuntCompensatorAdapterTest.java b/iidm/iidm-mergingview/src/test/java/com/powsybl/iidm/mergingview/ShuntCompensatorAdapterTest.java index 97ea2bf8f6..83b9ed4d99 100644 --- a/iidm/iidm-mergingview/src/test/java/com/powsybl/iidm/mergingview/ShuntCompensatorAdapterTest.java +++ b/iidm/iidm-mergingview/src/test/java/com/powsybl/iidm/mergingview/ShuntCompensatorAdapterTest.java @@ -6,9 +6,8 @@ */ package com.powsybl.iidm.mergingview; -import com.powsybl.iidm.network.Network; -import com.powsybl.iidm.network.ShuntCompensator; -import com.powsybl.iidm.network.Terminal; +import com.powsybl.iidm.network.*; +import com.powsybl.iidm.network.test.EurostagTutorialExample1Factory; import com.powsybl.iidm.network.test.HvdcTestNetwork; import org.junit.Before; import org.junit.Test; @@ -45,23 +44,20 @@ public void testSetterGetter() { }); int maxCount = shuntCExpected.getMaximumSectionCount(); - assertEquals(maxCount, shuntCActual.getMaximumSectionCount()); - assertTrue(shuntCActual.setMaximumSectionCount(++maxCount) instanceof ShuntCompensatorAdapter); - assertEquals(maxCount, shuntCActual.getMaximumSectionCount()); - + shuntCActual.getModel(ShuntCompensatorLinearModel.class).setMaximumSectionCount(++maxCount); int currentCount = shuntCExpected.getCurrentSectionCount(); assertEquals(currentCount, shuntCActual.getCurrentSectionCount()); assertTrue(shuntCActual.setCurrentSectionCount(++currentCount) instanceof ShuntCompensatorAdapter); assertEquals(currentCount, shuntCActual.getCurrentSectionCount()); - double b = shuntCExpected.getbPerSection(); - assertEquals(b, shuntCActual.getbPerSection(), 0.0d); - assertTrue(shuntCActual.setbPerSection(++b) instanceof ShuntCompensatorAdapter); - assertEquals(shuntCExpected.getbPerSection(), shuntCActual.getbPerSection(), 0.0d); + double b = shuntCExpected.getModel(ShuntCompensatorLinearModel.class).getbPerSection(); + assertEquals(b, shuntCActual.getModel(ShuntCompensatorLinearModel.class).getbPerSection(), 0.0d); + shuntCActual.getModel(ShuntCompensatorLinearModel.class).setbPerSection(++b); + assertEquals(shuntCExpected.getModel(ShuntCompensatorLinearModel.class).getbPerSection(), shuntCActual.getModel(ShuntCompensatorLinearModel.class).getbPerSection(), 0.0d); double currentB = shuntCExpected.getCurrentB(); assertEquals(currentB, shuntCActual.getCurrentB(), 0.0d); - assertTrue(shuntCActual.setbPerSection(++currentB) instanceof ShuntCompensatorAdapter); + shuntCActual.getModel(ShuntCompensatorLinearModel.class).setbPerSection(++currentB); assertEquals(shuntCExpected.getCurrentB(), shuntCActual.getCurrentB(), 0.0d); Terminal terminal = mergingView.getLccConverterStation("C1").getTerminal(); @@ -86,5 +82,72 @@ public void testSetterGetter() { // Not implemented yet ! TestUtil.notImplemented(shuntCActual::remove); } + + @Test + public void testCreateLinear() { + createNetwork(); + + // Linear shunt + ShuntCompensatorAdder adder = mergingView.getVoltageLevel("VLLOAD") + .newShuntCompensator() + .setId("linear") + .setConnectableBus("NLOAD") + .setCurrentSectionCount(0) + .newLinearModel() + .setbPerSection(1.0) + .setMaximumSectionCount(2) + .add(); + assertTrue(adder instanceof ShuntCompensatorAdderAdapter); + assertTrue(adder.add() instanceof ShuntCompensatorAdapter); + + ShuntCompensator shunt = mergingView.getShuntCompensator("linear"); + assertEquals(0, shunt.getCurrentSectionCount()); + assertEquals(2, shunt.getMaximumSectionCount()); + + ShuntCompensatorLinearModel model = shunt.getModel(ShuntCompensatorLinearModel.class); + assertEquals(1.0, model.getbPerSection(), 0.0); + assertTrue(Double.isNaN(model.getgPerSection())); + } + + @Test + public void testCreateNonLinear() { + createNetwork(); + + // Non linear shunt + ShuntCompensatorAdder adder = mergingView.getVoltageLevel("VLLOAD") + .newShuntCompensator() + .setId("nonLinear") + .setConnectableBus("NLOAD") + .setCurrentSectionCount(0) + .newNonLinearModel() + .beginSection() + .setSectionNum(0) + .setB(1.0) + .endSection() + .beginSection() + .setSectionNum(1) + .setB(2.0) + .endSection() + .add(); + assertTrue(adder instanceof ShuntCompensatorAdderAdapter); + assertTrue(adder.add() instanceof ShuntCompensatorAdapter); + + ShuntCompensator shunt = mergingView.getShuntCompensator("nonLinear"); + assertEquals(0, shunt.getCurrentSectionCount()); + assertEquals(1, shunt.getMaximumSectionCount()); + + ShuntCompensatorNonLinearModel model = shunt.getModel(ShuntCompensatorNonLinearModel.class); + assertEquals(2, model.getSections().size()); + assertEquals(1.0, model.getB(0), 0.0); + assertTrue(Double.isNaN(model.getG(0))); + assertEquals(2.0, model.getB(1), 0.0); + assertTrue(Double.isNaN(model.getG(1))); + } + + private void createNetwork() { + Network network = EurostagTutorialExample1Factory.create(); + network.getLoad("LOAD").remove(); + mergingView.merge(network); + } } //pour les méthodes setComponentNumber de BusExt je peux les remonter dans Bus diff --git a/iidm/iidm-mergingview/src/test/java/com/powsybl/iidm/mergingview/VoltageLevelAdapterTest.java b/iidm/iidm-mergingview/src/test/java/com/powsybl/iidm/mergingview/VoltageLevelAdapterTest.java index d94ce50172..87c31cc8d4 100644 --- a/iidm/iidm-mergingview/src/test/java/com/powsybl/iidm/mergingview/VoltageLevelAdapterTest.java +++ b/iidm/iidm-mergingview/src/test/java/com/powsybl/iidm/mergingview/VoltageLevelAdapterTest.java @@ -138,9 +138,11 @@ public void baseTests() { .setId("SHUNT") .setConnectableBus("busA") .setBus("busA") - .setbPerSection(1e-5) .setCurrentSectionCount(1) - .setMaximumSectionCount(1) + .newLinearModel() + .setbPerSection(1e-5) + .setMaximumSectionCount(1) + .add() .add(); vlActual.getShuntCompensators().forEach(s -> { assertTrue(s instanceof ShuntCompensatorAdapter); diff --git a/iidm/iidm-scripting/src/main/groovy/com/powsybl/iidm/network/scripting/ShuntCompensatorExtension.groovy b/iidm/iidm-scripting/src/main/groovy/com/powsybl/iidm/network/scripting/ShuntCompensatorExtension.groovy new file mode 100644 index 0000000000..ca0df57e10 --- /dev/null +++ b/iidm/iidm-scripting/src/main/groovy/com/powsybl/iidm/network/scripting/ShuntCompensatorExtension.groovy @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2020, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package com.powsybl.iidm.network.scripting + +import com.powsybl.commons.PowsyblException +import com.powsybl.iidm.network.ShuntCompensator +import com.powsybl.iidm.network.ShuntCompensatorLinearModel +import com.powsybl.iidm.network.ShuntCompensatorModelType +import com.powsybl.iidm.network.ShuntCompensatorNonLinearModel + +/** + * + * @author Miora Ralambotiana + */ +class ShuntCompensatorExtension { + + static double getMaximumB(ShuntCompensator self) { + if (ShuntCompensatorModelType.LINEAR == self.getModelType()) { + // forward bPerSection * maximumSectionCount for linear shunts + return self.getModel(ShuntCompensatorLinearModel.class).getbPerSection() * self.getModel().getMaximumSectionCount() + } else if (ShuntCompensatorModelType.NON_LINEAR == self.getModelType()) { + // forward to non linear model getter for non linear shunts + return self.getModel(ShuntCompensatorNonLinearModel.class).getMaximumB() + } + throw new PowsyblException(String.format("Unexpected shunt model type: %s", self.getModelType().toString())) + } + + static double getbPerSection(ShuntCompensator self) { + if (ShuntCompensatorModelType.LINEAR == self.getModelType()) { + // forward bPerSection of linear model + return self.getModel(ShuntCompensatorLinearModel.class).getbPerSection() + } + throw new PowsyblException("shunt model is not linear") + } + + static void setbPerSection(ShuntCompensator self, double bPerSection) { + if (ShuntCompensatorModelType.LINEAR == self.getModelType()) { + // forward to linear model setter for bPerSection + self.getModel(ShuntCompensatorLinearModel.class).setbPerSection(bPerSection) + } else { + throw new PowsyblException("shunt model is not linear") + } + } + + static int getMaximumSectionCount(ShuntCompensator self) { + // forward maximumSectionCount of model + self.getModel().getMaximumSectionCount() + } + + static void setMaximumSectionCount(ShuntCompensator self, int maximumSectionCount) { + if (ShuntCompensatorModelType.LINEAR == self.getModelType()) { + // forward to linear model setter for maximumSectionCount + self.getModel(ShuntCompensatorLinearModel.class).setMaximumSectionCount(maximumSectionCount) + } else { + throw new PowsyblException("shunt model is not linear") + } + } +} diff --git a/iidm/iidm-scripting/src/main/resources/META-INF/groovy/org.codehaus.groovy.runtime.ExtensionModule b/iidm/iidm-scripting/src/main/resources/META-INF/groovy/org.codehaus.groovy.runtime.ExtensionModule index c1870fa672..0b2d9d3d03 100644 --- a/iidm/iidm-scripting/src/main/resources/META-INF/groovy/org.codehaus.groovy.runtime.ExtensionModule +++ b/iidm/iidm-scripting/src/main/resources/META-INF/groovy/org.codehaus.groovy.runtime.ExtensionModule @@ -1,3 +1,3 @@ moduleName = powsybl-iidm-scripting-module moduleVersion = 1.0 -extensionClasses = com.powsybl.iidm.network.scripting.IdentifiableExtension com.powsybl.iidm.network.scripting.NetworkExtension com.powsybl.iidm.network.scripting.SubstationExtension +extensionClasses = com.powsybl.iidm.network.scripting.IdentifiableExtension com.powsybl.iidm.network.scripting.NetworkExtension com.powsybl.iidm.network.scripting.SubstationExtension com.powsybl.iidm.network.scripting.ShuntCompensatorExtension diff --git a/iidm/iidm-scripting/src/test/groovy/com/powsybl/iidm/network/scripting/NetworkExtensionTest.groovy b/iidm/iidm-scripting/src/test/groovy/com/powsybl/iidm/network/scripting/NetworkExtensionTest.groovy index c962aea2be..b2b5888f2f 100644 --- a/iidm/iidm-scripting/src/test/groovy/com/powsybl/iidm/network/scripting/NetworkExtensionTest.groovy +++ b/iidm/iidm-scripting/src/test/groovy/com/powsybl/iidm/network/scripting/NetworkExtensionTest.groovy @@ -43,9 +43,11 @@ class NetworkExtensionTest { network.getVoltageLevel("bbVL").newShuntCompensator().setId("SHUNT") .setBus("Bus1") .setConnectableBus("Bus1") - .setbPerSection(5.0) .setCurrentSectionCount(6) - .setMaximumSectionCount(10) + .newLinearModel() + .setbPerSection(5.0) + .setMaximumSectionCount(10) + .add() .add() } diff --git a/iidm/iidm-scripting/src/test/groovy/com/powsybl/iidm/network/scripting/ShuntCompensatorExtensionTest.groovy b/iidm/iidm-scripting/src/test/groovy/com/powsybl/iidm/network/scripting/ShuntCompensatorExtensionTest.groovy new file mode 100644 index 0000000000..4797e02f78 --- /dev/null +++ b/iidm/iidm-scripting/src/test/groovy/com/powsybl/iidm/network/scripting/ShuntCompensatorExtensionTest.groovy @@ -0,0 +1,147 @@ +/** + * Copyright (c) 2020, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package com.powsybl.iidm.network.scripting + +import com.powsybl.commons.PowsyblException +import com.powsybl.iidm.network.Country +import com.powsybl.iidm.network.Network +import com.powsybl.iidm.network.ShuntCompensator +import com.powsybl.iidm.network.ShuntCompensatorAdder +import com.powsybl.iidm.network.Substation +import com.powsybl.iidm.network.TopologyKind +import com.powsybl.iidm.network.VoltageLevel +import org.junit.Rule +import org.junit.Test +import org.junit.rules.ExpectedException + +import static org.junit.Assert.assertEquals + +/** + * + * @author Miora Ralambotiana + */ +class ShuntCompensatorExtensionTest { + + @Rule + public ExpectedException thrown = ExpectedException.none() + + @Test + void linearShuntTest() { + ShuntCompensator shunt = createLinearShuntCompensator() + assertEquals(10, shunt.maximumSectionCount) + shunt.maximumSectionCount = 11 + assertEquals(11, shunt.maximumSectionCount) + assertEquals(5.0, shunt.bPerSection, 0.0f) + shunt.bPerSection = 4.0 + assertEquals(4.0, shunt.bPerSection, 0.0f) + assertEquals(44.0, shunt.maximumB, 0.0) + } + + @Test + void nonLinearShuntTest() { + ShuntCompensator shunt = createNonLinearShuntCompensator() + assertEquals(2, shunt.maximumSectionCount) + assertEquals(6.0, shunt.maximumB, 0.0f) + } + + @Test + void failGetbPerSectionTest() { + thrown.expect(PowsyblException.class) + thrown.expectMessage("shunt model is not linear") + ShuntCompensator shunt = createNonLinearShuntCompensator() + double bPerSection = shunt.bPerSection + } + + @Test + void failSetbPerSectionTest() { + thrown.expect(PowsyblException.class) + thrown.expectMessage("shunt model is not linear") + ShuntCompensator shunt = createNonLinearShuntCompensator() + shunt.bPerSection = 4.0 + } + + @Test + void failSetMaximumSectionCountTest() { + thrown.expect(PowsyblException.class) + thrown.expectMessage("shunt model is not linear") + ShuntCompensator shunt = createNonLinearShuntCompensator() + shunt.maximumSectionCount = 11 + } + + static ShuntCompensator createLinearShuntCompensator() { + Network network = Network.create("test", "test") + Substation substation = network.newSubstation() + .setCountry(Country.AF) + .setTso("tso") + .setName("sub") + .setId("subId") + .add() + VoltageLevel voltageLevel = substation.newVoltageLevel() + .setTopologyKind(TopologyKind.BUS_BREAKER) + .setId("bbVL") + .setName("bbVL_name") + .setNominalV(200.0f) + .add() + voltageLevel.getBusBreakerView() + .newBus() + .setName("Bus1") + .setId("Bus1") + .add() + network.getVoltageLevel("bbVL").newShuntCompensator().setId("SHUNT") + .setBus("Bus1") + .setConnectableBus("Bus1") + .setCurrentSectionCount(6) + .newLinearModel() + .setbPerSection(5.0) + .setMaximumSectionCount(10) + .add() + .add() + } + + static ShuntCompensator createNonLinearShuntCompensator() { + Network network = Network.create("test", "test") + Substation substation = network.newSubstation() + .setCountry(Country.AF) + .setTso("tso") + .setName("sub") + .setId("subId") + .add() + VoltageLevel voltageLevel = substation.newVoltageLevel() + .setTopologyKind(TopologyKind.BUS_BREAKER) + .setId("bbVL") + .setName("bbVL_name") + .setNominalV(200.0f) + .add() + voltageLevel.getBusBreakerView() + .newBus() + .setName("Bus1") + .setId("Bus1") + .add() + ShuntCompensatorAdder adder = voltageLevel.newShuntCompensator() + .setId("SHUNT") + .setBus("Bus1") + .setConnectableBus("Bus1") + .setCurrentSectionCount(1) + adder.newNonLinearModel() + .beginSection() + .setSectionNum(0) + .setB(0.0) + .setG(0.0) + .endSection() + .beginSection() + .setSectionNum(1) + .setB(5.0) + .setG(2.0) + .endSection() + .beginSection() + .setSectionNum(2) + .setB(6.0) + .endSection() + .add() + adder.add() + } +} \ No newline at end of file diff --git a/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractLccTest.java b/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractLccTest.java index 6b5a63d72e..00e4c64317 100644 --- a/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractLccTest.java +++ b/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractLccTest.java @@ -62,9 +62,6 @@ public void testBase() { assertTrue(network.getShuntCompensator("C1_Filter1").getTerminal().isConnected()); assertEquals(0.0, network.getShuntCompensator(C1_FILTER2).getCurrentB(), 0.0); - // TODO: delete this line when getMaximumB() is deleted - assertEquals(2e-5, network.getShuntCompensator(C1_FILTER2).getMaximumB(), 0.0); - assertFalse(network.getShuntCompensator(C1_FILTER2).getTerminal().isConnected()); assertEquals(1, network.getHvdcLineCount()); HvdcLine l = network.getHvdcLine("L"); diff --git a/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractShuntCompensatorTest.java b/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractShuntCompensatorTest.java index 7e674c29aa..002da06c33 100644 --- a/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractShuntCompensatorTest.java +++ b/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractShuntCompensatorTest.java @@ -6,6 +6,7 @@ */ package com.powsybl.iidm.network.tck; +import com.powsybl.commons.PowsyblException; import com.powsybl.iidm.network.*; import com.powsybl.iidm.network.test.EurostagTutorialExample1Factory; import com.powsybl.iidm.network.test.NoEquipmentNetworkFactory; @@ -21,6 +22,9 @@ public abstract class AbstractShuntCompensatorTest { + interface FooModel extends ShuntCompensatorModel { + } + private static final String INVALID = "invalid"; private static final String SHUNT = "shunt"; @@ -49,41 +53,168 @@ public void setUp() { } @Test - public void baseTest() { + public void baseLinearShuntTest() { // adder - ShuntCompensator shuntCompensator = voltageLevel.newShuntCompensator() + ShuntCompensator shuntCompensator = createLinearShunt(SHUNT, "shuntName", 5.0, 4.0, + 6, 10, terminal, true, 200, 10); + + assertEquals(ConnectableType.SHUNT_COMPENSATOR, shuntCompensator.getType()); + assertEquals("shuntName", shuntCompensator.getOptionalName().orElse(null)); + assertEquals(SHUNT, shuntCompensator.getId()); + assertEquals(6, shuntCompensator.getCurrentSectionCount()); + assertEquals(10, shuntCompensator.getMaximumSectionCount()); + assertSame(terminal, shuntCompensator.getRegulatingTerminal()); + assertTrue(shuntCompensator.isVoltageRegulatorOn()); + assertEquals(200, shuntCompensator.getTargetV(), 0.0); + assertEquals(10, shuntCompensator.getTargetDeadband(), 0.0); + assertEquals(ShuntCompensatorModelType.LINEAR, shuntCompensator.getModelType()); + ShuntCompensatorLinearModel shuntLinearModel = shuntCompensator.getModel(ShuntCompensatorLinearModel.class); + assertEquals(5.0, shuntLinearModel.getbPerSection(), 0.0); + assertEquals(4.0, shuntLinearModel.getgPerSection(), 0.0); + + // try get incorrect shunt model + try { + shuntCompensator.getModel(FooModel.class); + fail(); + } catch (ValidationException ignored) { + // ignore + } + + // currentSectionCount + try { + shuntCompensator.setCurrentSectionCount(-1); + fail(); + } catch (ValidationException ignored) { + // ignore + } + try { + // max = 10, current could not be 20 + shuntCompensator.setCurrentSectionCount(20); + fail(); + } catch (ValidationException ignored) { + // ignore + } + shuntCompensator.setCurrentSectionCount(6); + assertEquals(6, shuntCompensator.getCurrentSectionCount()); + + // for linear model + + // bPerSection + try { + shuntLinearModel.setbPerSection(0.0); + fail(); + } catch (ValidationException ignored) { + // ignore + } + shuntLinearModel.setbPerSection(1.0); + assertEquals(1.0, shuntLinearModel.getbPerSection(), 0.0); + + // gPerSection + shuntLinearModel.setgPerSection(2.0); + assertEquals(2.0, shuntLinearModel.getgPerSection(), 0.0); + + // maximumSectionCount + try { + shuntLinearModel.setMaximumSectionCount(1); + fail(); + } catch (ValidationException ignored) { + // ignore + } + shuntLinearModel.setMaximumSectionCount(20); + assertEquals(20, shuntCompensator.getMaximumSectionCount()); + + // remove + int count = network.getShuntCompensatorCount(); + shuntCompensator.remove(); + assertNull(network.getShuntCompensator(SHUNT)); + assertNotNull(shuntCompensator); + assertEquals(count - 1L, network.getShuntCompensatorCount()); + } + + @Test + public void invalidbPerSection() { + thrown.expect(ValidationException.class); + thrown.expectMessage("section susceptance is invalid"); + createLinearShunt(INVALID, INVALID, Double.NaN, Double.NaN, 5, 10, null, false, Double.NaN, Double.NaN); + } + + @Test + public void invalidZerobPerSection() { + thrown.expect(ValidationException.class); + thrown.expectMessage("susceptance per section is equal to zero"); + createLinearShunt(INVALID, INVALID, 0.0, Double.NaN, 5, 10, null, false, Double.NaN, Double.NaN); + } + + @Test + public void invalidNegativeMaxPerSection() { + thrown.expect(ValidationException.class); + thrown.expectMessage("should be greater than 0"); + createLinearShunt(INVALID, INVALID, 2.0, Double.NaN, 0, -1, null, false, Double.NaN, Double.NaN); + } + + @Test + public void baseNonLinearShuntTest() { + // adder + ShuntCompensatorAdder adder = voltageLevel.newShuntCompensator() .setId(SHUNT) .setName("shuntName") .setConnectableBus("busA") - .setbPerSection(5.0) - .setCurrentSectionCount(6) - .setMaximumSectionCount(10) + .setCurrentSectionCount(1) .setRegulatingTerminal(terminal) .setVoltageRegulatorOn(true) .setTargetV(200) - .setTargetDeadband(10) + .setTargetDeadband(10); + adder.newNonLinearModel() + .beginSection() + .setSectionNum(0) + .setB(0.0) + .setG(0.0) + .endSection() + .beginSection() + .setSectionNum(1) + .setB(5.0) + .setG(2.0) + .endSection() + .beginSection() + .setSectionNum(2) + .setB(6.0) + .endSection() .add(); + ShuntCompensator shuntCompensator = adder.add(); + assertEquals(ConnectableType.SHUNT_COMPENSATOR, shuntCompensator.getType()); - assertEquals("shuntName", shuntCompensator.getName()); + assertEquals("shuntName", shuntCompensator.getOptionalName().orElse(null)); + assertEquals("shuntName", shuntCompensator.getNameOrId()); assertEquals(SHUNT, shuntCompensator.getId()); - assertEquals(5.0, shuntCompensator.getbPerSection(), 0.0); - assertEquals(6, shuntCompensator.getCurrentSectionCount()); - assertEquals(10, shuntCompensator.getMaximumSectionCount()); + assertEquals(1, shuntCompensator.getCurrentSectionCount()); + assertEquals(2, shuntCompensator.getMaximumSectionCount()); assertSame(terminal, shuntCompensator.getRegulatingTerminal()); assertTrue(shuntCompensator.isVoltageRegulatorOn()); assertEquals(200, shuntCompensator.getTargetV(), 0.0); assertEquals(10, shuntCompensator.getTargetDeadband(), 0.0); + assertEquals(ShuntCompensatorModelType.NON_LINEAR, shuntCompensator.getModelType()); + ShuntCompensatorNonLinearModel shuntNonLinearModel = shuntCompensator.getModel(ShuntCompensatorNonLinearModel.class); + assertEquals(3, shuntNonLinearModel.getSections().size()); + assertFalse(shuntNonLinearModel.getSection(3).isPresent()); + assertEquals(0.0, shuntNonLinearModel.getB(0), 0.0); + assertEquals(0.0, shuntNonLinearModel.getG(0), 0.0); + assertEquals(5.0, shuntNonLinearModel.getB(1), 0.0); + assertEquals(2.0, shuntNonLinearModel.getG(1), 0.0); + assertEquals(6.0, shuntNonLinearModel.getB(2), 0.0); + assertTrue(Double.isNaN(shuntNonLinearModel.getG(2))); + assertEquals(6.0, shuntNonLinearModel.getMaximumB(), 0.0); + assertEquals(2.0, shuntNonLinearModel.getMaximumG(), 0.0); + assertFalse(shuntNonLinearModel.getSection(3).isPresent()); - // setter getter + // try get incorrect shunt model try { - shuntCompensator.setbPerSection(0.0); + shuntCompensator.getModel(FooModel.class); fail(); } catch (ValidationException ignored) { // ignore } - shuntCompensator.setbPerSection(1.0); - assertEquals(1.0, shuntCompensator.getbPerSection(), 0.0); + // currentSectionCount try { shuntCompensator.setCurrentSectionCount(-1); fail(); @@ -91,24 +222,134 @@ public void baseTest() { // ignore } try { - // max = 10 , current could not be 20 + // exiting = 0, 1, 2, current could not be 20 shuntCompensator.setCurrentSectionCount(20); fail(); } catch (ValidationException ignored) { // ignore } - shuntCompensator.setCurrentSectionCount(6); - assertEquals(6, shuntCompensator.getCurrentSectionCount()); + shuntCompensator.setCurrentSectionCount(2); + assertEquals(2, shuntCompensator.getCurrentSectionCount()); + // for non linear model + + // getB try { - shuntCompensator.setMaximumSectionCount(1); + // try to get susceptance of a non-existing section + shuntNonLinearModel.getB(3); fail(); - } catch (ValidationException ignored) { + } catch (PowsyblException ignored) { + // ignore + } + + // getG + try { + // try to get conductance of a non-existing section + shuntNonLinearModel.getG(3); + fail(); + } catch (PowsyblException ignored) { // ignore } - shuntCompensator.setMaximumSectionCount(20); - assertEquals(20, shuntCompensator.getMaximumSectionCount()); + // add or replace a section + try { + // try to add or replace with negative section number + shuntNonLinearModel.addOrReplaceSection(-2, 4.0, 1.0); + fail(); + } catch (ValidationException ignored) { + // ignored + } + try { + // try to add or replace with a negative susceptance + shuntNonLinearModel.addOrReplaceSection(3, Double.NaN, 1.0); + fail(); + } catch (ValidationException ignored) { + // ignored + } + shuntNonLinearModel.addOrReplaceSection(3, 4.0, 1.0); // add a section + assertEquals(4, shuntNonLinearModel.getSections().size()); + assertEquals(4.0, shuntNonLinearModel.getB(3), 0.0); + assertEquals(1.0, shuntNonLinearModel.getG(3), 0.0); + assertEquals(3, shuntCompensator.getMaximumSectionCount()); + shuntNonLinearModel.addOrReplaceSection(3, 3.0, 1.5); // replace a section + assertEquals(4, shuntNonLinearModel.getSections().size()); + assertEquals(3.0, shuntNonLinearModel.getB(3), 0.0); + assertEquals(1.5, shuntNonLinearModel.getG(3), 0.0); + + // remove a section + try { + // try to remove a section with negative section number + shuntNonLinearModel.removeSection(-1); + fail(); + } catch (ValidationException ignored) { + // ignored + } + try { + // try to remove a non-existing section + shuntNonLinearModel.removeSection(4); + fail(); + } catch (ValidationException ignored) { + // ignored + } + try { + // try to remove the current section + shuntNonLinearModel.removeSection(2); + fail(); + } catch (ValidationException ignored) { + // ignored + } + shuntNonLinearModel.removeSection(3); + assertEquals(3, shuntNonLinearModel.getSections().size()); + assertFalse(shuntNonLinearModel.getSection(3).isPresent()); + assertEquals(2, shuntCompensator.getMaximumSectionCount()); + } + + @Test + public void invalidEmptyNonLinearModel() { + thrown.expect(ValidationException.class); + thrown.expectMessage("a shunt compensator must have at least one section"); + ShuntCompensatorAdder adder = createShuntAdder(INVALID, INVALID, 6, terminal, true, 200, 10); + adder.newNonLinearModel().add(); + } + + @Test + public void invalidExistingSection() { + thrown.expect(ValidationException.class); + thrown.expectMessage("a section is already defined at this number"); + ShuntCompensatorAdder adder = createShuntAdder(INVALID, INVALID, 6, terminal, true, 200, 10); + adder.newNonLinearModel() + .beginSection() + .setSectionNum(1) + .setB(5.0) + .endSection() + .beginSection() + .setSectionNum(1) + .setB(4.0) + .endSection(); + } + + @Test + public void undefinedModel() { + thrown.expect(ValidationException.class); + thrown.expectMessage("the shunt compensator model has not been defined"); + voltageLevel.newShuntCompensator() + .setId(INVALID) + .setName(INVALID) + .setConnectableBus("busA") + .setCurrentSectionCount(6) + .setRegulatingTerminal(terminal) + .setVoltageRegulatorOn(false) + .setTargetV(Double.NaN) + .setTargetDeadband(Double.NaN) + .add(); + } + + @Test + public void regulationTest() { + ShuntCompensator shuntCompensator = createLinearShunt(SHUNT, "shuntName", 5.0, 4.0, 6, 10, terminal, true, + 200, 10); + + // regulating terminal try { Network tmp = EurostagTutorialExample1Factory.create(); Terminal tmpTerminal = tmp.getGenerator("GEN").getTerminal(); @@ -120,7 +361,13 @@ public void baseTest() { shuntCompensator.setRegulatingTerminal(null); assertSame(shuntCompensator.getTerminal(), shuntCompensator.getRegulatingTerminal()); + // voltageRegulatorOn + shuntCompensator.setVoltageRegulatorOn(false); + assertFalse(shuntCompensator.isVoltageRegulatorOn()); + + // targetV try { + shuntCompensator.setVoltageRegulatorOn(true); shuntCompensator.setTargetV(Double.NaN); fail(); } catch (ValidationException ignored) { @@ -134,47 +381,26 @@ public void baseTest() { } catch (ValidationException ignored) { // ignore } - shuntCompensator.setVoltageRegulatorOn(false); shuntCompensator.setTargetV(400); - assertFalse(shuntCompensator.isVoltageRegulatorOn()); assertEquals(400, shuntCompensator.getTargetV(), 0.0); + // targetDeadband try { shuntCompensator.setTargetDeadband(-1.0); fail(); } catch (ValidationException ignored) { // ignore } + try { + shuntCompensator.setVoltageRegulatorOn(false); + shuntCompensator.setTargetDeadband(Double.NaN); + shuntCompensator.setVoltageRegulatorOn(true); + fail(); + } catch (ValidationException ignored) { + // ignore + } shuntCompensator.setTargetDeadband(5.0); assertEquals(5.0, shuntCompensator.getTargetDeadband(), 0.0); - - // remove - int count = network.getShuntCompensatorCount(); - shuntCompensator.remove(); - assertNull(network.getShuntCompensator(SHUNT)); - assertNotNull(shuntCompensator); - assertEquals(count - 1L, network.getShuntCompensatorCount()); - } - - @Test - public void invalidbPerSection() { - thrown.expect(ValidationException.class); - thrown.expectMessage("susceptance per section is invalid"); - createShunt(INVALID, INVALID, Double.NaN, 5, 10, null, false, Double.NaN, Double.NaN); - } - - @Test - public void invalidZerobPerSection() { - thrown.expect(ValidationException.class); - thrown.expectMessage("susceptance per section is equal to zero"); - createShunt(INVALID, INVALID, 0.0, 5, 10, null, false, Double.NaN, Double.NaN); - } - - @Test - public void invalidNegativeMaxPerSection() { - thrown.expect(ValidationException.class); - thrown.expectMessage("should be greater than 0"); - createShunt(INVALID, INVALID, 2.0, 0, -1, null, false, Double.NaN, Double.NaN); } @Test @@ -183,27 +409,34 @@ public void invalidRegulatingTerminal() { thrown.expectMessage("regulating terminal is not part of the network"); Network tmp = EurostagTutorialExample1Factory.create(); Terminal tmpTerminal = tmp.getGenerator("GEN").getTerminal(); - createShunt(INVALID, INVALID, 2.0, 0, 10, tmpTerminal, false, Double.NaN, Double.NaN); + createLinearShunt(INVALID, INVALID, 2.0, 1.0, 0, 10, tmpTerminal, false, Double.NaN, Double.NaN); } @Test public void invalidTargetV() { thrown.expect(ValidationException.class); thrown.expectMessage("invalid value (-10.0) for voltage setpoint"); - createShunt(INVALID, INVALID, 2.0, 0, 10, null, true, -10, Double.NaN); + createLinearShunt(INVALID, INVALID, 2.0, 1.0, 0, 10, null, true, -10, 0); + } + + @Test + public void invalidNanTargetV() { + thrown.expect(ValidationException.class); + thrown.expectMessage("invalid value (NaN) for voltage setpoint (voltage regulator is on)"); + createLinearShunt(INVALID, INVALID, 5.0, 1.0, 6, 10, null, true, Double.NaN, 0); } @Test public void invalidTargetDeadband() { thrown.expect(ValidationException.class); thrown.expectMessage("Unexpected value for target deadband of shunt compensator: -10.0"); - createShunt(INVALID, INVALID, 2.0, 0, 10, null, false, Double.NaN, -10); + createLinearShunt(INVALID, INVALID, 2.0, 1.0, 0, 10, null, false, Double.NaN, -10); } @Test public void testSetterGetterInMultiVariants() { VariantManager variantManager = network.getVariantManager(); - createShunt(TEST_MULTI_VARIANT, TEST_MULTI_VARIANT, 2.0, 5, 10, terminal, true, 200, 10); + createLinearShunt(TEST_MULTI_VARIANT, TEST_MULTI_VARIANT, 2.0, 1.0, 5, 10, terminal, true, 200, 10); ShuntCompensator shunt = network.getShuntCompensator(TEST_MULTI_VARIANT); List variantsToAdd = Arrays.asList("s1", "s2", "s3", "s4"); variantManager.cloneVariant(VariantManagerConstants.INITIAL_VARIANT_ID, variantsToAdd); @@ -212,6 +445,7 @@ public void testSetterGetterInMultiVariants() { // check values cloned by extend assertEquals(5, shunt.getCurrentSectionCount()); assertEquals(10.0, shunt.getCurrentB(), 0.0); // 2*5 + assertEquals(5.0, shunt.getCurrentG(), 0.0); // 1*5 // change values in s4 shunt.setCurrentSectionCount(4) .setVoltageRegulatorOn(false) @@ -226,6 +460,7 @@ public void testSetterGetterInMultiVariants() { // check values cloned by allocate assertEquals(4, shunt.getCurrentSectionCount()); assertEquals(8.0, shunt.getCurrentB(), 0.0); // 2*4 + assertEquals(4.0, shunt.getCurrentG(), 0.0); // 1*4 assertFalse(shunt.isVoltageRegulatorOn()); assertEquals(220, shunt.getTargetV(), 0.0); assertEquals(5.0, shunt.getTargetDeadband(), 0.0); @@ -234,6 +469,7 @@ public void testSetterGetterInMultiVariants() { variantManager.setWorkingVariant(VariantManagerConstants.INITIAL_VARIANT_ID); assertEquals(5, shunt.getCurrentSectionCount()); assertEquals(10.0, shunt.getCurrentB(), 0.0); // 2*5 + assertEquals(5.0, shunt.getCurrentG(), 0.0); // 1*5 assertTrue(shunt.isVoltageRegulatorOn()); assertEquals(200, shunt.getTargetV(), 0.0); assertEquals(10, shunt.getTargetDeadband(), 0.0); @@ -267,18 +503,25 @@ public void testSetterGetterInMultiVariants() { } } - private void createShunt(String id, String name, double bPerSection, int currentSectionCount, int maxSectionCount, Terminal regulatingTerminal, boolean voltageRegulatorOn, double targetV, double targetDeadband) { - voltageLevel.newShuntCompensator() + private ShuntCompensator createLinearShunt(String id, String name, double bPerSection, double gPerSection, int currentSectionCount, int maxSectionCount, Terminal regulatingTerminal, boolean voltageRegulatorOn, double targetV, double targetDeadband) { + return createShuntAdder(id, name, currentSectionCount, regulatingTerminal, voltageRegulatorOn, targetV, targetDeadband) + .newLinearModel() + .setbPerSection(bPerSection) + .setgPerSection(gPerSection) + .setMaximumSectionCount(maxSectionCount) + .add() + .add(); + } + + private ShuntCompensatorAdder createShuntAdder(String id, String name, int currentSectionCount, Terminal regulatingTerminal, boolean voltageRegulatorOn, double targetV, double targetDeadband) { + return voltageLevel.newShuntCompensator() .setId(id) .setName(name) .setConnectableBus("busA") - .setbPerSection(bPerSection) .setCurrentSectionCount(currentSectionCount) - .setMaximumSectionCount(maxSectionCount) .setRegulatingTerminal(regulatingTerminal) .setVoltageRegulatorOn(voltageRegulatorOn) .setTargetV(targetV) - .setTargetDeadband(targetDeadband) - .add(); + .setTargetDeadband(targetDeadband); } } diff --git a/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/EurostagTutorialExample1Factory.java b/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/EurostagTutorialExample1Factory.java index cc777f0521..3e6d56cc76 100644 --- a/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/EurostagTutorialExample1Factory.java +++ b/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/EurostagTutorialExample1Factory.java @@ -445,9 +445,11 @@ public static Network createWithMultipleConnectedComponents(NetworkFactory netwo vlhv3.newShuntCompensator() .setId("SHUNT") .setConnectableBus(nshunt.getId()) - .setMaximumSectionCount(1) .setCurrentSectionCount(1) - .setbPerSection(1e-5) + .newLinearModel() + .setbPerSection(1e-5) + .setMaximumSectionCount(1) + .add() .add(); return network; diff --git a/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/HvdcTestNetwork.java b/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/HvdcTestNetwork.java index bcb4385e6d..fdea891ef7 100644 --- a/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/HvdcTestNetwork.java +++ b/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/HvdcTestNetwork.java @@ -112,14 +112,14 @@ public static Network createVsc(NetworkFactory networkFactory) { .setQ(50.0); cs1.newReactiveCapabilityCurve() .beginPoint() - .setP(5.0) - .setMinQ(0.0) - .setMaxQ(10.0) + .setP(5.0) + .setMinQ(0.0) + .setMaxQ(10.0) .endPoint() .beginPoint() - .setP(10.0) - .setMinQ(0.0) - .setMaxQ(10.0) + .setP(10.0) + .setMinQ(0.0) + .setMaxQ(10.0) .endPoint() .add(); VoltageLevel vl2 = network.getVoltageLevel("VL2"); @@ -151,9 +151,11 @@ public static Network createLcc(NetworkFactory networkFactory) { .setName("Filter 1") .setConnectableBus("B1") .setBus("B1") - .setbPerSection(1e-5) .setCurrentSectionCount(1) - .setMaximumSectionCount(1) + .newLinearModel() + .setbPerSection(1e-5) + .setMaximumSectionCount(1) + .add() .add(); shunt1.getTerminal() .setQ(25.0); @@ -161,9 +163,11 @@ public static Network createLcc(NetworkFactory networkFactory) { .setId("C1_Filter2") .setName("Filter 2") .setConnectableBus("B1") - .setbPerSection(2e-5) .setCurrentSectionCount(0) - .setMaximumSectionCount(1) + .newLinearModel() + .setbPerSection(2e-5) + .setMaximumSectionCount(1) + .add() .add(); shunt2.getTerminal() .setQ(25.0); @@ -215,9 +219,11 @@ public static Network createLcc(NetworkFactory networkFactory) { .setId("C2_Filter1") .setName("Filter 3") .setNode(4) - .setbPerSection(3e-5) .setCurrentSectionCount(1) - .setMaximumSectionCount(1) + .newLinearModel() + .setbPerSection(3e-5) + .setMaximumSectionCount(1) + .add() .add(); shunt3.getTerminal() .setQ(12.5); @@ -225,9 +231,11 @@ public static Network createLcc(NetworkFactory networkFactory) { .setId("C2_Filter2") .setName("Filter 4") .setNode(6) - .setbPerSection(4e-5) .setCurrentSectionCount(1) - .setMaximumSectionCount(1) + .newLinearModel() + .setbPerSection(4e-5) + .setMaximumSectionCount(1) + .add() .add(); shunt4.getTerminal() .setQ(12.5); diff --git a/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/ShuntTestCaseFactory.java b/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/ShuntTestCaseFactory.java index 9160f55f44..a238295a8a 100644 --- a/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/ShuntTestCaseFactory.java +++ b/iidm/iidm-test/src/main/java/com/powsybl/iidm/network/test/ShuntTestCaseFactory.java @@ -67,13 +67,15 @@ public static Network create(NetworkFactory networkFactory) { .setId("SHUNT") .setBus("B1") .setConnectableBus("B1") - .setMaximumSectionCount(1) .setCurrentSectionCount(1) - .setbPerSection(1e-5) .setVoltageRegulatorOn(true) .setRegulatingTerminal(load.getTerminal()) .setTargetV(200) .setTargetDeadband(5.0) + .newLinearModel() + .setMaximumSectionCount(1) + .setbPerSection(1e-5) + .add() .add(); return network; diff --git a/iidm/iidm-xml-converter/src/main/java/com/powsybl/iidm/xml/ShuntXml.java b/iidm/iidm-xml-converter/src/main/java/com/powsybl/iidm/xml/ShuntXml.java index b3da59de0a..4422103f13 100644 --- a/iidm/iidm-xml-converter/src/main/java/com/powsybl/iidm/xml/ShuntXml.java +++ b/iidm/iidm-xml-converter/src/main/java/com/powsybl/iidm/xml/ShuntXml.java @@ -6,10 +6,9 @@ */ package com.powsybl.iidm.xml; +import com.powsybl.commons.PowsyblException; import com.powsybl.commons.xml.XmlUtil; -import com.powsybl.iidm.network.ShuntCompensator; -import com.powsybl.iidm.network.ShuntCompensatorAdder; -import com.powsybl.iidm.network.VoltageLevel; +import com.powsybl.iidm.network.*; import com.powsybl.iidm.xml.util.IidmXmlUtil; import javax.xml.stream.XMLStreamException; @@ -37,7 +36,10 @@ protected boolean hasSubElements(ShuntCompensator sc) { @Override protected void writeRootElementAttributes(ShuntCompensator sc, VoltageLevel vl, NetworkXmlWriterContext context) throws XMLStreamException { - XmlUtil.writeDouble("bPerSection", sc.getbPerSection(), context.getWriter()); + if (ShuntCompensatorModelType.NON_LINEAR.equals(sc.getModelType())) { + throw new PowsyblException("Non linear shunt not yet supported"); + } + XmlUtil.writeDouble("bPerSection", sc.getModel(ShuntCompensatorLinearModel.class).getbPerSection(), context.getWriter()); context.getWriter().writeAttribute("maximumSectionCount", Integer.toString(sc.getMaximumSectionCount())); context.getWriter().writeAttribute("currentSectionCount", Integer.toString(sc.getCurrentSectionCount())); IidmXmlUtil.writeBooleanAttributeFromMinimumVersion(ROOT_ELEMENT_NAME, "voltageRegulatorOn", sc.isVoltageRegulatorOn(), false, @@ -76,9 +78,11 @@ protected ShuntCompensator readRootElementAttributes(ShuntCompensatorAdder adder .setTargetV(targetV) .setTargetDeadband(targetDeadband); }); - adder.setbPerSection(bPerSection) - .setMaximumSectionCount(maximumSectionCount) - .setCurrentSectionCount(currentSectionCount); + adder.setCurrentSectionCount(currentSectionCount) + .newLinearModel() + .setMaximumSectionCount(maximumSectionCount) + .setbPerSection(bPerSection) + .add(); readNodeOrBus(adder, context); ShuntCompensator sc = adder.add(); readPQ(null, sc.getTerminal(), context.getReader()); diff --git a/loadflow/loadflow-results-completion/src/test/java/com/powsybl/loadflow/resultscompletion/LoadFlowResultsCompletionZ0FlowsTest.java b/loadflow/loadflow-results-completion/src/test/java/com/powsybl/loadflow/resultscompletion/LoadFlowResultsCompletionZ0FlowsTest.java index b8b4b63f95..add90dbfde 100644 --- a/loadflow/loadflow-results-completion/src/test/java/com/powsybl/loadflow/resultscompletion/LoadFlowResultsCompletionZ0FlowsTest.java +++ b/loadflow/loadflow-results-completion/src/test/java/com/powsybl/loadflow/resultscompletion/LoadFlowResultsCompletionZ0FlowsTest.java @@ -470,17 +470,21 @@ private Network createNetwork() { .setId("SC3.1") .setConnectableBus("B3.1") .setBus("B3.1") - .setbPerSection(25.0 / Math.pow(vbase, 2)) - .setMaximumSectionCount(1) .setCurrentSectionCount(1) + .newLinearModel() + .setbPerSection(25.0 / Math.pow(vbase, 2)) + .setMaximumSectionCount(1) + .add() .add(); vl.newShuntCompensator() .setId("SC3.4") .setConnectableBus("B3.4") .setBus("B3.4") - .setbPerSection(5.00 / Math.pow(vbase, 2)) - .setMaximumSectionCount(1) .setCurrentSectionCount(1) + .newLinearModel() + .setbPerSection(5.00 / Math.pow(vbase, 2)) + .setMaximumSectionCount(1) + .add() .add(); return network; } diff --git a/loadflow/loadflow-validation/src/main/java/com/powsybl/loadflow/validation/ShuntCompensatorsValidation.java b/loadflow/loadflow-validation/src/main/java/com/powsybl/loadflow/validation/ShuntCompensatorsValidation.java index d1a6e4cdc8..41e2ddd5dc 100644 --- a/loadflow/loadflow-validation/src/main/java/com/powsybl/loadflow/validation/ShuntCompensatorsValidation.java +++ b/loadflow/loadflow-validation/src/main/java/com/powsybl/loadflow/validation/ShuntCompensatorsValidation.java @@ -15,12 +15,11 @@ import java.util.Comparator; import java.util.Objects; +import com.powsybl.commons.PowsyblException; +import com.powsybl.iidm.network.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.powsybl.iidm.network.Bus; -import com.powsybl.iidm.network.Network; -import com.powsybl.iidm.network.ShuntCompensator; import com.powsybl.loadflow.validation.io.ValidationWriter; /** @@ -62,10 +61,10 @@ public boolean checkShunts(Network network, ValidationConfig config, ValidationW Objects.requireNonNull(shuntsWriter); LOGGER.info("Checking shunt compensators of network {}", network.getId()); return network.getShuntCompensatorStream() - .sorted(Comparator.comparing(ShuntCompensator::getId)) - .map(shunt -> checkShunts(shunt, config, shuntsWriter)) - .reduce(Boolean::logicalAnd) - .orElse(true); + .sorted(Comparator.comparing(ShuntCompensator::getId)) + .map(shunt -> checkShunts(shunt, config, shuntsWriter)) + .reduce(Boolean::logicalAnd) + .orElse(true); } public boolean checkShunts(ShuntCompensator shunt, ValidationConfig config, Writer writer) { @@ -85,11 +84,15 @@ public boolean checkShunts(ShuntCompensator shunt, ValidationConfig config, Vali Objects.requireNonNull(config); Objects.requireNonNull(shuntsWriter); + if (ShuntCompensatorModelType.NON_LINEAR.equals(shunt.getModelType())) { + throw new PowsyblException("non linear shunt not supported yet"); + } + double p = shunt.getTerminal().getP(); double q = shunt.getTerminal().getQ(); int currentSectionCount = shunt.getCurrentSectionCount(); int maximumSectionCount = shunt.getMaximumSectionCount(); - double bPerSection = shunt.getbPerSection(); + double bPerSection = shunt.getModel(ShuntCompensatorLinearModel.class).getbPerSection(); double nominalV = shunt.getTerminal().getVoltageLevel().getNominalV(); double qMax = bPerSection * maximumSectionCount * nominalV * nominalV; Bus bus = shunt.getTerminal().getBusView().getBus(); @@ -102,8 +105,8 @@ public boolean checkShunts(ShuntCompensator shunt, ValidationConfig config, Vali } public boolean checkShunts(String id, double p, double q, int currentSectionCount, int maximumSectionCount, double bPerSection, - double v, double qMax, double nominalV, boolean connected, boolean mainComponent, ValidationConfig config, - Writer writer) { + double v, double qMax, double nominalV, boolean connected, boolean mainComponent, ValidationConfig config, + Writer writer) { Objects.requireNonNull(id); Objects.requireNonNull(config); Objects.requireNonNull(writer); @@ -116,8 +119,8 @@ public boolean checkShunts(String id, double p, double q, int currentSectionCoun } public boolean checkShunts(String id, double p, double q, int currentSectionCount, int maximumSectionCount, double bPerSection, - double v, double qMax, double nominalV, boolean connected, boolean mainComponent, ValidationConfig config, - ValidationWriter shuntsWriter) { + double v, double qMax, double nominalV, boolean connected, boolean mainComponent, ValidationConfig config, + ValidationWriter shuntsWriter) { boolean validated = true; if (!connected && !Double.isNaN(q) && q != 0) { // if the shunt is disconnected then either “q” is not defined or “q” is 0 diff --git a/loadflow/loadflow-validation/src/test/java/com/powsybl/loadflow/validation/ShuntCompensatorsValidationTest.java b/loadflow/loadflow-validation/src/test/java/com/powsybl/loadflow/validation/ShuntCompensatorsValidationTest.java index 6acee81bb3..ef78b195c1 100644 --- a/loadflow/loadflow-validation/src/test/java/com/powsybl/loadflow/validation/ShuntCompensatorsValidationTest.java +++ b/loadflow/loadflow-validation/src/test/java/com/powsybl/loadflow/validation/ShuntCompensatorsValidationTest.java @@ -12,18 +12,14 @@ import java.io.IOException; import java.util.stream.Stream; +import com.powsybl.iidm.network.*; import org.apache.commons.io.output.NullWriter; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; -import com.powsybl.iidm.network.Bus; -import com.powsybl.iidm.network.Network; -import com.powsybl.iidm.network.ShuntCompensator; -import com.powsybl.iidm.network.Terminal; import com.powsybl.iidm.network.Terminal.BusView; import com.powsybl.loadflow.validation.io.ValidationWriter; -import com.powsybl.iidm.network.VoltageLevel; /** * @@ -67,13 +63,18 @@ public void setUp() throws IOException { Mockito.when(shuntTerminal.getBusView()).thenReturn(shuntBusView); Mockito.when(shuntTerminal.getVoltageLevel()).thenReturn(shuntVoltageLevel); + ShuntCompensatorLinearModel shuntModel = Mockito.mock(ShuntCompensatorLinearModel.class); + Mockito.when(shuntModel.getbPerSection()).thenReturn(bPerSection); + shunt = Mockito.mock(ShuntCompensator.class); Mockito.when(shunt.getId()).thenReturn("shunt"); Mockito.when(shunt.getTerminal()).thenReturn(shuntTerminal); Mockito.when(shunt.getCurrentSectionCount()).thenReturn(currentSectionCount); Mockito.when(shunt.getMaximumSectionCount()).thenReturn(maximumSectionCount); - Mockito.when(shunt.getbPerSection()).thenReturn(bPerSection); Mockito.when(shunt.getProperty("qMax")).thenReturn(Double.toString(qMax)); + Mockito.when(shunt.getModelType()).thenReturn(ShuntCompensatorModelType.LINEAR); + Mockito.when(shunt.getModel()).thenReturn(shuntModel); + Mockito.when(shunt.getModel(ShuntCompensatorLinearModel.class)).thenReturn(shuntModel); } @Test