Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EMF module and merge tests #82

Merged
merged 7 commits into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions emf/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>powsybl-entsoe</artifactId>
<groupId>com.powsybl</groupId>
<version>2.2.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>powsybl-emf</artifactId>
<name>European merging function algorithm</name>
<description>Implementation of european merging function algorithm</description>

<dependencies>
<dependency>
<groupId>com.powsybl</groupId>
<artifactId>powsybl-commons</artifactId>
</dependency>
<dependency>
<groupId>com.powsybl</groupId>
<artifactId>powsybl-iidm-api</artifactId>
</dependency>
<dependency>
<groupId>com.powsybl</groupId>
<artifactId>powsybl-cgmes-extensions</artifactId>
</dependency>
<dependency>
<groupId>com.powsybl</groupId>
<artifactId>powsybl-cgmes-conversion</artifactId>
</dependency>
<dependency>
<groupId>com.powsybl</groupId>
<artifactId>powsybl-iidm-mergingview</artifactId>
</dependency>
<dependency>
<groupId>com.powsybl</groupId>
<artifactId>powsybl-cgmes-conformity</artifactId>
</dependency>
<dependency>
<groupId>com.powsybl</groupId>
<artifactId>powsybl-cgmes-model</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.google.jimfs</groupId>
<artifactId>jimfs</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.powsybl</groupId>
<artifactId>powsybl-config-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit-jupiter.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.powsybl</groupId>
<artifactId>powsybl-iidm-impl</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.powsybl</groupId>
<artifactId>powsybl-open-loadflow</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.powsybl</groupId>
<artifactId>powsybl-triple-store-impl-rdf4j</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
222 changes: 222 additions & 0 deletions emf/src/test/java/com/powsybl/emf/IGMmergeTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
/*
* Copyright (c) 2023, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add the SPDX?

package com.powsybl.emf;

import com.google.common.jimfs.Configuration;
import com.google.common.jimfs.Jimfs;
import com.powsybl.cgmes.conformity.CgmesConformity1Catalog;
import com.powsybl.cgmes.conversion.export.*;
import com.powsybl.cgmes.model.test.TestGridModelResources;
import com.powsybl.commons.datasource.GenericReadOnlyDataSource;
import com.powsybl.commons.datasource.ResourceSet;
import com.powsybl.commons.xml.XmlUtil;
import com.powsybl.iidm.mergingview.MergingView;
import com.powsybl.iidm.network.Network;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.function.Consumer;

import static org.junit.jupiter.api.Assertions.assertNotNull;

/**
* @author Bertrand Rix <bertrand.rix at artelys.com>
*/
class IGMmergeTests {
miovd marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add your name as @author in the javadoc?


private FileSystem fs;

@BeforeEach
public void setUp() {
fs = Jimfs.newFileSystem(Configuration.unix());
}

miovd marked this conversation as resolved.
Show resolved Hide resolved
@AfterEach
public void tearDown() throws IOException {
fs.close();
}

@Test
void igmsDestructiveMerge() throws IOException {
miovd marked this conversation as resolved.
Show resolved Hide resolved

Set<String> branchIds = new HashSet<>();
Set<String> generatorsId = new HashSet<>();
Set<String> voltageLevelIds = new HashSet<>();

//Load two IGMs BE and NL
Map<String, Network> validNetworks = new HashMap<>();
TestGridModelResources resBE = CgmesConformity1Catalog.microGridBaseCaseBE();
Network igmBE = Network.read(resBE.dataSource());
validNetworks.put("BE", igmBE);
igmBE.getBranches().forEach(b -> branchIds.add(b.getId()));
igmBE.getGenerators().forEach(g -> generatorsId.add(g.getId()));
igmBE.getVoltageLevels().forEach(v -> voltageLevelIds.add(v.getId()));

TestGridModelResources resNL = CgmesConformity1Catalog.microGridBaseCaseNL();
Network igmNL = Network.read(resNL.dataSource());
validNetworks.put("NL", igmNL);
igmNL.getBranches().forEach(b -> branchIds.add(b.getId()));
igmNL.getGenerators().forEach(g -> generatorsId.add(g.getId()));
igmNL.getVoltageLevels().forEach(v -> voltageLevelIds.add(v.getId()));

//Merge, Serialize and Deserialize the network
igmBE.merge(igmNL);
validNetworks.put("Merged", igmBE);

Path destructiveMergeDir = Files.createDirectory(fs.getPath("/destructiveMerge"));
exportNetwork(igmBE, destructiveMergeDir, "BE_NL", validNetworks, Set.of("EQ", "TP", "SSH", "SV"));

//Copy the boundary set explicitly it is not serialized and is needed for reimport
ResourceSet boundaries = CgmesConformity1Catalog.microGridBaseCaseBoundaries();
for (String bFile : boundaries.getFileNames()) {
Files.copy(boundaries.newInputStream(bFile), destructiveMergeDir.resolve("BE_NL" + bFile));
}

//Reimport and check
Network serializedMergedNetwork = Network.read(new GenericReadOnlyDataSource(destructiveMergeDir, "BE_NL"), null);
validate(serializedMergedNetwork, branchIds, generatorsId, voltageLevelIds);
}

@Test
void igmsMergeWithMergingView() throws IOException {
miovd marked this conversation as resolved.
Show resolved Hide resolved

Set<String> branchIds = new HashSet<>();
Set<String> generatorsId = new HashSet<>();
Set<String> voltageLevelIds = new HashSet<>();

Map<String, Network> validNetworks = new HashMap<>();
TestGridModelResources resBE = CgmesConformity1Catalog.microGridBaseCaseBE();
Network igmBE = Network.read(resBE.dataSource());
validNetworks.put("BE", igmBE);
igmBE.getBranches().forEach(b -> branchIds.add(b.getId()));
igmBE.getGenerators().forEach(g -> generatorsId.add(g.getId()));
igmBE.getVoltageLevels().forEach(v -> voltageLevelIds.add(v.getId()));

TestGridModelResources resNL = CgmesConformity1Catalog.microGridBaseCaseNL();
Network igmNL = Network.read(resNL.dataSource());

MergingView mergingView = MergingView.create("merged", "validation");
mergingView.merge(igmBE, igmNL);
validNetworks.put("NL", igmNL);
igmNL.getBranches().forEach(b -> branchIds.add(b.getId()));
igmNL.getGenerators().forEach(g -> generatorsId.add(g.getId()));
igmNL.getVoltageLevels().forEach(v -> voltageLevelIds.add(v.getId()));
validNetworks.put("Merged", mergingView);

Path mergingViewMergeDir = Files.createDirectory(fs.getPath("/mergingViewMerge"));
//Export to CGMES only state variable of the merged network, the rest is exported separately for each igms
exportNetwork(mergingView, mergingViewMergeDir, "BE_NL", validNetworks, Set.of("SV"));
exportNetwork(igmBE, mergingViewMergeDir, "BE_NL_BE", Map.of("BE", igmBE), Set.of("EQ", "TP", "SSH"));
exportNetwork(igmNL, mergingViewMergeDir, "BE_NL_NL", Map.of("NL", igmNL), Set.of("EQ", "TP", "SSH"));

//Copy the boundary set explicitly it is not serialized and is needed for reimport
ResourceSet boundaries = CgmesConformity1Catalog.microGridBaseCaseBoundaries();
for (String bFile : boundaries.getFileNames()) {
Files.copy(boundaries.newInputStream(bFile), mergingViewMergeDir.resolve("BE_NL" + bFile));
}

Network serializedMergedNetwork = Network.read(new GenericReadOnlyDataSource(mergingViewMergeDir, "BE_NL"), null);
validate(serializedMergedNetwork, branchIds, generatorsId, voltageLevelIds);
}

@Test
void cgmToCgmes() throws IOException {
miovd marked this conversation as resolved.
Show resolved Hide resolved
//Read resources for BE and NL, merge the resources themselves and read a network from this set of resources
TestGridModelResources mergedResourcesBENL = new TestGridModelResources(
"MicroGrid-BaseCase-BE_NL_MergedResources",
null,
new ResourceSet("/conformity/cas-1.1.3-data-4.0.3/MicroGrid/BaseCase/CGMES_v2.4.15_MicroGridTestConfiguration_BC_BE_v2/",
"MicroGridTestConfiguration_BC_BE_DL_V2.xml",
"MicroGridTestConfiguration_BC_BE_DY_V2.xml",
"MicroGridTestConfiguration_BC_BE_EQ_V2.xml",
"MicroGridTestConfiguration_BC_BE_GL_V2.xml",
"MicroGridTestConfiguration_BC_BE_SSH_V2.xml",
"MicroGridTestConfiguration_BC_BE_SV_V2.xml",
"MicroGridTestConfiguration_BC_BE_TP_V2.xml"),
new ResourceSet("/conformity/cas-1.1.3-data-4.0.3/MicroGrid/BaseCase/CGMES_v2.4.15_MicroGridTestConfiguration_BC_NL_v2/",
"MicroGridTestConfiguration_BC_NL_DL_V2.xml",
"MicroGridTestConfiguration_BC_NL_DY_V2.xml",
"MicroGridTestConfiguration_BC_NL_EQ_V2.xml",
"MicroGridTestConfiguration_BC_NL_GL_V2.xml",
"MicroGridTestConfiguration_BC_NL_SSH_V2.xml",
"MicroGridTestConfiguration_BC_NL_SV_V2.xml",
"MicroGridTestConfiguration_BC_NL_TP_V2.xml"),
CgmesConformity1Catalog.microGridBaseCaseBoundaries());
Network networkBENL = Network.read(mergedResourcesBENL.dataSource());

Set<String> branchIds = new HashSet<>();
Set<String> generatorsId = new HashSet<>();
Set<String> voltageLevelIds = new HashSet<>();

//networkBENL.getBranches().forEach(b -> branchIds.add(b.getId()));
networkBENL.getBranches().forEach(b -> branchIds.add(b.getId().replace(" ", "%20"))); // FIXME workaround before fixing CGMES export/import
networkBENL.getGenerators().forEach(g -> generatorsId.add(g.getId()));
networkBENL.getVoltageLevels().forEach(v -> voltageLevelIds.add(v.getId()));

Path mergedResourcesDir = Files.createDirectory(fs.getPath("/mergedResourcesExport"));
exportNetwork(networkBENL, mergedResourcesDir, "BE_NL", Map.of("BENL", networkBENL), Set.of("EQ", "TP", "SSH", "SV"));

//Copy the boundary set explicitly it is not serialized and is needed for reimport
ResourceSet boundaries = CgmesConformity1Catalog.microGridBaseCaseBoundaries();
for (String bFile : boundaries.getFileNames()) {
Files.copy(boundaries.newInputStream(bFile), mergedResourcesDir.resolve("BE_NL" + bFile));
}
Network serializedMergedNetwork = Network.read(new GenericReadOnlyDataSource(mergedResourcesDir, "BE_NL"), null);
validate(serializedMergedNetwork, branchIds, generatorsId, voltageLevelIds);
}

private static void validate(Network n, Set<String> branchIds, Set<String> generatorsId, Set<String> voltageLevelIds) {
branchIds.forEach(b -> assertNotNull(n.getBranch(b)));
generatorsId.forEach(g -> assertNotNull(n.getGenerator(g)));
voltageLevelIds.forEach(v -> assertNotNull(n.getVoltageLevel(v)));
}

private static void exportNetwork(Network network, Path outputDir, String baseName, Map<String, Network> validNetworks, Set<String> profilesToExport) {
Objects.requireNonNull(network);
Path filenameEq = outputDir.resolve(baseName + "_EQ.xml");
Path filenameTp = outputDir.resolve(baseName + "_TP.xml");
Path filenameSsh = outputDir.resolve(baseName + "_SSH.xml");
Path filenameSv = outputDir.resolve(baseName + "_SV.xml");
CgmesExportContext context = new CgmesExportContext();
context.setScenarioTime(network.getCaseDate());
validNetworks.forEach((name, n) -> {
context.addIidmMappings(n);
});

if (profilesToExport.contains("EQ")) {
export(filenameEq, writer -> EquipmentExport.write(network, writer, context));
}
if (profilesToExport.contains("TP")) {
export(filenameTp, writer -> TopologyExport.write(network, writer, context));
}
if (profilesToExport.contains("SSH")) {
export(filenameSsh, writer -> SteadyStateHypothesisExport.write(network, writer, context));
}
if (profilesToExport.contains("SV")) {
export(filenameSv, writer -> StateVariablesExport.write(network, writer, context));
}
}

private static void export(Path file, Consumer<XMLStreamWriter> outConsumer) {
try (OutputStream out = Files.newOutputStream(file)) {
XMLStreamWriter writer = XmlUtil.initializeWriter(true, " ", out);
outConsumer.accept(writer);
} catch (IOException | XMLStreamException e) {
throw new RuntimeException(e);
}
}
}
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
<module>distribution-entsoe</module>
<module>flow-decomposition</module>
<module>glsk</module>
<module>emf</module>
</modules>

<dependencyManagement>
Expand Down