diff --git a/action/action-dsl/src/main/groovy/eu/itesla_project/action/dsl/ActionDslLoader.groovy b/action/action-dsl/src/main/groovy/eu/itesla_project/action/dsl/ActionDslLoader.groovy index 390d66b3..da1ee314 100644 --- a/action/action-dsl/src/main/groovy/eu/itesla_project/action/dsl/ActionDslLoader.groovy +++ b/action/action-dsl/src/main/groovy/eu/itesla_project/action/dsl/ActionDslLoader.groovy @@ -9,9 +9,11 @@ package eu.itesla_project.action.dsl import eu.itesla_project.action.dsl.ast.ExpressionNode import eu.itesla_project.action.dsl.spi.DslTaskExtension import eu.itesla_project.contingency.BranchContingency +import eu.itesla_project.contingency.BusbarSectionContingency import eu.itesla_project.contingency.ContingencyImpl import eu.itesla_project.contingency.GeneratorContingency import eu.itesla_project.contingency.tasks.ModificationTask +import eu.itesla_project.iidm.network.BusbarSection import eu.itesla_project.iidm.network.Generator import eu.itesla_project.iidm.network.Identifiable import eu.itesla_project.iidm.network.Line @@ -129,6 +131,8 @@ class ActionDslLoader extends DslLoader { elements.add(new BranchContingency(equipment)) } else if (identifiable instanceof Generator) { elements.add(new GeneratorContingency(equipment)) + } else if (identifiable instanceof BusbarSection) { + elements.add(new BusbarSectionContingency(equipment)) } else { throw new ActionDslException("Equipment type " + identifiable.getClass().name + " not supported in contingencies") } diff --git a/afs/afs-core/src/main/java/eu/itesla_project/afs/core/AppData.java b/afs/afs-core/src/main/java/eu/itesla_project/afs/core/AppData.java index 3550031a..33743374 100644 --- a/afs/afs-core/src/main/java/eu/itesla_project/afs/core/AppData.java +++ b/afs/afs-core/src/main/java/eu/itesla_project/afs/core/AppData.java @@ -6,6 +6,7 @@ */ package eu.itesla_project.afs.core; +import eu.itesla_project.afs.storage.AppFileSystemStorage; import eu.itesla_project.commons.util.ServiceLoaderCache; import eu.itesla_project.computation.ComputationManager; import eu.itesla_project.computation.local.LocalComputationManager; @@ -13,6 +14,7 @@ import eu.itesla_project.iidm.import_.ImportersServiceLoader; import java.util.*; +import java.util.stream.Collectors; /** * @author Geoffroy Jamgotchian @@ -101,7 +103,7 @@ public Set> getProjectFileClasses() { return projectFileClasses; } - public FileExtension getFileExtension(Class fileClass) { + FileExtension getFileExtension(Class fileClass) { Objects.requireNonNull(fileClass); FileExtension extension = fileExtensions.get(fileClass); if (extension == null) { @@ -110,7 +112,7 @@ public FileExtension getFileExtension(Class fileClass) { return extension; } - public FileExtension getFileExtensionByPseudoClass(String filePseudoClass) { + FileExtension getFileExtensionByPseudoClass(String filePseudoClass) { Objects.requireNonNull(filePseudoClass); FileExtension extension = fileExtensionsByPseudoClass.get(filePseudoClass); if (extension == null) { @@ -119,7 +121,7 @@ public FileExtension getFileExtensionByPseudoClass(String filePseudoClass) { return extension; } - public ProjectFileExtension getProjectFileExtension(Class projectFileOrProjectFileBuilderClass) { + ProjectFileExtension getProjectFileExtension(Class projectFileOrProjectFileBuilderClass) { Objects.requireNonNull(projectFileOrProjectFileBuilderClass); ProjectFileExtension extension = projectFileExtensions.get(projectFileOrProjectFileBuilderClass); if (extension == null) { @@ -129,7 +131,7 @@ public ProjectFileExtension getProjectFileExtension(Class projectFileOrProjec return extension; } - public ProjectFileExtension getProjectFileExtensionByPseudoClass(String projectFilePseudoClass) { + ProjectFileExtension getProjectFileExtensionByPseudoClass(String projectFilePseudoClass) { Objects.requireNonNull(projectFilePseudoClass); ProjectFileExtension extension = projectFileExtensionsByPseudoClass.get(projectFilePseudoClass); if (extension == null) { @@ -147,6 +149,19 @@ public ComputationManager getComputationManager() { return computationManager; } + public List getRemotelyAccessibleFileSystemNames() { + return fileSystems.entrySet().stream() + .map(Map.Entry::getValue) + .filter(AppFileSystem::isRemotelyAccessible) + .map(AppFileSystem::getName) + .collect(Collectors.toList()); + } + + public AppFileSystemStorage getRemotelyAccessibleStorage(String fileSystemName) { + AppFileSystem afs = fileSystems.get(fileSystemName); + return afs != null ? afs.getStorage() : null; + } + @Override public void close() throws Exception { getFileSystems().forEach(AppFileSystem::close); diff --git a/afs/afs-core/src/main/java/eu/itesla_project/afs/core/AppFileSystem.java b/afs/afs-core/src/main/java/eu/itesla_project/afs/core/AppFileSystem.java index 588c3089..402f3fb6 100644 --- a/afs/afs-core/src/main/java/eu/itesla_project/afs/core/AppFileSystem.java +++ b/afs/afs-core/src/main/java/eu/itesla_project/afs/core/AppFileSystem.java @@ -21,12 +21,15 @@ public class AppFileSystem implements AutoCloseable { private final String name; + private final boolean remotelyAccessible; + private final AppFileSystemStorage storage; private AppData data; - public AppFileSystem(String name, AppFileSystemStorage storage) { + public AppFileSystem(String name, boolean remotelyAccessible, AppFileSystemStorage storage) { this.name = Objects.requireNonNull(name); + this.remotelyAccessible = remotelyAccessible; this.storage = Objects.requireNonNull(storage); } @@ -34,6 +37,14 @@ public String getName() { return name; } + public boolean isRemotelyAccessible() { + return remotelyAccessible; + } + + AppFileSystemStorage getStorage() { + return storage; + } + public Folder getRootFolder() { return new Folder(storage.getRootNode(), storage, this); } diff --git a/afs/afs-core/src/main/java/eu/itesla_project/afs/core/ProjectNode.java b/afs/afs-core/src/main/java/eu/itesla_project/afs/core/ProjectNode.java index 47f1c08b..1be9fbac 100644 --- a/afs/afs-core/src/main/java/eu/itesla_project/afs/core/ProjectNode.java +++ b/afs/afs-core/src/main/java/eu/itesla_project/afs/core/ProjectNode.java @@ -48,6 +48,11 @@ public Project getProject() { return new Project(projectId, storage, fileSystem); } + public void moveTo(ProjectFolder folder) { + Objects.requireNonNull(folder); + storage.setParentNode(id, folder.id); + } + public void delete() { storage.deleteNode(id); } diff --git a/afs/afs-core/src/test/java/eu/itesla_project/afs/core/AbstractProjectFileTest.java b/afs/afs-core/src/test/java/eu/itesla_project/afs/core/AbstractProjectFileTest.java index 078751da..be557aff 100644 --- a/afs/afs-core/src/test/java/eu/itesla_project/afs/core/AbstractProjectFileTest.java +++ b/afs/afs-core/src/test/java/eu/itesla_project/afs/core/AbstractProjectFileTest.java @@ -54,7 +54,7 @@ public void setup() throws IOException { ImportersLoader importersLoader = new ImportersLoaderList(getImporters(), Collections.emptyList()); ComputationManager computationManager = Mockito.mock(ComputationManager.class); storage = createStorage(); - afs = new AppFileSystem("mem", storage); + afs = new AppFileSystem("mem", false, storage); ad = new AppData(computationManager, importersLoader, Collections.singletonList(computationManager1 -> Collections.singletonList(afs)), diff --git a/afs/afs-core/src/test/java/eu/itesla_project/afs/core/AfsBaseTest.java b/afs/afs-core/src/test/java/eu/itesla_project/afs/core/AfsBaseTest.java index 2baf5934..8e03c246 100644 --- a/afs/afs-core/src/test/java/eu/itesla_project/afs/core/AfsBaseTest.java +++ b/afs/afs-core/src/test/java/eu/itesla_project/afs/core/AfsBaseTest.java @@ -7,9 +7,9 @@ package eu.itesla_project.afs.core; import com.google.common.collect.ImmutableList; +import eu.itesla_project.afs.mapdb.storage.MapDbAppFileSystemStorage; import eu.itesla_project.afs.storage.AppFileSystemStorage; import eu.itesla_project.afs.storage.NodeId; -import eu.itesla_project.afs.mapdb.storage.MapDbAppFileSystemStorage; import eu.itesla_project.computation.ComputationManager; import eu.itesla_project.iidm.import_.ImportersLoader; import eu.itesla_project.iidm.import_.ImportersLoaderList; @@ -29,6 +29,69 @@ */ public class AfsBaseTest { + private static class FooFile extends ProjectFile { + + private FooFile(NodeId id, AppFileSystemStorage storage, NodeId projectId, AppFileSystem fileSystem) { + super(id, storage, projectId, fileSystem); + } + + @Override + public FileIcon getIcon() { + return new FileIcon("?", new byte[]{}); + } + } + + private static class FooFileBuilder implements ProjectFileBuilder { + + private final NodeId folderId; + + private final AppFileSystemStorage storage; + + private final NodeId projectId; + + private final AppFileSystem fileSystem; + + private FooFileBuilder(NodeId folderId, AppFileSystemStorage storage, NodeId projectId, AppFileSystem fileSystem) { + this.folderId = folderId; + this.storage = storage; + this.projectId = projectId; + this.fileSystem = fileSystem; + } + + @Override + public FooFile build() { + NodeId id = storage.createNode(folderId, "foo", "foo"); + return new FooFile(id, storage, projectId, fileSystem); + } + } + + private static class FooFileExtension implements ProjectFileExtension { + @Override + public Class getProjectFileClass() { + return FooFile.class; + } + + @Override + public String getProjectFilePseudoClass() { + return "foo"; + } + + @Override + public Class> getProjectFileBuilderClass() { + return FooFileBuilder.class; + } + + @Override + public FooFile createProjectFile(NodeId id, AppFileSystemStorage storage, NodeId projectId, AppFileSystem fileSystem) { + return new FooFile(id, storage, projectId, fileSystem); + } + + @Override + public FooFileBuilder createProjectFileBuilder(NodeId folderId, AppFileSystemStorage storage, NodeId projectId, AppFileSystem fileSystem) { + return new FooFileBuilder(folderId, storage, projectId, fileSystem); + } + } + private AppFileSystemStorage storage; private AppFileSystem afs; @@ -46,9 +109,9 @@ public void setup() throws IOException { ImportersLoader importersLoader = new ImportersLoaderList(Collections.emptyList(), Collections.emptyList()); ComputationManager computationManager = Mockito.mock(ComputationManager.class); - afs = new AppFileSystem("mem", storage); + afs = new AppFileSystem("mem", true, storage); ad = new AppData(computationManager, importersLoader, Collections.singletonList(computationManager1 -> Collections.singletonList(afs)), - Collections.emptyList(), Collections.emptyList()); + Collections.emptyList(), Collections.singletonList(new FooFileExtension())); } @After @@ -57,11 +120,13 @@ public void tearDown() throws Exception { } @Test - public void test() throws IOException { + public void baseTest() throws IOException { assertSame(afs, ad.getFileSystem("mem")); assertNull(ad.getFileSystem("???")); + assertEquals(Collections.singletonList("mem"), ad.getRemotelyAccessibleFileSystemNames()); + assertNotNull(ad.getRemotelyAccessibleStorage("mem")); assertEquals("mem", afs.getName()); - assertTrue(ad.getProjectFileClasses().isEmpty()); // no plugin + assertEquals(1, ad.getProjectFileClasses().size()); Folder root = afs.getRootFolder(); assertNotNull(root); Folder dir1 = (Folder) root.getChild("dir1"); @@ -119,4 +184,20 @@ public void test() throws IOException { assertEquals("dir6", project1.getRootFolder().getChild("dir5/dir6").getName()); } + @Test + public void moveToTest() throws IOException { + Project project = afs.getRootFolder().createProject("test", ""); + ProjectFolder test1 = project.getRootFolder().createFolder("test1"); + ProjectFolder test2 = project.getRootFolder().createFolder("test2"); + FooFile file = test1.fileBuilder(FooFileBuilder.class) + .build(); + assertEquals(test1.getId(), file.getFolder().getId()); + assertEquals(1, test1.getChildren().size()); + assertTrue(test2.getChildren().isEmpty()); + file.moveTo(test2); + assertEquals(test2.getId(), file.getFolder().getId()); + assertTrue(test1.getChildren().isEmpty()); + assertEquals(1, test2.getChildren().size()); + } + } \ No newline at end of file diff --git a/afs/afs-core/src/test/java/eu/itesla_project/afs/core/AppFileSystemToolTest.java b/afs/afs-core/src/test/java/eu/itesla_project/afs/core/AppFileSystemToolTest.java index 145f6ae3..abaec733 100644 --- a/afs/afs-core/src/test/java/eu/itesla_project/afs/core/AppFileSystemToolTest.java +++ b/afs/afs-core/src/test/java/eu/itesla_project/afs/core/AppFileSystemToolTest.java @@ -37,7 +37,7 @@ public AppFileSystemToolTest() { @Override protected AppData createAppData() { AppFileSystemStorage storage = MapDbAppFileSystemStorage.createHeap("mem"); - AppFileSystem afs = new AppFileSystem("mem", storage); + AppFileSystem afs = new AppFileSystem("mem", false, storage); AppData appData = new AppData(computationManager, importersLoader, Collections.singletonList(computationManager1 -> Collections.singletonList(afs)), Collections.emptyList(), Collections.emptyList()); afs.getRootFolder().createProject("test_project1", ""); diff --git a/afs/afs-local/src/main/java/eu/itesla_project/afs/local/LocalAppFileSystem.java b/afs/afs-local/src/main/java/eu/itesla_project/afs/local/LocalAppFileSystem.java index e854b66b..6448099d 100644 --- a/afs/afs-local/src/main/java/eu/itesla_project/afs/local/LocalAppFileSystem.java +++ b/afs/afs-local/src/main/java/eu/itesla_project/afs/local/LocalAppFileSystem.java @@ -21,6 +21,7 @@ public class LocalAppFileSystem extends AppFileSystem { public LocalAppFileSystem(LocalAppFileSystemConfig config, ComputationManager computationManager, ImportConfig importConfig, ImportersLoader importersLoader) { super(config.getDriveName(), - new LocalAppFileSystemStorage(config.getRootDir(), config.getDriveName(), computationManager, importConfig, importersLoader)); + config.isRemotelyAccessible(), + new LocalAppFileSystemStorage(config.getRootDir(), config.getDriveName(), computationManager, importConfig, importersLoader)); } } \ No newline at end of file diff --git a/afs/afs-local/src/main/java/eu/itesla_project/afs/local/LocalAppFileSystemConfig.java b/afs/afs-local/src/main/java/eu/itesla_project/afs/local/LocalAppFileSystemConfig.java index e4529558..c4437cac 100644 --- a/afs/afs-local/src/main/java/eu/itesla_project/afs/local/LocalAppFileSystemConfig.java +++ b/afs/afs-local/src/main/java/eu/itesla_project/afs/local/LocalAppFileSystemConfig.java @@ -7,6 +7,7 @@ package eu.itesla_project.afs.local; import eu.itesla_project.afs.core.AfsException; +import eu.itesla_project.afs.storage.AbstractAppFileSystemConfig; import eu.itesla_project.commons.config.ModuleConfig; import eu.itesla_project.commons.config.PlatformConfig; @@ -19,9 +20,7 @@ /** * @author Geoffroy Jamgotchian */ -public class LocalAppFileSystemConfig { - - private String driveName; +public class LocalAppFileSystemConfig extends AbstractAppFileSystemConfig { private Path rootDir; @@ -33,17 +32,21 @@ public static List load(PlatformConfig platformConfig) List configs = new ArrayList<>(); ModuleConfig moduleConfig = platformConfig.getModuleConfigIfExists("local-app-file-system"); if (moduleConfig != null) { - if (moduleConfig.hasProperty("drive-name") && moduleConfig.hasProperty("root-dir")) { + if (moduleConfig.hasProperty("drive-name") + && moduleConfig.hasProperty("root-dir")) { String driveName = moduleConfig.getStringProperty("drive-name"); + boolean remotelyAccessible = moduleConfig.getBooleanProperty("remotely-accessible", DEFAULT_REMOTELY_ACCESSIBLE); Path rootDir = moduleConfig.getPathProperty("root-dir"); - configs.add(new LocalAppFileSystemConfig(driveName, rootDir)); + configs.add(new LocalAppFileSystemConfig(driveName, remotelyAccessible, rootDir)); } int maxAdditionalDriveCount = moduleConfig.getIntProperty("max-additional-drive-count", 0); for (int i = 0; i < maxAdditionalDriveCount; i++) { - if (moduleConfig.hasProperty("drive-name-" + i) && moduleConfig.hasProperty("root-dir-" + i)) { + if (moduleConfig.hasProperty("drive-name-" + i) + && moduleConfig.hasProperty("root-dir-" + i)) { String driveName = moduleConfig.getStringProperty("drive-name-" + i); + boolean remotelyAccessible = moduleConfig.getBooleanProperty("remotely-accessible-" + i, DEFAULT_REMOTELY_ACCESSIBLE); Path rootDir = moduleConfig.getPathProperty("root-dir-" + i); - configs.add(new LocalAppFileSystemConfig(driveName, rootDir)); + configs.add(new LocalAppFileSystemConfig(driveName, remotelyAccessible, rootDir)); } } } @@ -58,20 +61,11 @@ private static Path checkRootDir(Path rootDir) { return rootDir; } - public LocalAppFileSystemConfig(String driveName, Path rootDir) { - this.driveName = Objects.requireNonNull(driveName); + public LocalAppFileSystemConfig(String driveName, boolean remotelyAccessible, Path rootDir) { + super(driveName, remotelyAccessible); this.rootDir = checkRootDir(rootDir).toAbsolutePath(); } - public String getDriveName() { - return driveName; - } - - public LocalAppFileSystemConfig setDriveName(String driveName) { - this.driveName = Objects.requireNonNull(driveName); - return this; - } - public Path getRootDir() { return rootDir; } diff --git a/afs/afs-local/src/main/java/eu/itesla_project/afs/local/storage/LocalAppFileSystemStorage.java b/afs/afs-local/src/main/java/eu/itesla_project/afs/local/storage/LocalAppFileSystemStorage.java index d0c9a947..ec659e48 100644 --- a/afs/afs-local/src/main/java/eu/itesla_project/afs/local/storage/LocalAppFileSystemStorage.java +++ b/afs/afs-local/src/main/java/eu/itesla_project/afs/local/storage/LocalAppFileSystemStorage.java @@ -130,6 +130,11 @@ public NodeId getParentNode(NodeId nodeId) { return path.equals(rootDir) ? null : new PathNodeId(path.getParent()); } + @Override + public void setParentNode(NodeId nodeId, NodeId newParentNodeId) { + throw new AssertionError(); + } + @Override public boolean isWritable(NodeId nodeId) { return false; diff --git a/afs/afs-local/src/test/java/eu/itesla_project/afs/local/LocalAppFileSystemConfigTest.java b/afs/afs-local/src/test/java/eu/itesla_project/afs/local/LocalAppFileSystemConfigTest.java index bb2d267f..5e3642d3 100644 --- a/afs/afs-local/src/test/java/eu/itesla_project/afs/local/LocalAppFileSystemConfigTest.java +++ b/afs/afs-local/src/test/java/eu/itesla_project/afs/local/LocalAppFileSystemConfigTest.java @@ -18,8 +18,7 @@ import java.nio.file.Files; import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; /** * @author Geoffroy Jamgotchian @@ -41,6 +40,7 @@ public void setUp() throws Exception { moduleConfig.setPathProperty("root-dir", fileSystem.getPath("/work")); moduleConfig.setStringProperty("max-additional-drive-count", "2"); moduleConfig.setStringProperty("drive-name-1", "local1"); + moduleConfig.setStringProperty("remotely-accessible-1", "true"); moduleConfig.setPathProperty("root-dir-1", fileSystem.getPath("/work")); } @@ -56,8 +56,10 @@ public void loadTest() { LocalAppFileSystemConfig config = configs.get(0); LocalAppFileSystemConfig config1 = configs.get(1); assertEquals("local", config.getDriveName()); + assertFalse(config.isRemotelyAccessible()); assertEquals(fileSystem.getPath("/work"), config.getRootDir()); assertEquals("local1", config1.getDriveName()); + assertTrue(config1.isRemotelyAccessible()); assertEquals(fileSystem.getPath("/work"), config1.getRootDir()); config.setDriveName("local2"); config.setRootDir(fileSystem.getPath("/tmp")); diff --git a/afs/afs-local/src/test/java/eu/itesla_project/afs/local/LocalAppFileSystemProviderTest.java b/afs/afs-local/src/test/java/eu/itesla_project/afs/local/LocalAppFileSystemProviderTest.java index fbb55309..4e7cecd2 100644 --- a/afs/afs-local/src/test/java/eu/itesla_project/afs/local/LocalAppFileSystemProviderTest.java +++ b/afs/afs-local/src/test/java/eu/itesla_project/afs/local/LocalAppFileSystemProviderTest.java @@ -44,7 +44,7 @@ public void tearDown() throws Exception { @Test public void test() { ComputationManager computationManager = Mockito.mock(ComputationManager.class); - LocalAppFileSystemConfig config = new LocalAppFileSystemConfig("drive", fileSystem.getPath("/work")); + LocalAppFileSystemConfig config = new LocalAppFileSystemConfig("drive", true, fileSystem.getPath("/work")); List fileSystems = new LocalAppFileSystemProvider(Collections.singletonList(config), new ImportConfig(), new ImportersLoaderList(Collections.emptyList(), Collections.emptyList())) @@ -52,5 +52,6 @@ public void test() { assertEquals(1, fileSystems.size()); assertTrue(fileSystems.get(0) instanceof LocalAppFileSystem); assertEquals("drive", fileSystems.get(0).getName()); + assertTrue(fileSystems.get(0).isRemotelyAccessible()); } } \ No newline at end of file diff --git a/afs/afs-mapdb-storage/src/main/java/eu/itesla_project/afs/mapdb/storage/MapDbAppFileSystemStorage.java b/afs/afs-mapdb-storage/src/main/java/eu/itesla_project/afs/mapdb/storage/MapDbAppFileSystemStorage.java index ab7cedc0..4e04b985 100644 --- a/afs/afs-mapdb-storage/src/main/java/eu/itesla_project/afs/mapdb/storage/MapDbAppFileSystemStorage.java +++ b/afs/afs-mapdb-storage/src/main/java/eu/itesla_project/afs/mapdb/storage/MapDbAppFileSystemStorage.java @@ -279,11 +279,38 @@ public NodeId getChildNode(NodeId parentNodeId, String name) { public NodeId getParentNode(NodeId nodeId) { Objects.requireNonNull(nodeId); if (!nodeNameMap.containsKey(nodeId)) { - throw new AfsStorageException("Parent node " + nodeId + " not found"); + throw new AfsStorageException("Node " + nodeId + " not found"); } return parentNodeMap.get(nodeId); } + @Override + public void setParentNode(NodeId nodeId, NodeId newParentNodeId) { + Objects.requireNonNull(nodeId); + Objects.requireNonNull(newParentNodeId); + if (!nodeNameMap.containsKey(nodeId)) { + throw new AfsStorageException("Node " + nodeId + " not found"); + } + if (!nodeNameMap.containsKey(newParentNodeId)) { + throw new AfsStorageException("New parent node " + newParentNodeId+ " not found"); + } + NodeId oldParentNodeId = parentNodeMap.get(nodeId); + if (oldParentNodeId == null) { + throw new AfsStorageException("Cannot change parent of root folder"); + } + + parentNodeMap.put(nodeId, newParentNodeId); + + // remove from old parent + String name = nodeNameMap.get(nodeId); + childNodeMap.remove(new NamedLink(oldParentNodeId, name)); + childNodesMap.put(oldParentNodeId, remove(childNodesMap.get(oldParentNodeId), nodeId)); + + // add to new parent + childNodesMap.put(newParentNodeId, add(childNodesMap.get(newParentNodeId), nodeId)); + childNodeMap.put(new NamedLink(newParentNodeId, name), nodeId); + } + @Override public boolean isWritable(NodeId nodeId) { return true; diff --git a/afs/afs-mapdb/src/main/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystem.java b/afs/afs-mapdb/src/main/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystem.java index afbdce83..f6896889 100644 --- a/afs/afs-mapdb/src/main/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystem.java +++ b/afs/afs-mapdb/src/main/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystem.java @@ -9,19 +9,12 @@ import eu.itesla_project.afs.core.AppFileSystem; import eu.itesla_project.afs.mapdb.storage.MapDbAppFileSystemStorage; -import java.nio.file.Path; -import java.util.Objects; -import java.util.function.BiFunction; - /** * @author Geoffroy Jamgotchian */ public class MapDbAppFileSystem extends AppFileSystem { - public MapDbAppFileSystem(MapDbAppFileSystemConfig config, - BiFunction storageProvider) { - super(Objects.requireNonNull(config).getDriveName(), - Objects.requireNonNull(storageProvider).apply(config.getDriveName(), - config.getDbFile())); + public MapDbAppFileSystem(String driveName, boolean remotelyAccessible, MapDbAppFileSystemStorage storage) { + super(driveName, remotelyAccessible, storage); } } diff --git a/afs/afs-mapdb/src/main/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystemConfig.java b/afs/afs-mapdb/src/main/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystemConfig.java index 9f19f7cd..7d650e95 100644 --- a/afs/afs-mapdb/src/main/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystemConfig.java +++ b/afs/afs-mapdb/src/main/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystemConfig.java @@ -7,6 +7,7 @@ package eu.itesla_project.afs.mapdb; import eu.itesla_project.afs.core.AfsException; +import eu.itesla_project.afs.storage.AbstractAppFileSystemConfig; import eu.itesla_project.commons.config.ModuleConfig; import eu.itesla_project.commons.config.PlatformConfig; @@ -19,9 +20,7 @@ /** * @author Geoffroy Jamgotchian */ -public class MapDbAppFileSystemConfig { - - private String driveName; +public class MapDbAppFileSystemConfig extends AbstractAppFileSystemConfig { private Path dbFile; @@ -33,17 +32,21 @@ public static List load(PlatformConfig platformConfig) List configs = new ArrayList<>(); ModuleConfig moduleConfig = platformConfig.getModuleConfigIfExists("mapdb-app-file-system"); if (moduleConfig != null) { - if (moduleConfig.hasProperty("drive-name") && moduleConfig.hasProperty("db-file")) { + if (moduleConfig.hasProperty("drive-name") + && moduleConfig.hasProperty("db-file")) { String driveName = moduleConfig.getStringProperty("drive-name"); + boolean remotelyAccessible = moduleConfig.getBooleanProperty("remotely-accessible", DEFAULT_REMOTELY_ACCESSIBLE); Path rootDir = moduleConfig.getPathProperty("db-file"); - configs.add(new MapDbAppFileSystemConfig(driveName, rootDir)); + configs.add(new MapDbAppFileSystemConfig(driveName, remotelyAccessible, rootDir)); } int maxAdditionalDriveCount = moduleConfig.getIntProperty("max-additional-drive-count", 0); for (int i = 0; i < maxAdditionalDriveCount; i++) { - if (moduleConfig.hasProperty("drive-name-" + i) && moduleConfig.hasProperty("db-file-" + i)) { + if (moduleConfig.hasProperty("drive-name-" + i) + && moduleConfig.hasProperty("db-file-" + i)) { String driveName = moduleConfig.getStringProperty("drive-name-" + i); + boolean remotelyAccessible = moduleConfig.getBooleanProperty("remotely-accessible-" + i, DEFAULT_REMOTELY_ACCESSIBLE); Path rootDir = moduleConfig.getPathProperty("db-file-" + i); - configs.add(new MapDbAppFileSystemConfig(driveName, rootDir)); + configs.add(new MapDbAppFileSystemConfig(driveName, remotelyAccessible, rootDir)); } } } @@ -58,20 +61,11 @@ private static Path checkDbFile(Path dbFile) { return dbFile; } - public MapDbAppFileSystemConfig(String driveName, Path dbFile) { - this.driveName = Objects.requireNonNull(driveName); + public MapDbAppFileSystemConfig(String driveName, boolean remotelyAccessible, Path dbFile) { + super(driveName, remotelyAccessible); this.dbFile = checkDbFile(dbFile); } - public String getDriveName() { - return driveName; - } - - public MapDbAppFileSystemConfig setDriveName(String driveName) { - this.driveName = Objects.requireNonNull(driveName); - return this; - } - public Path getDbFile() { return dbFile; } diff --git a/afs/afs-mapdb/src/main/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystemProvider.java b/afs/afs-mapdb/src/main/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystemProvider.java index 4413d21d..0e3b3168 100644 --- a/afs/afs-mapdb/src/main/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystemProvider.java +++ b/afs/afs-mapdb/src/main/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystemProvider.java @@ -42,7 +42,10 @@ public MapDbAppFileSystemProvider(List configs, @Override public List getFileSystems(ComputationManager computationManager) { return configs.stream() - .map(config -> new MapDbAppFileSystem(config, storageProvider)) + .map(config -> { + MapDbAppFileSystemStorage storage = storageProvider.apply(config.getDriveName(), config.getDbFile()); + return new MapDbAppFileSystem(config.getDriveName(), config.isRemotelyAccessible(), storage); + }) .collect(Collectors.toList()); } } diff --git a/afs/afs-mapdb/src/test/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystemConfigTest.java b/afs/afs-mapdb/src/test/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystemConfigTest.java index 50cb4d95..3a9b0ed8 100644 --- a/afs/afs-mapdb/src/test/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystemConfigTest.java +++ b/afs/afs-mapdb/src/test/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystemConfigTest.java @@ -18,8 +18,7 @@ import java.nio.file.Files; import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; /** * @author Geoffroy Jamgotchian @@ -39,6 +38,7 @@ public void setUp() throws Exception { platformConfig = new InMemoryPlatformConfig(fileSystem); MapModuleConfig moduleConfig = platformConfig.createModuleConfig("mapdb-app-file-system"); moduleConfig.setStringProperty("drive-name", "db"); + moduleConfig.setStringProperty("remotely-accessible", "true"); moduleConfig.setPathProperty("db-file", fileSystem.getPath("/db")); moduleConfig.setStringProperty("max-additional-drive-count", "1"); moduleConfig.setStringProperty("drive-name-0", "db0"); @@ -57,8 +57,10 @@ public void loadTest() { MapDbAppFileSystemConfig config = configs.get(0); MapDbAppFileSystemConfig config1 = configs.get(1); assertEquals("db", config.getDriveName()); + assertTrue(config.isRemotelyAccessible()); assertEquals(fileSystem.getPath("/db"), config.getDbFile()); assertEquals("db0", config1.getDriveName()); + assertFalse(config1.isRemotelyAccessible()); assertEquals(fileSystem.getPath("/db0"), config1.getDbFile()); config.setDriveName("db2"); config.setDbFile(fileSystem.getPath("/db2")); diff --git a/afs/afs-mapdb/src/test/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystemProviderTest.java b/afs/afs-mapdb/src/test/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystemProviderTest.java index 48799c99..6470834f 100644 --- a/afs/afs-mapdb/src/test/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystemProviderTest.java +++ b/afs/afs-mapdb/src/test/java/eu/itesla_project/afs/mapdb/MapDbAppFileSystemProviderTest.java @@ -49,12 +49,13 @@ public void tearDown() throws Exception { @Test public void test() { ComputationManager computationManager = Mockito.mock(ComputationManager.class); - MapDbAppFileSystemConfig config = new MapDbAppFileSystemConfig("drive", dbFile); + MapDbAppFileSystemConfig config = new MapDbAppFileSystemConfig("drive", true, dbFile); List fileSystems = new MapDbAppFileSystemProvider(Collections.singletonList(config), (name, file) -> MapDbAppFileSystemStorage.createHeap(name)) .getFileSystems(computationManager); assertEquals(1, fileSystems.size()); assertTrue(fileSystems.get(0) instanceof MapDbAppFileSystem); assertEquals("drive", fileSystems.get(0).getName()); + assertTrue(fileSystems.get(0).isRemotelyAccessible()); } } \ No newline at end of file diff --git a/afs/afs-storage/src/main/java/eu/itesla_project/afs/storage/AbstractAppFileSystemConfig.java b/afs/afs-storage/src/main/java/eu/itesla_project/afs/storage/AbstractAppFileSystemConfig.java new file mode 100644 index 00000000..00c8fca8 --- /dev/null +++ b/afs/afs-storage/src/main/java/eu/itesla_project/afs/storage/AbstractAppFileSystemConfig.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2017, 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 eu.itesla_project.afs.storage; + +import java.util.Objects; + +/** + * @author Geoffroy Jamgotchian + */ +public abstract class AbstractAppFileSystemConfig> { + + protected static final boolean DEFAULT_REMOTELY_ACCESSIBLE = false; + + protected String driveName; + + protected boolean remotelyAccessible; + + public AbstractAppFileSystemConfig(String driveName, boolean remotelyAccessible) { + this.driveName = Objects.requireNonNull(driveName); + this.remotelyAccessible = remotelyAccessible; + } + + public String getDriveName() { + return driveName; + } + + public T setDriveName(String driveName) { + this.driveName = Objects.requireNonNull(driveName); + return (T) this; + } + + public boolean isRemotelyAccessible() { + return remotelyAccessible; + } + + public T setRemotelyAccessible(boolean remotelyAccessible) { + this.remotelyAccessible = remotelyAccessible; + return (T) this; + } +} diff --git a/afs/afs-storage/src/main/java/eu/itesla_project/afs/storage/AppFileSystemStorage.java b/afs/afs-storage/src/main/java/eu/itesla_project/afs/storage/AppFileSystemStorage.java index 010877e2..2a1986a2 100644 --- a/afs/afs-storage/src/main/java/eu/itesla_project/afs/storage/AppFileSystemStorage.java +++ b/afs/afs-storage/src/main/java/eu/itesla_project/afs/storage/AppFileSystemStorage.java @@ -35,6 +35,8 @@ public interface AppFileSystemStorage extends AutoCloseable { NodeId getParentNode(NodeId nodeId); + void setParentNode(NodeId nodeId, NodeId newParentNodeId); + void deleteNode(NodeId nodeId); String getStringAttribute(NodeId nodeId, String name); diff --git a/afs/afs-storage/src/test/java/eu/itesla_project/afs/storage/AbstractAppFileSystemStorageTest.java b/afs/afs-storage/src/test/java/eu/itesla_project/afs/storage/AbstractAppFileSystemStorageTest.java index b5e3cf92..5a98215c 100644 --- a/afs/afs-storage/src/test/java/eu/itesla_project/afs/storage/AbstractAppFileSystemStorageTest.java +++ b/afs/afs-storage/src/test/java/eu/itesla_project/afs/storage/AbstractAppFileSystemStorageTest.java @@ -130,4 +130,16 @@ public void test() throws IOException { assertEquals(PseudoClass.PROJECT_FOLDER_PSEUDO_CLASS, storage.getNodePseudoClass(projectRootId)); assertTrue(storage.getChildNodes(projectRootId).isEmpty()); } + + @Test + public void setParentTest() throws IOException { + NodeId rootFolderId = storage.getRootNode(); + NodeId folder1Id = storage.createNode(rootFolderId, "test1", PseudoClass.FOLDER_PSEUDO_CLASS); + NodeId folder2Id = storage.createNode(rootFolderId, "test2", PseudoClass.FOLDER_PSEUDO_CLASS); + NodeId fileId = storage.createNode(folder1Id, "file", "file-type"); + assertEquals(folder1Id, storage.getParentNode(fileId)); + storage.setParentNode(fileId, folder2Id); + assertEquals(folder2Id, storage.getParentNode(fileId)); + } + } \ No newline at end of file diff --git a/contingency-api/src/main/java/eu/itesla_project/contingency/BranchContingency.java b/contingency-api/src/main/java/eu/itesla_project/contingency/BranchContingency.java index 08b3b044..f5c7f04c 100644 --- a/contingency-api/src/main/java/eu/itesla_project/contingency/BranchContingency.java +++ b/contingency-api/src/main/java/eu/itesla_project/contingency/BranchContingency.java @@ -7,7 +7,7 @@ package eu.itesla_project.contingency; import eu.itesla_project.contingency.tasks.BranchTripping; -import eu.itesla_project.contingency.tasks.ModificationTask; +import eu.itesla_project.contingency.tasks.TrippingTask; import java.util.Objects; @@ -18,15 +18,15 @@ public class BranchContingency implements ContingencyElement { private final String id; - private final String substationId; + private final String voltageLevelId; public BranchContingency(String id) { this(id, null); } - public BranchContingency(String id, String substationId) { + public BranchContingency(String id, String voltageLevelId) { this.id = Objects.requireNonNull(id); - this.substationId = substationId; + this.voltageLevelId = voltageLevelId; } @Override @@ -34,8 +34,8 @@ public String getId() { return id; } - public String getSubstationId() { - return substationId; + public String getVoltageLevelId() { + return voltageLevelId; } @Override @@ -44,8 +44,8 @@ public ContingencyElementType getType() { } @Override - public ModificationTask toTask() { - return new BranchTripping(id, substationId); + public TrippingTask toTask() { + return new BranchTripping(id, voltageLevelId); } } diff --git a/contingency-api/src/main/java/eu/itesla_project/contingency/BusbarSectionContingency.java b/contingency-api/src/main/java/eu/itesla_project/contingency/BusbarSectionContingency.java new file mode 100644 index 00000000..2b34ee56 --- /dev/null +++ b/contingency-api/src/main/java/eu/itesla_project/contingency/BusbarSectionContingency.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2017, 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 eu.itesla_project.contingency; + +import eu.itesla_project.contingency.tasks.BusbarSectionTripping; +import eu.itesla_project.contingency.tasks.TrippingTask; + +import java.util.Objects; + +/** + * @author Mathieu Bague + */ +public class BusbarSectionContingency implements ContingencyElement { + + private final String busbarSectionId; + + public BusbarSectionContingency(String busbarSectionId) { + this.busbarSectionId = Objects.requireNonNull(busbarSectionId); + } + + @Override + public String getId() { + return busbarSectionId; + } + + @Override + public ContingencyElementType getType() { + return ContingencyElementType.BUSBAR_SECTION; + } + + @Override + public TrippingTask toTask() { + return new BusbarSectionTripping(busbarSectionId); + } +} diff --git a/contingency-api/src/main/java/eu/itesla_project/contingency/ContingencyElement.java b/contingency-api/src/main/java/eu/itesla_project/contingency/ContingencyElement.java index 589a976f..4b69829c 100644 --- a/contingency-api/src/main/java/eu/itesla_project/contingency/ContingencyElement.java +++ b/contingency-api/src/main/java/eu/itesla_project/contingency/ContingencyElement.java @@ -6,7 +6,7 @@ */ package eu.itesla_project.contingency; -import eu.itesla_project.contingency.tasks.ModificationTask; +import eu.itesla_project.contingency.tasks.TrippingTask; /** * @author Geoffroy Jamgotchian @@ -17,6 +17,6 @@ public interface ContingencyElement { ContingencyElementType getType(); - ModificationTask toTask(); + TrippingTask toTask(); } diff --git a/contingency-api/src/main/java/eu/itesla_project/contingency/ContingencyElementType.java b/contingency-api/src/main/java/eu/itesla_project/contingency/ContingencyElementType.java index e088c9f6..185ae063 100644 --- a/contingency-api/src/main/java/eu/itesla_project/contingency/ContingencyElementType.java +++ b/contingency-api/src/main/java/eu/itesla_project/contingency/ContingencyElementType.java @@ -12,5 +12,6 @@ public enum ContingencyElementType { @Deprecated LINE, GENERATOR, - BRANCH + BRANCH, + BUSBAR_SECTION } diff --git a/contingency-api/src/main/java/eu/itesla_project/contingency/GeneratorContingency.java b/contingency-api/src/main/java/eu/itesla_project/contingency/GeneratorContingency.java index 1a78ac77..ad940829 100644 --- a/contingency-api/src/main/java/eu/itesla_project/contingency/GeneratorContingency.java +++ b/contingency-api/src/main/java/eu/itesla_project/contingency/GeneratorContingency.java @@ -7,7 +7,7 @@ package eu.itesla_project.contingency; import eu.itesla_project.contingency.tasks.GeneratorTripping; -import eu.itesla_project.contingency.tasks.ModificationTask; +import eu.itesla_project.contingency.tasks.TrippingTask; import java.util.Objects; @@ -33,7 +33,7 @@ public ContingencyElementType getType() { } @Override - public ModificationTask toTask() { + public TrippingTask toTask() { return new GeneratorTripping(id); } diff --git a/contingency-api/src/main/java/eu/itesla_project/contingency/LineContingency.java b/contingency-api/src/main/java/eu/itesla_project/contingency/LineContingency.java index 7cb93d96..8ec10c4f 100644 --- a/contingency-api/src/main/java/eu/itesla_project/contingency/LineContingency.java +++ b/contingency-api/src/main/java/eu/itesla_project/contingency/LineContingency.java @@ -16,8 +16,8 @@ public LineContingency(String id) { super(id); } - public LineContingency(String id, String substationId) { - super(id, substationId); + public LineContingency(String id, String voltageLevelId) { + super(id, voltageLevelId); } @Override diff --git a/contingency-api/src/main/java/eu/itesla_project/contingency/json/ContingencyElementDeserializer.java b/contingency-api/src/main/java/eu/itesla_project/contingency/json/ContingencyElementDeserializer.java index 2c27ecb9..76109e05 100644 --- a/contingency-api/src/main/java/eu/itesla_project/contingency/json/ContingencyElementDeserializer.java +++ b/contingency-api/src/main/java/eu/itesla_project/contingency/json/ContingencyElementDeserializer.java @@ -10,10 +10,7 @@ import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import eu.itesla_project.contingency.BranchContingency; -import eu.itesla_project.contingency.ContingencyElement; -import eu.itesla_project.contingency.ContingencyElementType; -import eu.itesla_project.contingency.GeneratorContingency; +import eu.itesla_project.contingency.*; import java.io.IOException; @@ -29,7 +26,7 @@ public ContingencyElementDeserializer() { @Override public ContingencyElement deserialize(JsonParser parser, DeserializationContext ctx) throws IOException { String id = null; - String substationId = null; + String voltageLevelId = null; ContingencyElementType type = null; while (parser.nextToken() != JsonToken.END_OBJECT) { @@ -38,8 +35,8 @@ public ContingencyElement deserialize(JsonParser parser, DeserializationContext id = parser.nextTextValue(); break; - case "substationId": - substationId = parser.nextTextValue(); + case "voltageLevelId": + voltageLevelId = parser.nextTextValue(); break; case "type": @@ -56,11 +53,14 @@ public ContingencyElement deserialize(JsonParser parser, DeserializationContext switch (type) { case LINE: case BRANCH: - return new BranchContingency(id, substationId); + return new BranchContingency(id, voltageLevelId); case GENERATOR: return new GeneratorContingency(id); + case BUSBAR_SECTION: + return new BusbarSectionContingency(id); + default: throw new AssertionError(); } diff --git a/contingency-api/src/main/java/eu/itesla_project/contingency/tasks/BranchTripping.java b/contingency-api/src/main/java/eu/itesla_project/contingency/tasks/BranchTripping.java index bda497b5..8f1cb536 100644 --- a/contingency-api/src/main/java/eu/itesla_project/contingency/tasks/BranchTripping.java +++ b/contingency-api/src/main/java/eu/itesla_project/contingency/tasks/BranchTripping.java @@ -9,29 +9,35 @@ import eu.itesla_project.commons.ITeslaException; import eu.itesla_project.computation.ComputationManager; import eu.itesla_project.iidm.network.Network; +import eu.itesla_project.iidm.network.Switch; +import eu.itesla_project.iidm.network.Terminal; import eu.itesla_project.iidm.network.TwoTerminalsConnectable; import java.util.Objects; +import java.util.Set; /** * @author Geoffroy Jamgotchian + * @author Mathieu Bague */ -public class BranchTripping implements ModificationTask { +public class BranchTripping extends TrippingTask { private final String branchId; - private final String substationId; + private final String voltageLevelId; public BranchTripping(String branchId) { this(branchId, null); } - public BranchTripping(String branchId, String substationId) { + public BranchTripping(String branchId, String voltageLevelId) { this.branchId = Objects.requireNonNull(branchId); - this.substationId = substationId; + this.voltageLevelId = voltageLevelId; } @Override - public void modify(Network network, ComputationManager computationManager) { + public void traverse(Network network, ComputationManager computationManager, Set switchesToOpen, Set terminalsToDisconnect) { + Objects.requireNonNull(network); + TwoTerminalsConnectable branch = network.getLine(branchId); if (branch == null) { branch = network.getTwoWindingsTransformer(branchId); @@ -39,17 +45,17 @@ public void modify(Network network, ComputationManager computationManager) { throw new ITeslaException("Branch '" + branchId + "' not found"); } } - if (substationId != null) { - if (substationId.equalsIgnoreCase(branch.getTerminal1().getVoltageLevel().getSubstation().getId())) { - branch.getTerminal1().disconnect(); - } else if (substationId.equalsIgnoreCase(branch.getTerminal2().getVoltageLevel().getSubstation().getId())) { - branch.getTerminal2().disconnect(); + if (voltageLevelId != null) { + if (voltageLevelId.equals(branch.getTerminal1().getVoltageLevel().getId())) { + ContingencyTopologyTraverser.traverse(branch.getTerminal1(), switchesToOpen, terminalsToDisconnect); + } else if (voltageLevelId.equals(branch.getTerminal2().getVoltageLevel().getId())) { + ContingencyTopologyTraverser.traverse(branch.getTerminal2(), switchesToOpen, terminalsToDisconnect); } else { - throw new ITeslaException("Substation '" + substationId + "' not connected to branch '" + branchId + "'"); + throw new ITeslaException("VoltageLevel '" + voltageLevelId + "' not connected to branch '" + branchId + "'"); } } else { - branch.getTerminal1().disconnect(); - branch.getTerminal2().disconnect(); + ContingencyTopologyTraverser.traverse(branch.getTerminal1(), switchesToOpen, terminalsToDisconnect); + ContingencyTopologyTraverser.traverse(branch.getTerminal2(), switchesToOpen, terminalsToDisconnect); } } diff --git a/contingency-api/src/main/java/eu/itesla_project/contingency/tasks/BusbarSectionTripping.java b/contingency-api/src/main/java/eu/itesla_project/contingency/tasks/BusbarSectionTripping.java new file mode 100644 index 00000000..096d2a87 --- /dev/null +++ b/contingency-api/src/main/java/eu/itesla_project/contingency/tasks/BusbarSectionTripping.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2017, 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 eu.itesla_project.contingency.tasks; + +import eu.itesla_project.commons.ITeslaException; +import eu.itesla_project.computation.ComputationManager; +import eu.itesla_project.iidm.network.BusbarSection; +import eu.itesla_project.iidm.network.Network; +import eu.itesla_project.iidm.network.Switch; +import eu.itesla_project.iidm.network.Terminal; + +import java.util.Objects; +import java.util.Set; + +/** + * @author Mathieu Bague + */ +public class BusbarSectionTripping extends TrippingTask { + + private final String busbarSectionId; + + public BusbarSectionTripping(String busbarSectionId) { + this.busbarSectionId = Objects.requireNonNull(busbarSectionId); + } + + @Override + public void traverse(Network network, ComputationManager computationManager, Set switchesToOpen, Set terminalsToDisconnect) { + Objects.requireNonNull(network); + + BusbarSection busbarSection = network.getBusbarSection(busbarSectionId); + if (busbarSection == null) { + throw new ITeslaException("Busbar section '" + busbarSectionId + "' not found"); + } + + ContingencyTopologyTraverser.traverse(busbarSection.getTerminal(), switchesToOpen, terminalsToDisconnect); + } +} diff --git a/contingency-api/src/main/java/eu/itesla_project/contingency/tasks/ContingencyTopologyTraverser.java b/contingency-api/src/main/java/eu/itesla_project/contingency/tasks/ContingencyTopologyTraverser.java new file mode 100644 index 00000000..31e6471e --- /dev/null +++ b/contingency-api/src/main/java/eu/itesla_project/contingency/tasks/ContingencyTopologyTraverser.java @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2017, 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 eu.itesla_project.contingency.tasks; + +import eu.itesla_project.iidm.network.*; + +import java.util.Objects; +import java.util.Set; + +/** + * @author Mathieu Bague + */ +class ContingencyTopologyTraverser { + + private static boolean isOpenable(Switch aSwitch) { + return (!aSwitch.isOpen() && + !aSwitch.isFictitious() && + aSwitch.getKind() == SwitchKind.BREAKER); + } + + static void traverse(Terminal terminal, Set switchesToOpen, Set terminalsToDisconnect) { + Objects.requireNonNull(terminal); + Objects.requireNonNull(switchesToOpen); + Objects.requireNonNull(terminalsToDisconnect); + + terminal.traverse(new VoltageLevel.TopologyTraverser() { + @Override + public boolean traverse(Terminal terminal, boolean connected) { + boolean traverse = true; + + if (terminal.getVoltageLevel().getTopologyKind() == TopologyKind.BUS_BREAKER) { + if (connected) { + terminalsToDisconnect.add(terminal); + traverse = false; + } + } + + return traverse; + } + + @Override + public boolean traverse(Switch aSwitch) { + boolean traverse = false; + + if (isOpenable(aSwitch)) { + switchesToOpen.add(aSwitch); + } else if (! aSwitch.isOpen()) { + traverse = true; + } + + return traverse; + } + }); + } +} diff --git a/contingency-api/src/main/java/eu/itesla_project/contingency/tasks/GeneratorTripping.java b/contingency-api/src/main/java/eu/itesla_project/contingency/tasks/GeneratorTripping.java index 0f2bf429..af6baefe 100644 --- a/contingency-api/src/main/java/eu/itesla_project/contingency/tasks/GeneratorTripping.java +++ b/contingency-api/src/main/java/eu/itesla_project/contingency/tasks/GeneratorTripping.java @@ -10,11 +10,17 @@ import eu.itesla_project.computation.ComputationManager; import eu.itesla_project.iidm.network.Generator; import eu.itesla_project.iidm.network.Network; +import eu.itesla_project.iidm.network.Switch; +import eu.itesla_project.iidm.network.Terminal; + +import java.util.Objects; +import java.util.Set; /** * @author Geoffroy Jamgotchian + * @author Mathieu Bague */ -public class GeneratorTripping implements ModificationTask { +public class GeneratorTripping extends TrippingTask { private final String generatorId; @@ -23,12 +29,15 @@ public GeneratorTripping(String generatorId) { } @Override - public void modify(Network network, ComputationManager computationManager) { + public void traverse(Network network, ComputationManager computationManager, Set switchesToOpen, Set terminalsToDisconnect) { + Objects.requireNonNull(network); + Generator g = network.getGenerator(generatorId); if (g == null) { throw new ITeslaException("Generator '" + generatorId + "' not found"); } - g.getTerminal().disconnect(); + + ContingencyTopologyTraverser.traverse(g.getTerminal(), switchesToOpen, terminalsToDisconnect); } } diff --git a/contingency-api/src/main/java/eu/itesla_project/contingency/tasks/TrippingTask.java b/contingency-api/src/main/java/eu/itesla_project/contingency/tasks/TrippingTask.java new file mode 100644 index 00000000..36fb8f6a --- /dev/null +++ b/contingency-api/src/main/java/eu/itesla_project/contingency/tasks/TrippingTask.java @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2017, 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 eu.itesla_project.contingency.tasks; + +import eu.itesla_project.computation.ComputationManager; +import eu.itesla_project.iidm.network.Network; +import eu.itesla_project.iidm.network.Switch; +import eu.itesla_project.iidm.network.Terminal; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author Mathieu Bague + */ +public abstract class TrippingTask implements ModificationTask { + + @Override + public void modify(Network network, ComputationManager computationManager) { + Set switchesToOpen = new HashSet<>(); + Set terminalsToDisconnect = new HashSet<>(); + + traverse(network, computationManager, switchesToOpen, terminalsToDisconnect); + + switchesToOpen.forEach(s -> s.setOpen(true)); + terminalsToDisconnect.forEach(Terminal::disconnect); + } + + public abstract void traverse(Network network, ComputationManager computationManager, Set switchesToOpen, Set terminalsToDisconnect); +} diff --git a/contingency-api/src/test/java/eu/itesla_project/contingency/BranchContingencyTest.java b/contingency-api/src/test/java/eu/itesla_project/contingency/BranchContingencyTest.java index a715b84a..ae51efd6 100644 --- a/contingency-api/src/test/java/eu/itesla_project/contingency/BranchContingencyTest.java +++ b/contingency-api/src/test/java/eu/itesla_project/contingency/BranchContingencyTest.java @@ -21,13 +21,13 @@ public class BranchContingencyTest { public void test() { BranchContingency contingency = new BranchContingency("id"); assertEquals("id", contingency.getId()); - assertNull(contingency.getSubstationId()); + assertNull(contingency.getVoltageLevelId()); assertEquals(ContingencyElementType.BRANCH, contingency.getType()); assertNotNull(contingency.toTask()); assertTrue(contingency.toTask() instanceof BranchTripping); - contingency = new BranchContingency("id", "substationId"); - assertEquals("substationId", contingency.getSubstationId()); + contingency = new BranchContingency("id", "voltageLevelId"); + assertEquals("voltageLevelId", contingency.getVoltageLevelId()); } } diff --git a/contingency-api/src/test/java/eu/itesla_project/contingency/BusbarSectionContingencyTest.java b/contingency-api/src/test/java/eu/itesla_project/contingency/BusbarSectionContingencyTest.java new file mode 100644 index 00000000..cb2305c4 --- /dev/null +++ b/contingency-api/src/test/java/eu/itesla_project/contingency/BusbarSectionContingencyTest.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2017, 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 eu.itesla_project.contingency; + +import eu.itesla_project.contingency.tasks.BusbarSectionTripping; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * @author Mathieu Bague + */ +public class BusbarSectionContingencyTest { + + @Test + public void test() { + BusbarSectionContingency contingency = new BusbarSectionContingency("id"); + assertEquals("id", contingency.getId()); + assertEquals(ContingencyElementType.BUSBAR_SECTION, contingency.getType()); + + assertNotNull(contingency.toTask()); + assertTrue(contingency.toTask() instanceof BusbarSectionTripping); + } +} diff --git a/contingency-api/src/test/java/eu/itesla_project/contingency/LineContingencyTest.java b/contingency-api/src/test/java/eu/itesla_project/contingency/LineContingencyTest.java index 3a667e0b..a39fe95c 100644 --- a/contingency-api/src/test/java/eu/itesla_project/contingency/LineContingencyTest.java +++ b/contingency-api/src/test/java/eu/itesla_project/contingency/LineContingencyTest.java @@ -19,10 +19,10 @@ public class LineContingencyTest { public void test() { LineContingency contingency = new LineContingency("id"); assertEquals("id", contingency.getId()); - assertNull(contingency.getSubstationId()); + assertNull(contingency.getVoltageLevelId()); assertEquals(ContingencyElementType.LINE, contingency.getType()); - contingency = new LineContingency("id", "substationId"); - assertEquals("substationId", contingency.getSubstationId()); + contingency = new LineContingency("id", "voltageLevelId"); + assertEquals("voltageLevelId", contingency.getVoltageLevelId()); } } diff --git a/contingency-api/src/test/java/eu/itesla_project/contingency/json/ContingencyJsonTest.java b/contingency-api/src/test/java/eu/itesla_project/contingency/json/ContingencyJsonTest.java index e1fbe844..f5678660 100644 --- a/contingency-api/src/test/java/eu/itesla_project/contingency/json/ContingencyJsonTest.java +++ b/contingency-api/src/test/java/eu/itesla_project/contingency/json/ContingencyJsonTest.java @@ -1,5 +1,12 @@ package eu.itesla_project.contingency.json; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.databind.module.SimpleModule; +import eu.itesla_project.commons.ConverterBaseTest; +import eu.itesla_project.contingency.*; +import org.junit.Test; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -9,21 +16,14 @@ import java.util.List; import java.util.Objects; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectWriter; -import com.fasterxml.jackson.databind.module.SimpleModule; -import eu.itesla_project.contingency.*; -import org.junit.Test; - -import eu.itesla_project.commons.ConverterBaseTest; - public class ContingencyJsonTest extends ConverterBaseTest { private static Contingency create() { List elements = new ArrayList<>(); - elements.add(new BranchContingency("NHV1_NHV2_2", "P1")); + elements.add(new BranchContingency("NHV1_NHV2_2", "VLHV1")); elements.add(new BranchContingency("NHV1_NHV2_1")); elements.add(new GeneratorContingency("GEN")); + elements.add(new BusbarSectionContingency("BBS1")); return new ContingencyImpl("contingency", elements); } diff --git a/contingency-api/src/test/java/eu/itesla_project/contingency/tasks/BranchTrippingTest.java b/contingency-api/src/test/java/eu/itesla_project/contingency/tasks/BranchTrippingTest.java index 8ed933d1..1face889 100644 --- a/contingency-api/src/test/java/eu/itesla_project/contingency/tasks/BranchTrippingTest.java +++ b/contingency-api/src/test/java/eu/itesla_project/contingency/tasks/BranchTrippingTest.java @@ -6,22 +6,27 @@ */ package eu.itesla_project.contingency.tasks; +import com.google.common.collect.Sets; import eu.itesla_project.commons.ITeslaException; import eu.itesla_project.contingency.BranchContingency; import eu.itesla_project.contingency.ContingencyImpl; -import eu.itesla_project.iidm.network.Line; -import eu.itesla_project.iidm.network.Network; -import eu.itesla_project.iidm.network.TwoWindingsTransformer; +import eu.itesla_project.iidm.network.*; import eu.itesla_project.iidm.network.test.EurostagTutorialExample1Factory; +import eu.itesla_project.iidm.network.test.FictitiousSwitchFactory; import org.junit.Test; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.junit.Assert.*; /** * @author Mathieu Bague */ -public class BranchTrippingTest { +public class BranchTrippingTest extends TrippingTest { @Test public void lineTrippingTest() { @@ -45,7 +50,7 @@ public void lineTrippingTest() { assertTrue(line.getTerminal1().isConnected()); assertTrue(line.getTerminal2().isConnected()); - tripping = new BranchContingency("NHV1_NHV2_1", "P2"); + tripping = new BranchContingency("NHV1_NHV2_1", "VLHV2"); contingency = new ContingencyImpl("contingency", tripping); contingency.toTask().modify(network, null); @@ -61,7 +66,7 @@ public void transformerTrippingTest() { assertTrue(transformer.getTerminal1().isConnected()); assertTrue(transformer.getTerminal2().isConnected()); - BranchContingency tripping = new BranchContingency("NHV2_NLOAD", "P2"); + BranchContingency tripping = new BranchContingency("NHV2_NLOAD", "VLHV2"); ContingencyImpl contingency = new ContingencyImpl("contingency", tripping); contingency.toTask().modify(network, null); @@ -84,4 +89,27 @@ public void unknownSubstationTrippingTest() { BranchTripping tripping = new BranchTripping("NHV2_NLOAD", "UNKNOWN"); tripping.modify(network, null); } + + @Test + public void fictitiousSwitchTest() { + Set switchIds = Sets.newHashSet("BD", "BL"); + + Network network = FictitiousSwitchFactory.create(); + List expectedSwitchStates = getSwitchStates(network, switchIds); + + BranchTripping tripping = new BranchTripping("CJ", "C"); + + Set switchesToOpen = new HashSet<>(); + Set terminalsToDisconnect = new HashSet<>(); + tripping.traverse(network, null, switchesToOpen, terminalsToDisconnect); + assertEquals(switchIds, switchesToOpen.stream().map(Switch::getId).collect(Collectors.toSet())); + assertEquals(Collections.emptySet(), terminalsToDisconnect); + + tripping.modify(network, null); + assertTrue(network.getSwitch("BD").isOpen()); + assertTrue(network.getSwitch("BL").isOpen()); + + List switchStates = getSwitchStates(network, switchIds); + assertEquals(expectedSwitchStates, switchStates); + } } diff --git a/contingency-api/src/test/java/eu/itesla_project/contingency/tasks/BusbarSectionTrippingTest.java b/contingency-api/src/test/java/eu/itesla_project/contingency/tasks/BusbarSectionTrippingTest.java new file mode 100644 index 00000000..276a5a94 --- /dev/null +++ b/contingency-api/src/test/java/eu/itesla_project/contingency/tasks/BusbarSectionTrippingTest.java @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2017, 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 eu.itesla_project.contingency.tasks; + +import com.google.common.collect.Sets; +import eu.itesla_project.commons.ITeslaException; +import eu.itesla_project.iidm.network.Network; +import eu.itesla_project.iidm.network.Switch; +import eu.itesla_project.iidm.network.Terminal; +import eu.itesla_project.iidm.network.test.FictitiousSwitchFactory; +import org.junit.Test; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author Mathieu Bague + */ +public class BusbarSectionTrippingTest extends TrippingTest { + + @Test + public void busbarSectionTrippingTest() throws IOException { + busbarSectionTrippingTest("D", Sets.newHashSet("BD", "BL")); + busbarSectionTrippingTest("O", Sets.newHashSet("BJ", "BT")); + busbarSectionTrippingTest("P", Sets.newHashSet("BJ", "BL", "BV", "BX", "BZ")); + } + + public void busbarSectionTrippingTest(String bbsId, Set switchIds) { + Network network = FictitiousSwitchFactory.create(); + List expectedSwitchStates = getSwitchStates(network, switchIds); + + BusbarSectionTripping tripping = new BusbarSectionTripping(bbsId); + + Set switchesToOpen = new HashSet<>(); + Set terminalsToDisconnect = new HashSet<>(); + tripping.traverse(network, null, switchesToOpen, terminalsToDisconnect); + assertEquals(switchIds, switchesToOpen.stream().map(Switch::getId).collect(Collectors.toSet())); + assertEquals(Collections.emptySet(), terminalsToDisconnect); + + tripping.modify(network, null); + for (String id : switchIds) { + assertTrue(network.getSwitch(id).isOpen()); + } + + List switchStates = getSwitchStates(network, switchIds); + assertEquals(expectedSwitchStates, switchStates); + } + + @Test(expected = ITeslaException.class) + public void unknownBusbarSectionTrippingTest() { + Network network = FictitiousSwitchFactory.create(); + + BusbarSectionTripping tripping = new BusbarSectionTripping("bbs"); + tripping.modify(network, null); + } +} diff --git a/contingency-api/src/test/java/eu/itesla_project/contingency/tasks/CompoundModificationTaskTest.java b/contingency-api/src/test/java/eu/itesla_project/contingency/tasks/CompoundModificationTaskTest.java index 7215910c..f06b2acd 100644 --- a/contingency-api/src/test/java/eu/itesla_project/contingency/tasks/CompoundModificationTaskTest.java +++ b/contingency-api/src/test/java/eu/itesla_project/contingency/tasks/CompoundModificationTaskTest.java @@ -23,8 +23,8 @@ public void test() { assertTrue(network.getLine("NHV1_NHV2_1").getTerminal1().isConnected()); assertTrue(network.getLine("NHV1_NHV2_1").getTerminal2().isConnected()); - BranchTripping tripping1 = new BranchTripping("NHV1_NHV2_1", "P1"); - BranchTripping tripping2 = new BranchTripping("NHV1_NHV2_1", "P2"); + BranchTripping tripping1 = new BranchTripping("NHV1_NHV2_1", "VLHV1"); + BranchTripping tripping2 = new BranchTripping("NHV1_NHV2_1", "VLHV2"); CompoundModificationTask task = new CompoundModificationTask(tripping1, tripping2); task.modify(network, null); diff --git a/contingency-api/src/test/java/eu/itesla_project/contingency/tasks/GeneratorTrippingTest.java b/contingency-api/src/test/java/eu/itesla_project/contingency/tasks/GeneratorTrippingTest.java index 7d6aae88..8b2c9421 100644 --- a/contingency-api/src/test/java/eu/itesla_project/contingency/tasks/GeneratorTrippingTest.java +++ b/contingency-api/src/test/java/eu/itesla_project/contingency/tasks/GeneratorTrippingTest.java @@ -10,16 +10,24 @@ import eu.itesla_project.contingency.ContingencyImpl; import eu.itesla_project.contingency.GeneratorContingency; import eu.itesla_project.iidm.network.Network; +import eu.itesla_project.iidm.network.Switch; +import eu.itesla_project.iidm.network.Terminal; import eu.itesla_project.iidm.network.test.EurostagTutorialExample1Factory; +import eu.itesla_project.iidm.network.test.FictitiousSwitchFactory; import org.junit.Test; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.junit.Assert.*; /** * @author Mathieu Bague */ -public class GeneratorTrippingTest { +public class GeneratorTrippingTest extends TrippingTest { @Test public void generatorTrippingTest() { @@ -42,4 +50,27 @@ public void unknownGeneratorTrippingTest() { GeneratorTripping tripping = new GeneratorTripping("generator"); tripping.modify(network, null); } + + @Test + public void fictitiousSwitchTest() { + Set switchIds = Collections.singleton("BJ"); + + Network network = FictitiousSwitchFactory.create(); + network.getSwitch("BT").setFictitious(true); + List expectedSwitchStates = getSwitchStates(network, switchIds); + + GeneratorTripping tripping = new GeneratorTripping("CD"); + + Set switchesToOpen = new HashSet<>(); + Set terminalsToDisconnect = new HashSet<>(); + tripping.traverse(network, null, switchesToOpen, terminalsToDisconnect); + assertEquals(switchIds, switchesToOpen.stream().map(Switch::getId).collect(Collectors.toSet())); + assertEquals(Collections.emptySet(), terminalsToDisconnect); + + tripping.modify(network, null); + assertTrue(network.getSwitch("BJ").isOpen()); + + List switchStates = getSwitchStates(network, switchIds); + assertEquals(expectedSwitchStates, switchStates); + } } diff --git a/contingency-api/src/test/java/eu/itesla_project/contingency/tasks/TrippingTest.java b/contingency-api/src/test/java/eu/itesla_project/contingency/tasks/TrippingTest.java new file mode 100644 index 00000000..4dd5b762 --- /dev/null +++ b/contingency-api/src/test/java/eu/itesla_project/contingency/tasks/TrippingTest.java @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2017, 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 eu.itesla_project.contingency.tasks; + +import eu.itesla_project.iidm.network.Network; +import eu.itesla_project.iidm.network.Switch; + +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author Mathieu Bague + */ +class TrippingTest { + + protected List getSwitchStates(Network network, Set switchIds) { + Objects.requireNonNull(network); + Objects.requireNonNull(switchIds); + + return network.getSwitchStream() + .filter(s -> ! switchIds.contains(s.getId())) + .map(Switch::isOpen) + .collect(Collectors.toList()); + } +} diff --git a/contingency-api/src/test/resources/contingency.json b/contingency-api/src/test/resources/contingency.json index b6228864..cd51e903 100644 --- a/contingency-api/src/test/resources/contingency.json +++ b/contingency-api/src/test/resources/contingency.json @@ -2,14 +2,17 @@ "id" : "contingency", "elements" : [ { "id" : "NHV1_NHV2_2", - "substationId" : "P1", + "voltageLevelId" : "VLHV1", "type" : "BRANCH" }, { "id" : "NHV1_NHV2_1", - "substationId" : null, + "voltageLevelId" : null, "type" : "BRANCH" }, { "id" : "GEN", "type" : "GENERATOR" + }, { + "id" : "BBS1", + "type" : "BUSBAR_SECTION" } ] } \ No newline at end of file diff --git a/iidm/iidm-api/src/main/java/eu/itesla_project/iidm/network/Network.java b/iidm/iidm-api/src/main/java/eu/itesla_project/iidm/network/Network.java index 7d5658c8..60fe0445 100644 --- a/iidm/iidm-api/src/main/java/eu/itesla_project/iidm/network/Network.java +++ b/iidm/iidm-api/src/main/java/eu/itesla_project/iidm/network/Network.java @@ -6,12 +6,12 @@ */ package eu.itesla_project.iidm.network; +import org.joda.time.DateTime; + import java.util.Collection; import java.util.Set; import java.util.stream.Stream; -import org.joda.time.DateTime; - /** * A power network model. * @@ -398,6 +398,19 @@ interface BusView { */ Switch getSwitch(String id); + /** + * Get all switches + * return all switches + */ + Stream getSwitchStream(); + + /** + * Get a busbar section from its id. + * @param id id of the busbar section + * @return the busbar section + */ + BusbarSection getBusbarSection(String id); + /** * Get all HVDC converter stations. * @return all HVDC converter stations diff --git a/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/BusBreakerVoltageLevel.java b/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/BusBreakerVoltageLevel.java index 6ac540f9..ec9007e2 100644 --- a/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/BusBreakerVoltageLevel.java +++ b/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/BusBreakerVoltageLevel.java @@ -742,20 +742,21 @@ void traverse(BusTerminal terminal, VoltageLevel.TopologyTraverser traverser) { traverse(terminal, traverser, new HashSet<>()); } - void traverse(BusTerminal terminal, VoltageLevel.TopologyTraverser traverser, Set traversedVoltageLevelsIds) { + void traverse(BusTerminal terminal, VoltageLevel.TopologyTraverser traverser, Set traversedTerminals) { Objects.requireNonNull(terminal); Objects.requireNonNull(traverser); - Objects.requireNonNull(traversedVoltageLevelsIds); + Objects.requireNonNull(traversedTerminals); - if (traversedVoltageLevelsIds.contains(terminal.getVoltageLevel().getId())) { + if (traversedTerminals.contains(terminal)) { return; } - traversedVoltageLevelsIds.add(terminal.getVoltageLevel().getId()); List nextTerminals = new ArrayList<>(); // check if we are allowed to traverse the terminal itself if (traverser.traverse(terminal, terminal.isConnected())) { + traversedTerminals.add(terminal); + addNextTerminals(terminal, nextTerminals); // then check we can traverse terminal connected to same bus @@ -776,6 +777,8 @@ void traverse(BusTerminal terminal, VoltageLevel.TopologyTraverser traverser, Se if (traverser.traverse(aSwitch)) { for (BusTerminal otherTerminal : otherBus.getTerminals()) { if (traverser.traverse(otherTerminal, otherTerminal.isConnected())) { + traversedTerminals.add(otherTerminal); + addNextTerminals(otherTerminal, nextTerminals); return TraverseResult.CONTINUE; } else { @@ -789,7 +792,7 @@ void traverse(BusTerminal terminal, VoltageLevel.TopologyTraverser traverser, Se }); for (TerminalExt nextTerminal : nextTerminals) { - nextTerminal.traverse(traverser, traversedVoltageLevelsIds); + nextTerminal.traverse(traverser, traversedTerminals); } } } diff --git a/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/BusTerminal.java b/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/BusTerminal.java index 78109088..b17bb2a5 100644 --- a/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/BusTerminal.java +++ b/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/BusTerminal.java @@ -6,6 +6,7 @@ */ package eu.itesla_project.iidm.network.impl; +import eu.itesla_project.iidm.network.Terminal; import eu.itesla_project.iidm.network.VoltageLevel; import eu.itesla_project.iidm.network.impl.util.Ref; @@ -102,8 +103,8 @@ public boolean isConnected() { } @Override - public void traverse(VoltageLevel.TopologyTraverser traverser, Set traversedVoltageLevelsIds) { - ((BusBreakerVoltageLevel) voltageLevel).traverse(this, traverser, traversedVoltageLevelsIds); + public void traverse(VoltageLevel.TopologyTraverser traverser, Set traversedTerminals) { + ((BusBreakerVoltageLevel) voltageLevel).traverse(this, traverser, traversedTerminals); } @Override diff --git a/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/NetworkImpl.java b/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/NetworkImpl.java index 07bf9a26..0f023d6a 100644 --- a/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/NetworkImpl.java +++ b/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/NetworkImpl.java @@ -410,6 +410,16 @@ public Switch getSwitch(String id) { return objectStore.get(id, SwitchImpl.class); } + @Override + public Stream getSwitchStream() { + return objectStore.getAll(SwitchImpl.class).stream().map(Function.identity()); + } + + @Override + public BusbarSection getBusbarSection(String id) { + return objectStore.get(id, BusbarSectionImpl.class); + } + @Override public HvdcConverterStationImpl getHvdcConverterStation(String id) { HvdcConverterStationImpl converterStation = getLccConverterStation(id); diff --git a/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/NodeBreakerVoltageLevel.java b/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/NodeBreakerVoltageLevel.java index 6d187a39..a11f328b 100644 --- a/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/NodeBreakerVoltageLevel.java +++ b/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/NodeBreakerVoltageLevel.java @@ -927,26 +927,26 @@ public boolean disconnect(TerminalExt terminal) { boolean isConnected(TerminalExt terminal) { assert terminal instanceof NodeTerminal; - int node = ((NodeTerminal) terminal).getNode(); - List paths = graph.findAllPaths(node, NodeBreakerVoltageLevel::isBusbarSection, Switch::isOpen); - return paths.size() > 0; + + return (terminal.getBusView().getBus() != null); } void traverse(NodeTerminal terminal, VoltageLevel.TopologyTraverser traverser) { traverse(terminal, traverser, new HashSet<>()); } - void traverse(NodeTerminal terminal, VoltageLevel.TopologyTraverser traverser, Set traversedVoltageLevelsIds) { + void traverse(NodeTerminal terminal, VoltageLevel.TopologyTraverser traverser, Set traversedTerminals) { Objects.requireNonNull(terminal); Objects.requireNonNull(traverser); - Objects.requireNonNull(traversedVoltageLevelsIds); + Objects.requireNonNull(traversedTerminals); - if (traversedVoltageLevelsIds.contains(terminal.getVoltageLevel().getId())) { + if (traversedTerminals.contains(terminal)) { return; } - traversedVoltageLevelsIds.add(terminal.getVoltageLevel().getId()); if (traverser.traverse(terminal, true)) { + traversedTerminals.add(terminal); + int node = terminal.getNode(); List nextTerminals = new ArrayList<>(); @@ -959,7 +959,8 @@ void traverse(NodeTerminal terminal, VoltageLevel.TopologyTraverser traverser, S if (otherTerminal == null) { return TraverseResult.CONTINUE; } else if (traverser.traverse(otherTerminal, true)) { - addNextTerminals(otherTerminal, nextTerminals); + traversedTerminals.add(otherTerminal); + addNextTerminals(otherTerminal, nextTerminals); return TraverseResult.CONTINUE; } else { @@ -971,7 +972,7 @@ void traverse(NodeTerminal terminal, VoltageLevel.TopologyTraverser traverser, S }); for (TerminalExt nextTerminal : nextTerminals) { - nextTerminal.traverse(traverser, traversedVoltageLevelsIds); + nextTerminal.traverse(traverser, traversedTerminals); } } } diff --git a/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/NodeTerminal.java b/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/NodeTerminal.java index 10b89e4b..d17d7e33 100644 --- a/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/NodeTerminal.java +++ b/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/NodeTerminal.java @@ -6,12 +6,12 @@ */ package eu.itesla_project.iidm.network.impl; +import eu.itesla_project.iidm.network.Terminal; import eu.itesla_project.iidm.network.VoltageLevel; import eu.itesla_project.iidm.network.impl.util.Ref; import gnu.trove.list.array.TFloatArrayList; import gnu.trove.list.array.TIntArrayList; -import java.util.ArrayList; import java.util.Set; /** @@ -151,8 +151,8 @@ public boolean isConnected() { } @Override - public void traverse(VoltageLevel.TopologyTraverser traverser, Set traversedVoltageLevelsIds) { - ((NodeBreakerVoltageLevel) voltageLevel).traverse(this, traverser, traversedVoltageLevelsIds); + public void traverse(VoltageLevel.TopologyTraverser traverser, Set traversedTerminals) { + ((NodeBreakerVoltageLevel) voltageLevel).traverse(this, traverser, traversedTerminals); } @Override diff --git a/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/TerminalExt.java b/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/TerminalExt.java index d5d575f6..d7ead4b6 100644 --- a/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/TerminalExt.java +++ b/iidm/iidm-impl/src/main/java/eu/itesla_project/iidm/network/impl/TerminalExt.java @@ -43,6 +43,6 @@ interface BusViewExt extends BusView { void setNum(int num); - void traverse(VoltageLevel.TopologyTraverser traverser, Set traversedVoltageLevelsIds); + void traverse(VoltageLevel.TopologyTraverser traverser, Set traversedTerminals); } diff --git a/iidm/iidm-impl/src/test/java/eu/itesla_project/iidm/network/impl/NetworkTest.java b/iidm/iidm-impl/src/test/java/eu/itesla_project/iidm/network/impl/NetworkTest.java index f3f7c94a..b75d9a98 100644 --- a/iidm/iidm-impl/src/test/java/eu/itesla_project/iidm/network/impl/NetworkTest.java +++ b/iidm/iidm-impl/src/test/java/eu/itesla_project/iidm/network/impl/NetworkTest.java @@ -6,24 +6,26 @@ */ package eu.itesla_project.iidm.network.impl; -import eu.itesla_project.iidm.network.*; import com.google.common.collect.Iterables; +import eu.itesla_project.iidm.network.*; import eu.itesla_project.iidm.network.VoltageLevel.NodeBreakerView; import eu.itesla_project.iidm.network.test.EurostagTutorialExample1Factory; import eu.itesla_project.iidm.network.test.HvdcTestNetwork; import eu.itesla_project.iidm.network.test.NetworkTest1Factory; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - import eu.itesla_project.iidm.network.test.SvcTestCaseFactory; import org.junit.Test; -import java.util.*; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** * @author Geoffroy Jamgotchian */ @@ -73,6 +75,8 @@ public void testNetwork1() { assertTrue(Iterables.size(topology1.getSwitches()) == 5); assertTrue(topology1.getSwitchCount() == 5); + assertEquals(5, network.getSwitchStream().count()); + Switch voltageLevel1Breaker1 = topology1.getSwitch("voltageLevel1Breaker1"); assertTrue(voltageLevel1Breaker1 != null); assertTrue(voltageLevel1Breaker1.getId().equals("voltageLevel1Breaker1")); diff --git a/iidm/iidm-test/src/main/java/eu/itesla_project/iidm/network/test/FictitiousSwitchFactory.java b/iidm/iidm-test/src/main/java/eu/itesla_project/iidm/network/test/FictitiousSwitchFactory.java index 6596e6d7..5219c374 100644 --- a/iidm/iidm-test/src/main/java/eu/itesla_project/iidm/network/test/FictitiousSwitchFactory.java +++ b/iidm/iidm-test/src/main/java/eu/itesla_project/iidm/network/test/FictitiousSwitchFactory.java @@ -65,7 +65,7 @@ public static Network create() { createSwitch(vlN, "Z", "AA", SwitchKind.DISCONNECTOR, false, true, false, 0, 13); createSwitch(vlN, "AB", "AC", SwitchKind.DISCONNECTOR, false, false, false, 0, 15); createSwitch(vlN, "AD", "AE", SwitchKind.DISCONNECTOR, false, true, false, 0, 8); - createSwitch(vlN, "AF", "AG", SwitchKind.DISCONNECTOR, false, true, false, 0, 2); + createSwitch(vlN, "AF", "AG", SwitchKind.DISCONNECTOR, false, true, true, 0, 2); createSwitch(vlN, "AH", "AI", SwitchKind.DISCONNECTOR, false, false, false, 7, 0); createSwitch(vlN, "AJ", "AK", SwitchKind.DISCONNECTOR, false, false, false, 1, 6); createSwitch(vlN, "AL", "AM", SwitchKind.DISCONNECTOR, false, false, false, 1, 19); @@ -75,8 +75,8 @@ public static Network create() { createSwitch(vlN, "AT", "AU", SwitchKind.DISCONNECTOR, false, true, false, 1, 13); createSwitch(vlN, "AV", "AW", SwitchKind.DISCONNECTOR, false, true, false, 1, 15); createSwitch(vlN, "AX", "AY", SwitchKind.DISCONNECTOR, false, false, false, 1, 8); - createSwitch(vlN, "AZ", "BA", SwitchKind.DISCONNECTOR, false, true, false, 1, 2); - createSwitch(vlN, "BB", "BC", SwitchKind.BREAKER, true, true, false, 2, 3); + createSwitch(vlN, "AZ", "BA", SwitchKind.DISCONNECTOR, false, true, true, 1, 2); + createSwitch(vlN, "BB", "BC", SwitchKind.BREAKER, true, true, true, 2, 3); createSwitch(vlN, "BD", "BE", SwitchKind.BREAKER, true, false, false, 3, 4); createSwitch(vlN, "BF", "BG", SwitchKind.DISCONNECTOR, false, false, false, 3, 5); createSwitch(vlN, "BH", "BI", SwitchKind.DISCONNECTOR, false, true, false, 9, 3); diff --git a/iidm/iidm-xml-converter/src/test/resources/fictitiousSwitchRef.xml b/iidm/iidm-xml-converter/src/test/resources/fictitiousSwitchRef.xml index 8879dfe6..6d951dfb 100644 --- a/iidm/iidm-xml-converter/src/test/resources/fictitiousSwitchRef.xml +++ b/iidm/iidm-xml-converter/src/test/resources/fictitiousSwitchRef.xml @@ -21,7 +21,7 @@