diff --git a/ampl-converter/src/main/java/com/powsybl/ampl/converter/util/NetworkUtil.java b/ampl-converter/src/main/java/com/powsybl/ampl/converter/util/NetworkUtil.java index d1081fbed80..a4a041c0689 100644 --- a/ampl-converter/src/main/java/com/powsybl/ampl/converter/util/NetworkUtil.java +++ b/ampl-converter/src/main/java/com/powsybl/ampl/converter/util/NetworkUtil.java @@ -7,9 +7,7 @@ */ package com.powsybl.ampl.converter.util; -import com.powsybl.iidm.network.Bus; -import com.powsybl.iidm.network.Terminal; -import com.powsybl.iidm.network.VoltageLevel; +import com.powsybl.iidm.network.*; import com.powsybl.iidm.network.extensions.SlackTerminal; /** diff --git a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/Branch.java b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/Branch.java index 20107ac6326..d24186fdc80 100644 --- a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/Branch.java +++ b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/Branch.java @@ -97,7 +97,6 @@ * * * - * * @author Geoffroy Jamgotchian {@literal } */ public interface Branch> extends Identifiable { diff --git a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/Network.java b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/Network.java index 8197882ca70..cd19d73ec72 100644 --- a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/Network.java +++ b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/Network.java @@ -761,6 +761,12 @@ default VoltageLevelAdder newVoltageLevel() { */ LineAdder newLine(); + /** + * Get a builder to create a new AC line by copying an existing one. + * @return a builder to create a new line + */ + LineAdder newLine(Line line); + /** * Get all AC lines. */ diff --git a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/OperationalLimitsGroup.java b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/OperationalLimitsGroup.java index 027d4072e36..c34a20cce89 100644 --- a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/OperationalLimitsGroup.java +++ b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/OperationalLimitsGroup.java @@ -9,6 +9,8 @@ package com.powsybl.iidm.network; import java.util.Optional; +import static com.powsybl.iidm.network.util.LoadingLimitsUtil.initializeFromLoadingLimits; + /** * @author Pauline Jean-Marie {@literal } */ @@ -28,6 +30,21 @@ public interface OperationalLimitsGroup { ApparentPowerLimitsAdder newApparentPowerLimits(); + default CurrentLimitsAdder newCurrentLimits(CurrentLimits currentLimits) { + CurrentLimitsAdder currentLimitsAdder = newCurrentLimits(); + return initializeFromLoadingLimits(currentLimitsAdder, currentLimits); + } + + default ActivePowerLimitsAdder newActivePowerLimits(ActivePowerLimits activePowerLimits) { + ActivePowerLimitsAdder activePowerLimitsAdder = newActivePowerLimits(); + return initializeFromLoadingLimits(activePowerLimitsAdder, activePowerLimits); + } + + default ApparentPowerLimitsAdder newApparentPowerLimits(ApparentPowerLimits apparentPowerLimits) { + ApparentPowerLimitsAdder apparentPowerLimitsAdder = newApparentPowerLimits(); + return initializeFromLoadingLimits(apparentPowerLimitsAdder, apparentPowerLimits); + } + void removeCurrentLimits(); void removeActivePowerLimits(); diff --git a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/util/LoadingLimitsUtil.java b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/util/LoadingLimitsUtil.java index 62e9c4cf9d3..ca75d5a8621 100644 --- a/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/util/LoadingLimitsUtil.java +++ b/iidm/iidm-api/src/main/java/com/powsybl/iidm/network/util/LoadingLimitsUtil.java @@ -7,8 +7,9 @@ */ package com.powsybl.iidm.network.util; -import com.powsybl.iidm.network.LoadingLimits; -import com.powsybl.iidm.network.LoadingLimitsAdder; +import com.powsybl.iidm.network.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Comparator; @@ -22,6 +23,8 @@ public final class LoadingLimitsUtil { private LoadingLimitsUtil() { } + private static final Logger LOGGER = LoggerFactory.getLogger(LoadingLimitsUtil.class); + /** * Interface for objects used to report the performed operation on limits when fixed by * {@link #fixMissingPermanentLimit(LoadingLimitsAdder, double, String, LimitFixLogger)}. @@ -96,6 +99,10 @@ public static > void * @param limits the limits to copy */ public static > A initializeFromLoadingLimits(A adder, L limits) { + if (limits == null) { + LOGGER.warn("Created adder is empty"); + return adder; + } adder.setPermanentLimit(limits.getPermanentLimit()); limits.getTemporaryLimits().forEach(limit -> adder.beginTemporaryLimit() diff --git a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/BranchUtil.java b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/BranchUtil.java index 76946450eb6..9f80dd77333 100644 --- a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/BranchUtil.java +++ b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/BranchUtil.java @@ -67,4 +67,15 @@ static int getOverloadDuration(Overload o1, Overload o2) { static double getValueForLimit(Terminal t, LimitType type) { return LimitViolationUtils.getValueForLimit(t, type); } + + static LineAdder fillLineAdder(LineAdder adder, Line line) { + return adder.setR(line.getR()) + .setX(line.getX()) + .setG1(line.getG1()) + .setG2(line.getG2()) + .setB1(line.getB1()) + .setB2(line.getB2()) + .setVoltageLevel1(line.getTerminal1().getVoltageLevel().getId()) + .setVoltageLevel2(line.getTerminal2().getVoltageLevel().getId()); + } } diff --git a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/LineAdderImpl.java b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/LineAdderImpl.java index aeeac6d7d60..7029ac21e1d 100644 --- a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/LineAdderImpl.java +++ b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/LineAdderImpl.java @@ -7,9 +7,7 @@ */ package com.powsybl.iidm.network.impl; -import com.powsybl.iidm.network.LineAdder; -import com.powsybl.iidm.network.ValidationException; -import com.powsybl.iidm.network.ValidationUtil; +import com.powsybl.iidm.network.*; import com.powsybl.commons.ref.Ref; /** @@ -20,6 +18,7 @@ class LineAdderImpl extends AbstractBranchAdder implements LineAd private final NetworkImpl network; private final String subnetwork; + private final Line copiedLine; private double r = Double.NaN; @@ -36,6 +35,13 @@ class LineAdderImpl extends AbstractBranchAdder implements LineAd LineAdderImpl(NetworkImpl network, String subnetwork) { this.network = network; this.subnetwork = subnetwork; + this.copiedLine = null; + } + + LineAdderImpl(NetworkImpl network, String subnetwork, Line copiedLine) { + this.network = network; + this.subnetwork = subnetwork; + this.copiedLine = copiedLine; } @Override @@ -110,6 +116,25 @@ public LineImpl add() { line.addTerminal(terminal1); line.addTerminal(terminal2); + if (copiedLine != null) { + copiedLine.getOperationalLimitsGroups1().forEach(groupToCopy -> { + OperationalLimitsGroup copy1 = line.newOperationalLimitsGroup1(groupToCopy.getId()); + groupToCopy.getCurrentLimits().ifPresent(limit -> copy1.newCurrentLimits(limit).add()); + groupToCopy.getActivePowerLimits().ifPresent(limit -> copy1.newActivePowerLimits(limit).add()); + groupToCopy.getApparentPowerLimits().ifPresent(limit -> copy1.newApparentPowerLimits(limit).add()); + }); + + copiedLine.getOperationalLimitsGroups2().forEach(groupToCopy -> { + OperationalLimitsGroup copy2 = line.newOperationalLimitsGroup2(groupToCopy.getId()); + groupToCopy.getCurrentLimits().ifPresent(limit -> copy2.newCurrentLimits(limit).add()); + groupToCopy.getActivePowerLimits().ifPresent(limit -> copy2.newActivePowerLimits(limit).add()); + groupToCopy.getApparentPowerLimits().ifPresent(limit -> copy2.newApparentPowerLimits(limit).add()); + }); + + copiedLine.getSelectedOperationalLimitsGroupId1().ifPresent(line::setSelectedOperationalLimitsGroup1); + copiedLine.getSelectedOperationalLimitsGroupId2().ifPresent(line::setSelectedOperationalLimitsGroup2); + } + // check that the line is attachable on both side voltageLevel1.getTopologyModel().attach(terminal1, true); voltageLevel2.getTopologyModel().attach(terminal2, true); diff --git a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/NetworkImpl.java b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/NetworkImpl.java index 31c25e9d926..9ed7bb5934c 100644 --- a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/NetworkImpl.java +++ b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/NetworkImpl.java @@ -356,13 +356,23 @@ public VoltageLevelExt getVoltageLevel(String id) { @Override public LineAdderImpl newLine() { - return newLine(null); + return newLine((String) null); } LineAdderImpl newLine(String subnetwork) { return new LineAdderImpl(this, subnetwork); } + @Override + public LineAdderImpl newLine(Line line) { + return newLine(null, line); + } + + LineAdderImpl newLine(String subnetwork, Line line) { + LineAdderImpl lineAdder = new LineAdderImpl(this, subnetwork, line); + return (LineAdderImpl) BranchUtil.fillLineAdder(lineAdder, line); + } + @Override public Iterable getLines() { return Collections.unmodifiableCollection(index.getAll(LineImpl.class)); diff --git a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/SubnetworkImpl.java b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/SubnetworkImpl.java index 52c0cfa5eb5..afd91472ec6 100644 --- a/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/SubnetworkImpl.java +++ b/iidm/iidm-impl/src/main/java/com/powsybl/iidm/network/impl/SubnetworkImpl.java @@ -232,6 +232,11 @@ public LineAdder newLine() { return getNetwork().newLine(id); } + @Override + public LineAdder newLine(Line line) { + return getNetwork().newLine(id, line); + } + @Override public Iterable getLines() { return getLineStream().toList(); diff --git a/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractCurrentLimitsTest.java b/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractCurrentLimitsTest.java index 88bdb4f4dc1..dfa8444a8c6 100644 --- a/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractCurrentLimitsTest.java +++ b/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractCurrentLimitsTest.java @@ -738,6 +738,7 @@ public void testAdderByCopy() { adder.add(); assertTrue(areLimitsIdentical(limits1, limits2)); + assertFalse(line.newCurrentLimits1(null).hasTemporaryLimits()); } @Test diff --git a/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractLineTest.java b/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractLineTest.java index ee02a53a38d..322764fb084 100644 --- a/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractLineTest.java +++ b/iidm/iidm-tck/src/test/java/com/powsybl/iidm/network/tck/AbstractLineTest.java @@ -20,6 +20,7 @@ import org.mockito.Mockito; import java.util.Collection; +import java.util.Objects; import java.util.Optional; import java.util.stream.Stream; @@ -41,6 +42,22 @@ public abstract class AbstractLineTest { private VoltageLevel voltageLevelA; private VoltageLevel voltageLevelB; + public boolean areLinesIdentical(Line line1, Line line2) { + boolean areIdentical = false; + + if (line1 != null && line2 != null) { + areIdentical = line1.getR() == line2.getR() + && line1.getX() == line2.getX() + && line1.getG1() == line2.getG1() + && line1.getG2() == line2.getG2() + && line1.getB1() == line2.getB1() + && line1.getB2() == line2.getB2() + && Objects.equals(line1.getTerminal1().getVoltageLevel().getId(), line2.getTerminal1().getVoltageLevel().getId()) + && Objects.equals(line1.getTerminal2().getVoltageLevel().getId(), line2.getTerminal2().getVoltageLevel().getId()); + } + return areIdentical; + } + @BeforeEach public void setUp() { network = NoEquipmentNetworkFactory.create(); @@ -181,6 +198,81 @@ public void testDefaultLine() { assertSame(voltageLevelB, acLine.getTerminal2().getVoltageLevel()); } + @Test + public void testLineCopier() { + // First limit normally created + LineAdder acLineAdder1 = network.newLine() + .setId("line1") + .setName(LINE_NAME) + .setR(1.0) + .setX(2.0) + .setG1(3.0) + .setG2(3.5) + .setB1(4.0) + .setB2(4.5) + .setVoltageLevel1("vl1") + .setVoltageLevel2("vl2") + .setBus1("busA") + .setBus2("busB") + .setConnectableBus1("busA") + .setConnectableBus2("busB"); + acLineAdder1.add(); + Line acLine1 = network.getLine("line1"); + // Group and limits creation 1 + acLine1.newOperationalLimitsGroup1("group1").newCurrentLimits().setPermanentLimit(220.0).add(); + acLine1.setSelectedOperationalLimitsGroup1("group1"); + Optional optionalLimits1 = acLine1.getCurrentLimits1(); + assertTrue(optionalLimits1.isPresent()); + CurrentLimits limits1 = optionalLimits1.get(); + assertNotNull(limits1); + + acLine1.getOperationalLimitsGroup1("group1").get().newActivePowerLimits().setPermanentLimit(220.0).add(); + acLine1.setSelectedOperationalLimitsGroup1("group1"); + Optional optionalActivePowerLimits1 = acLine1.getActivePowerLimits1(); + assertTrue(optionalActivePowerLimits1.isPresent()); + ActivePowerLimits activePowerLimits1 = optionalActivePowerLimits1.get(); + assertNotNull(activePowerLimits1); + + acLine1.getOperationalLimitsGroup1("group1").get().newApparentPowerLimits().setPermanentLimit(220.0).add(); + acLine1.setSelectedOperationalLimitsGroup1("group1"); + Optional optionalApparentPowerLimits1 = acLine1.getApparentPowerLimits1(); + assertTrue(optionalApparentPowerLimits1.isPresent()); + ApparentPowerLimits apparentPowerLimits1 = optionalApparentPowerLimits1.get(); + assertNotNull(apparentPowerLimits1); + + // Group and limit creation 2 + acLine1.newOperationalLimitsGroup2("group2").newCurrentLimits().setPermanentLimit(80.0).add(); + acLine1.setSelectedOperationalLimitsGroup2("group2"); + Optional optionalLimits2 = acLine1.getCurrentLimits2(); + assertTrue(optionalLimits2.isPresent()); + CurrentLimits limits2 = optionalLimits2.get(); + assertNotNull(limits2); + + // Second limit created by copy + LineAdder acLineAdder2 = network.newLine(acLine1); + acLineAdder2 + .setId("line2") + .setName(LINE_NAME) + .setBus1("busA") + .setBus2("busB") + .setConnectableBus1("busA") + .setConnectableBus2("busB"); + acLineAdder2.add(); + Line acLine2 = network.getLine("line2"); + // Limits check to set up test + Optional optionalLimits3 = acLine2.getCurrentLimits1(); + assertTrue(optionalLimits3.isPresent()); + CurrentLimits limits3 = optionalLimits3.get(); + + // Tests + assertNotNull(acLine2); + assertTrue(areLinesIdentical(acLine1, acLine2)); + assertEquals(limits1.getPermanentLimit(), limits3.getPermanentLimit()); + assertNotNull(acLine2.getOperationalLimitsGroup2("group2")); + assertEquals(acLine1.getSelectedOperationalLimitsGroupId2(), acLine2.getSelectedOperationalLimitsGroupId2()); + + } + @Test public void testMove1Bb() { Line line = createLineBetweenVoltageAB("line", LINE_NAME, 1.0, 2.0, 3.0, 3.5, 4.0, 4.5);