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 2 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
85 changes: 85 additions & 0 deletions emf/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?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>

<!-- Runtime dependencies -->
Copy link
Contributor

Choose a reason for hiding this comment

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

You can move these dependencies in test scope rather than runtime

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

</project>
235 changes: 235 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,235 @@
/*
* Copyright (c) 2022, RTE (http://www.rte-france.com)
Copy link
Contributor

Choose a reason for hiding this comment

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

*2023

* 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/.
*/
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.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 static org.junit.jupiter.api.Assertions.assertNotNull;

class IGMmergeTests {
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?


@Test
void igmsDestructiveMerge() throws IOException {

FileSystem fs = Jimfs.newFileSystem(Configuration.unix());
Copy link
Contributor

Choose a reason for hiding this comment

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

You can put this initialization in a setUp method annotated @Before


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 {

FileSystem fs = Jimfs.newFileSystem(Configuration.unix());
Copy link
Contributor

Choose a reason for hiding this comment

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

Same remark


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 {
//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());

FileSystem fs = Jimfs.newFileSystem(Configuration.unix());
Copy link
Contributor

Choose a reason for hiding this comment

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

Same remark


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

networkBENL.getBranches().forEach(b -> branchIds.add(b.getId()));
Copy link
Contributor

Choose a reason for hiding this comment

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

To prevent the encoding error (it will not be added in this release), do

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

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks.

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);
}

public void validate(Network n, Set<String> branchIds, Set<String> generatorsId, Set<String> voltageLevelIds) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can be static and private

branchIds.forEach(b -> assertNotNull(n.getBranch(b)));
generatorsId.forEach(g -> assertNotNull(n.getGenerator(g)));
voltageLevelIds.forEach(v -> assertNotNull(n.getVoltageLevel(v)));
}

public void exportNetwork(Network network, Path outputDir, String baseName, Map<String, Network> validNetworks, Set<String> profilesToExport) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can be static and private

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")) {
exportEquipment(network, context, filenameEq);
}
if (profilesToExport.contains("TP")) {
exportTopology(network, context, filenameTp);
}
if (profilesToExport.contains("SSH")) {
exportSteadyStateHypothesis(network, context, filenameSsh);
}
if (profilesToExport.contains("SV")) {
exportStateVariable(network, context, filenameSv);
}
}

public void exportEquipment(Network network, CgmesExportContext context, Path file) {
try (OutputStream out = Files.newOutputStream(file)) {
XMLStreamWriter writer = XmlUtil.initializeWriter(true, " ", out);
EquipmentExport.write(network, writer, context);
} catch (IOException | XMLStreamException e) {
throw new RuntimeException(e);
}
}

public void exportTopology(Network network, CgmesExportContext context, Path file) {
try (OutputStream out = Files.newOutputStream(file)) {
XMLStreamWriter writer = XmlUtil.initializeWriter(true, " ", out);
TopologyExport.write(network, writer, context);
} catch (IOException | XMLStreamException e) {
throw new RuntimeException(e);
}
}

public void exportSteadyStateHypothesis(Network network, CgmesExportContext context, Path file) {
try (OutputStream out = Files.newOutputStream(file)) {
XMLStreamWriter writer = XmlUtil.initializeWriter(true, " ", out);
SteadyStateHypothesisExport.write(network, writer, context);
} catch (XMLStreamException | IOException e) {
throw new RuntimeException(e);
}
}

public void exportStateVariable(Network network, CgmesExportContext context, Path file) {
try (OutputStream out = Files.newOutputStream(file)) {
XMLStreamWriter writer = XmlUtil.initializeWriter(true, " ", out);
StateVariablesExport.write(network, writer, context);
} 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