MatpowerImporterTest.java
/**
* Copyright (c) 2020, 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
*/
package com.powsybl.matpower.converter;
import com.powsybl.commons.datasource.DirectoryDataSource;
import com.powsybl.commons.test.AbstractSerDeTest;
import com.powsybl.iidm.network.Importer;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.NetworkFactory;
import com.powsybl.iidm.serde.NetworkSerDe;
import com.powsybl.loadflow.LoadFlowParameters;
import com.powsybl.loadflow.resultscompletion.LoadFlowResultsCompletion;
import com.powsybl.loadflow.resultscompletion.LoadFlowResultsCompletionParameters;
import com.powsybl.loadflow.validation.ValidationConfig;
import com.powsybl.loadflow.validation.ValidationType;
import com.powsybl.matpower.model.MBus;
import com.powsybl.matpower.model.MatpowerModel;
import com.powsybl.matpower.model.MatpowerModelFactory;
import com.powsybl.matpower.model.MatpowerWriter;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Properties;
import static com.powsybl.commons.test.ComparisonUtils.assertXmlEquals;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author Christian Biasuzzi {@literal <christian.biasuzzi@techrain.eu>}
*/
class MatpowerImporterTest extends AbstractSerDeTest {
private static final LocalDate DEFAULTDATEFORTESTS = LocalDate.of(2020, Month.JANUARY, 1);
@Test
void baseTest() {
Importer importer = new MatpowerImporter();
assertEquals("MATPOWER", importer.getFormat());
assertEquals("MATPOWER Format to IIDM converter", importer.getComment());
assertEquals(List.of("mat"), importer.getSupportedExtensions());
assertEquals(1, importer.getParameters().size());
assertEquals("matpower.import.ignore-base-voltage", importer.getParameters().get(0).getName());
}
@Test
void copyTest() throws IOException {
MatpowerModel model = MatpowerModelFactory.create9();
Path matpowerBinCase = tmpDir.resolve(model.getCaseName() + ".mat");
MatpowerWriter.write(model, matpowerBinCase, true);
new MatpowerImporter().copy(new DirectoryDataSource(tmpDir, model.getCaseName()),
new DirectoryDataSource(tmpDir, "copy"));
assertTrue(Files.exists(tmpDir.resolve("copy.mat")));
}
@Test
void existsTest() throws IOException {
MatpowerModel model = MatpowerModelFactory.create118();
Path matpowerBinCase = tmpDir.resolve(model.getCaseName() + ".mat");
MatpowerWriter.write(model, matpowerBinCase, true);
assertTrue(new MatpowerImporter().exists(new DirectoryDataSource(tmpDir, model.getCaseName())));
assertFalse(new MatpowerImporter().exists(new DirectoryDataSource(tmpDir, "doesnotexist")));
}
@Test
void testCase9() throws IOException {
testCase(MatpowerModelFactory.create9());
}
@Test
void testCase9limits() throws IOException {
testCase(MatpowerModelFactory.create9limits());
}
@Test
void testCase14() throws IOException {
testCase(MatpowerModelFactory.create14());
}
@Test
void testCase14WithPhaseShifter() throws IOException {
testCase(MatpowerModelFactory.create14WithPhaseShifter());
}
@Test
void testCase14WithPhaseShifterZeroRatioIssue() throws IOException {
testCase(MatpowerModelFactory.readModelJsonFromResources("ieee14-phase-shifter-zero-ratio-issue.json"));
}
@Test
void testCase14WithPhaseShifterSolved() throws IOException {
testCaseSolved(MatpowerModelFactory.create14WithPhaseShifter());
}
@Test
void testCase14WithInvertedVoltageLimits() throws IOException {
MatpowerModel model14 = MatpowerModelFactory.create14();
model14.setCaseName("ieee14-inverted-voltage-limits");
MBus bus1 = model14.getBusByNum(1);
bus1.setMinimumVoltageMagnitude(1.1);
bus1.setMaximumVoltageMagnitude(0.9);
testCase(model14);
}
@Test
void testCase30() throws IOException {
testCase(MatpowerModelFactory.create30());
}
@Test
void testCase30ConsideringBaseVoltage() throws IOException {
MatpowerModel model = MatpowerModelFactory.create30();
model.setCaseName("ieee30-considering-base-voltage");
Properties properties = new Properties();
properties.put("matpower.import.ignore-base-voltage", false);
testCase(model, properties);
}
@Test
void testCase57() throws IOException {
testCase(MatpowerModelFactory.create57());
}
@Test
void testCase118() throws IOException {
testCase(MatpowerModelFactory.create118());
}
@Test
void testCase300() throws IOException {
testCase(MatpowerModelFactory.create300());
}
@Test
void testCase9zeroimpedance() throws IOException {
testCase(MatpowerModelFactory.create9zeroimpedance());
}
@Test
void testCase9DcLine() throws IOException {
testCase(MatpowerModelFactory.create9Dcline());
}
@Test
void testNonexistentCase() {
assertThrows(UncheckedIOException.class, () -> testNetwork(new MatpowerImporter().importData(new DirectoryDataSource(tmpDir, "unknown"), NetworkFactory.findDefault(), null)));
}
private void testCase(MatpowerModel model) throws IOException {
testCase(model, null);
}
private void testCase(MatpowerModel model, Properties properties) throws IOException {
String caseId = model.getCaseName();
Path matFile = tmpDir.resolve(caseId + ".mat");
MatpowerWriter.write(model, matFile, true);
Network network = new MatpowerImporter().importData(new DirectoryDataSource(tmpDir, caseId), NetworkFactory.findDefault(), properties);
testNetwork(network, caseId);
}
private void testNetwork(Network network, String id) throws IOException {
//set the case date of the network to be tested to a default value to match the saved networks' date
ZonedDateTime caseDateTime = DEFAULTDATEFORTESTS.atStartOfDay(ZoneOffset.UTC.normalized());
network.setCaseDate(ZonedDateTime.ofInstant(caseDateTime.toInstant(), ZoneOffset.UTC));
String fileName = id + ".xiidm";
Path file = tmpDir.resolve(fileName);
NetworkSerDe.write(network, file);
try (InputStream is = Files.newInputStream(file)) {
assertXmlEquals(getClass().getResourceAsStream("/" + fileName), is);
}
}
private void testNetwork(Network network) throws IOException {
testNetwork(network, network.getId());
}
private void testCaseSolved(MatpowerModel model) throws IOException {
String caseId = model.getCaseName();
Path matFile = tmpDir.resolve(caseId + ".mat");
MatpowerWriter.write(model, matFile, true);
Network network = new MatpowerImporter().importData(new DirectoryDataSource(tmpDir, caseId), NetworkFactory.findDefault(), null);
testSolved(network);
}
private void testSolved(Network network) throws IOException {
// Precision required on bus balances (MVA)
double threshold = 0.0000001;
ValidationConfig config = loadFlowValidationConfig(threshold);
Path work = Files.createDirectories(fileSystem.getPath("/lf-validation" + network.getId()));
computeMissingFlows(network, config.getLoadFlowParameters());
assertTrue(ValidationType.BUSES.check(network, config, work));
}
private static ValidationConfig loadFlowValidationConfig(double threshold) {
ValidationConfig config = ValidationConfig.load();
config.setVerbose(true);
config.setThreshold(threshold);
config.setOkMissingValues(false);
LoadFlowParameters lf = new LoadFlowParameters();
lf.setTwtSplitShuntAdmittance(true);
config.setLoadFlowParameters(lf);
return config;
}
private static void computeMissingFlows(Network network, LoadFlowParameters lfparams) {
LoadFlowResultsCompletionParameters p = new LoadFlowResultsCompletionParameters(
LoadFlowResultsCompletionParameters.EPSILON_X_DEFAULT,
LoadFlowResultsCompletionParameters.APPLY_REACTANCE_CORRECTION_DEFAULT,
LoadFlowResultsCompletionParameters.Z0_THRESHOLD_DIFF_VOLTAGE_ANGLE);
LoadFlowResultsCompletion lf = new LoadFlowResultsCompletion(p, lfparams);
lf.run(network, null);
}
}