diff --git a/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/MergingVariantManager.java b/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/MergingVariantManager.java new file mode 100644 index 00000000000..13481512b06 --- /dev/null +++ b/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/MergingVariantManager.java @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2019, 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.commons.PowsyblException; +import com.powsybl.iidm.network.Network; +import com.powsybl.iidm.network.VariantManager; +import com.powsybl.iidm.network.VariantManagerConstants; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; + +/** + * @author Thomas Adam + */ +class MergingVariantManager implements VariantManager { + + private final MergingViewIndex index; + + private boolean allowVariantMultiThreadAccess = false; + + private String workingVariantId = VariantManagerConstants.INITIAL_VARIANT_ID; + + MergingVariantManager(final MergingViewIndex index) { + this.index = Objects.requireNonNull(index, "merging view index is null"); + } + + private Stream getVariantManagerStream() { + return index.getNetworkStream().map(Network::getVariantManager); + } + + @Override + public Collection getVariantIds() { + final VariantManager vm = getVariantManagerStream().findFirst().orElseThrow(() -> new PowsyblException("No VariantManager found")); + return vm.getVariantIds(); + } + + @Override + public String getWorkingVariantId() { + return workingVariantId; + } + + @Override + public void setWorkingVariant(String variantId) { + this.workingVariantId = variantId; + getVariantManagerStream().forEach(v -> v.setWorkingVariant(variantId)); + } + + @Override + public void allowVariantMultiThreadAccess(boolean allow) { + this.allowVariantMultiThreadAccess = allow; + getVariantManagerStream().forEach(v -> v.allowVariantMultiThreadAccess(allow)); + } + + @Override + public boolean isVariantMultiThreadAccessAllowed() { + return allowVariantMultiThreadAccess; + } + + // ------------------------------- + // Simple delegated methods ------ + // ------------------------------- + @Override + public void cloneVariant(String sourceVariantId, List targetVariantIds) { + cloneVariant(sourceVariantId, targetVariantIds, false); + } + + @Override + public void cloneVariant(String sourceVariantId, List targetVariantIds, boolean mayOverwrite) { + getVariantManagerStream().forEach(v -> v.cloneVariant(sourceVariantId, targetVariantIds, mayOverwrite)); + } + + @Override + public void cloneVariant(String sourceVariantId, String targetVariantId) { + cloneVariant(sourceVariantId, targetVariantId, false); + } + + @Override + public void cloneVariant(String sourceVariantId, String targetVariantId, boolean mayOverwrite) { + getVariantManagerStream().forEach(v -> v.cloneVariant(sourceVariantId, targetVariantId, mayOverwrite)); + } + + @Override + public void removeVariant(String variantId) { + getVariantManagerStream().forEach(v -> v.removeVariant(variantId)); + } +} diff --git a/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/MergingView.java b/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/MergingView.java index 4e0fa16423a..78568139378 100644 --- a/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/MergingView.java +++ b/iidm/iidm-mergingview/src/main/java/com/powsybl/iidm/mergingview/MergingView.java @@ -24,7 +24,7 @@ * @author Thomas Adam */ public final class MergingView implements Network { - public static final PowsyblException NOT_IMPLEMENTED_EXCEPTION = new PowsyblException("Not implemented exception"); + static final PowsyblException NOT_IMPLEMENTED_EXCEPTION = new PowsyblException("Not implemented exception"); private static final Logger LOGGER = LoggerFactory.getLogger(MergingView.class); @@ -137,11 +137,15 @@ public Collection getConnectedComponents() { private final BusViewAdapter busView; + /** Variant management for all merged networks */ + private final MergingVariantManager variantManager; + /** Constructor */ private MergingView(final NetworkFactory factory, final String id, final String format) { Objects.requireNonNull(factory, "factory is null"); index = new MergingViewIndex(this); + variantManager = new MergingVariantManager(index); busBreakerView = new BusBreakerViewAdapter(index); busView = new BusViewAdapter(index); // Working network will store view informations @@ -831,15 +835,14 @@ public > Collection getExtensions() { return workingNetwork.getExtensions(); } - // ------------------------------- - // Not implemented methods ------- - // ------------------------------- - @Override public VariantManager getVariantManager() { - throw NOT_IMPLEMENTED_EXCEPTION; + return variantManager; } + // ------------------------------- + // Not implemented methods ------- + // ------------------------------- @Override public LineAdder newLine() { throw NOT_IMPLEMENTED_EXCEPTION; diff --git a/iidm/iidm-mergingview/src/test/java/com/powsybl/iidm/mergingview/MergingNetworkTest.java b/iidm/iidm-mergingview/src/test/java/com/powsybl/iidm/mergingview/MergingNetworkTest.java index 53ec0cd50db..04f7357eb2a 100644 --- a/iidm/iidm-mergingview/src/test/java/com/powsybl/iidm/mergingview/MergingNetworkTest.java +++ b/iidm/iidm-mergingview/src/test/java/com/powsybl/iidm/mergingview/MergingNetworkTest.java @@ -193,7 +193,6 @@ public void testSetterGetter() { assertTrue(mergingView.getExtensions().isEmpty()); // Not implemented yet ! - TestUtil.notImplemented(mergingView::getVariantManager); // Lines TestUtil.notImplemented(mergingView::newLine); TestUtil.notImplemented(mergingView::newTieLine); diff --git a/iidm/iidm-mergingview/src/test/java/com/powsybl/iidm/mergingview/MultiVariantMergingViewTest.java b/iidm/iidm-mergingview/src/test/java/com/powsybl/iidm/mergingview/MultiVariantMergingViewTest.java new file mode 100644 index 00000000000..04e6c0445f8 --- /dev/null +++ b/iidm/iidm-mergingview/src/test/java/com/powsybl/iidm/mergingview/MultiVariantMergingViewTest.java @@ -0,0 +1,161 @@ +/** + * Copyright (c) 2019, 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.google.common.collect.Iterables; +import com.powsybl.iidm.network.*; +import com.powsybl.iidm.network.test.EurostagTutorialExample1Factory; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.*; + +/** + * + * @author Thomas Adam + */ +public class MultiVariantMergingViewTest { + + @Test + public void singleThreadTest() { + final MergingView mergingView = MergingView.create("SingleThreadTest", "iidm"); + mergingView.merge(EurostagTutorialExample1Factory.create()); + final VariantManager manager = mergingView.getVariantManager(); + manager.cloneVariant(VariantManagerConstants.INITIAL_VARIANT_ID, "SecondVariant"); + manager.setWorkingVariant("SecondVariant"); + final Generator generator = mergingView.getGenerator("GEN"); + generator.setVoltageRegulatorOn(false); + assertFalse(generator.isVoltageRegulatorOn()); + manager.setWorkingVariant(VariantManagerConstants.INITIAL_VARIANT_ID); + assertTrue(generator.isVoltageRegulatorOn()); + + assertEquals(2, manager.getVariantIds().size()); + manager.removeVariant("SecondVariant"); + assertEquals(1, manager.getVariantIds().size()); + + final List variantsToAdd = Arrays.asList("s1", "s2", "s3", "s4"); + manager.cloneVariant(VariantManagerConstants.INITIAL_VARIANT_ID, variantsToAdd); + assertEquals(variantsToAdd.size() + 1, manager.getVariantIds().size()); + } + + @Test + public void multiThreadTest() throws InterruptedException { + final MergingView mergingView = MergingView.create("MultiThreadTest", "iidm"); + mergingView.merge(EurostagTutorialExample1Factory.create()); + final VariantManager manager = mergingView.getVariantManager(); + manager.allowVariantMultiThreadAccess(true); + assertTrue(manager.isVariantMultiThreadAccessAllowed()); + + manager.cloneVariant(VariantManagerConstants.INITIAL_VARIANT_ID, "SecondVariant"); + + final Generator generator = mergingView.getGenerator("GEN"); + + manager.setWorkingVariant(VariantManagerConstants.INITIAL_VARIANT_ID); + generator.setVoltageRegulatorOn(true); + + manager.setWorkingVariant("SecondVariant"); + generator.setVoltageRegulatorOn(false); + + final boolean[] voltageRegulatorOnInitialVariant = new boolean[1]; + final boolean[] voltageRegulatorOnSecondVariant = new boolean[1]; + final CountDownLatch latch = new CountDownLatch(2); // to sync threads after having set the working variant + ExecutorService service = Executors.newFixedThreadPool(2); + service.invokeAll(Arrays.asList( + () -> { + manager.setWorkingVariant(VariantManagerConstants.INITIAL_VARIANT_ID); + latch.countDown(); + latch.await(); + voltageRegulatorOnInitialVariant[0] = generator.isVoltageRegulatorOn(); + return null; + }, + () -> { + manager.setWorkingVariant("SecondVariant"); + latch.countDown(); + latch.await(); + voltageRegulatorOnSecondVariant[0] = generator.isVoltageRegulatorOn(); + return null; + }) + ); + service.shutdown(); + service.awaitTermination(1, TimeUnit.MINUTES); + assertTrue(voltageRegulatorOnInitialVariant[0]); + assertFalse(voltageRegulatorOnSecondVariant[0]); + } + + @Test + public void multiVariantTopologyTest() throws InterruptedException { + final MergingView mergingView = MergingView.create("MultiVariantTopologyTest", "iidm"); + mergingView.merge(EurostagTutorialExample1Factory.create()); + final VariantManager manager = mergingView.getVariantManager(); + manager.cloneVariant(VariantManagerConstants.INITIAL_VARIANT_ID, "NEW_VARIANT"); + VoltageLevel vlload = mergingView.getVoltageLevel("VLLOAD"); + Bus nload = vlload.getBusBreakerView().getBus("NLOAD"); + Load newLoad = vlload.newLoad() + .setId("NEW_LOAD") + .setP0(10) + .setQ0(10) + .setBus("NLOAD") + .setConnectableBus("NLOAD") + .add(); + manager.setWorkingVariant("NEW_VARIANT"); + assertNotNull(newLoad.getTerminal().getBusBreakerView().getBus()); + assertEquals(2, Iterables.size(nload.getLoads())); + newLoad.getTerminal().disconnect(); + assertNull(newLoad.getTerminal().getBusBreakerView().getBus()); + assertEquals(2, Iterables.size(vlload.getLoads())); + assertEquals(1, Iterables.size(nload.getLoads())); + manager.setWorkingVariant(VariantManagerConstants.INITIAL_VARIANT_ID); + assertNotNull(newLoad.getTerminal().getBusBreakerView().getBus()); + assertEquals(2, Iterables.size(vlload.getLoads())); + assertEquals(2, Iterables.size(nload.getLoads())); + } + + @Test + public void variantNotSetTest() throws InterruptedException { + final MergingView mergingView = MergingView.create("VariantNotSetTest", "iidm"); + mergingView.merge(EurostagTutorialExample1Factory.create()); + final VariantManager manager = mergingView.getVariantManager(); + manager.allowVariantMultiThreadAccess(true); + assertEquals(VariantManagerConstants.INITIAL_VARIANT_ID, manager.getWorkingVariantId()); + ExecutorService service = Executors.newSingleThreadExecutor(); + service.submit(() -> { + try { + mergingView.getGenerator("GEN").getTargetP(); + fail(); + } catch (Exception ignored) { + } + }); + service.shutdown(); + service.awaitTermination(1, TimeUnit.MINUTES); + } + + @Test + public void variantSetTest() throws InterruptedException { + final MergingView mergingView = MergingView.create("VariantNotSetTest", "iidm"); + mergingView.merge(EurostagTutorialExample1Factory.create()); + final VariantManager manager = mergingView.getVariantManager(); + manager.allowVariantMultiThreadAccess(true); + assertEquals(VariantManagerConstants.INITIAL_VARIANT_ID, manager.getWorkingVariantId()); + ExecutorService service = Executors.newSingleThreadExecutor(); + service.submit(() -> { + try { + manager.setWorkingVariant(VariantManagerConstants.INITIAL_VARIANT_ID); + mergingView.getGenerator("GEN").getTargetP(); + } catch (Exception e) { + fail(); + } + }); + service.shutdown(); + service.awaitTermination(1, TimeUnit.MINUTES); + } +}