EquipmentExportTest.java
/**
* Copyright (c) 2021, 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.cgmes.conversion.test.export;
import com.powsybl.cgmes.conformity.Cgmes3ModifiedCatalog;
import com.powsybl.cgmes.conformity.Cgmes3Catalog;
import com.powsybl.cgmes.conformity.CgmesConformity1Catalog;
import com.powsybl.cgmes.conformity.CgmesConformity1ModifiedCatalog;
import com.powsybl.cgmes.conversion.CgmesExport;
import com.powsybl.cgmes.conversion.CgmesImport;
import com.powsybl.cgmes.conversion.CgmesModelExtension;
import com.powsybl.cgmes.conversion.Conversion;
import com.powsybl.cgmes.conversion.export.CgmesExportContext;
import com.powsybl.cgmes.conversion.export.EquipmentExport;
import com.powsybl.cgmes.conversion.export.TopologyExport;
import com.powsybl.cgmes.extensions.*;
import com.powsybl.cgmes.model.CgmesNames;
import com.powsybl.commons.test.AbstractSerDeTest;
import com.powsybl.commons.datasource.DirectoryDataSource;
import com.powsybl.commons.datasource.ReadOnlyDataSource;
import com.powsybl.commons.datasource.ResourceDataSource;
import com.powsybl.commons.datasource.ResourceSet;
import com.powsybl.commons.xml.XmlUtil;
import com.powsybl.computation.local.LocalComputationManager;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.RemoteReactivePowerControl;
import com.powsybl.iidm.network.test.*;
import com.powsybl.iidm.serde.ExportOptions;
import com.powsybl.iidm.serde.NetworkSerDe;
import com.powsybl.iidm.serde.XMLImporter;
import com.powsybl.iidm.network.util.BranchData;
import com.powsybl.iidm.network.util.TwtData;
import org.apache.commons.lang3.tuple.Pair;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.xmlunit.diff.DifferenceEvaluator;
import org.xmlunit.diff.DifferenceEvaluators;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.FileSystem;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.google.common.jimfs.Configuration;
import com.google.common.jimfs.Jimfs;
import static com.powsybl.cgmes.conversion.test.ConversionUtil.writeCgmesProfile;
import static com.powsybl.cgmes.conversion.test.ConversionUtil.getFirstMatch;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author Marcos de Miguel {@literal <demiguelm at aia.es>}
*/
class EquipmentExportTest extends AbstractSerDeTest {
private Properties importParams;
@Override
@BeforeEach
public void setUp() throws IOException {
super.setUp();
importParams = new Properties();
importParams.put(CgmesImport.IMPORT_CGM_WITH_SUBNETWORKS, "false");
}
@Test
void smallGridHvdc() throws IOException, XMLStreamException {
ReadOnlyDataSource dataSource = CgmesConformity1Catalog.smallNodeBreakerHvdc().dataSource();
Network expected = new CgmesImport().importData(dataSource, NetworkFactory.findDefault(), importParams);
Network actual = exportImportNodeBreaker(expected, dataSource);
assertTrue(compareNetworksEQdata(expected, actual));
}
@Test
void smallNodeBreaker() throws IOException, XMLStreamException {
ReadOnlyDataSource dataSource = CgmesConformity1Catalog.smallNodeBreaker().dataSource();
Network expected = new CgmesImport().importData(dataSource, NetworkFactory.findDefault(), importParams);
Network actual = exportImportNodeBreaker(expected, dataSource);
assertTrue(compareNetworksEQdata(expected, actual));
}
@Test
void smallBusBranch() throws IOException, XMLStreamException {
ReadOnlyDataSource dataSource = CgmesConformity1Catalog.smallBusBranch().dataSource();
Network expected = new CgmesImport().importData(dataSource, NetworkFactory.findDefault(), importParams);
Network actual = exportImportBusBranch(expected, dataSource);
assertTrue(compareNetworksEQdata(expected, actual));
}
@Test
void miniNodeBreaker() throws IOException, XMLStreamException {
ReadOnlyDataSource dataSource = CgmesConformity1Catalog.miniNodeBreaker().dataSource();
Network expected = new CgmesImport().importData(dataSource, NetworkFactory.findDefault(), importParams);
Network actual = exportImportNodeBreaker(expected, dataSource);
// Avoid negative zeros during the comparison
expected.getGenerators().forEach(generator -> {
generator.setTargetP(generator.getTargetP() + 0.0);
generator.setTargetQ(generator.getTargetQ() + 0.0);
});
actual.getGenerators().forEach(generator -> {
generator.setTargetP(generator.getTargetP() + 0.0);
generator.setTargetQ(generator.getTargetQ() + 0.0);
});
assertTrue(compareNetworksEQdata(expected, actual));
}
@Test
void miniBusBranch() throws IOException, XMLStreamException {
ReadOnlyDataSource dataSource = CgmesConformity1Catalog.miniBusBranch().dataSource();
Network expected = new CgmesImport().importData(dataSource, NetworkFactory.findDefault(), importParams);
Network actual = exportImportBusBranchNoBoundaries(expected, dataSource);
// Avoid negative zeros during the comparison
expected.getGenerators().forEach(generator -> {
generator.setTargetP(generator.getTargetP() + 0.0);
generator.setTargetQ(generator.getTargetQ() + 0.0);
});
actual.getGenerators().forEach(generator -> {
generator.setTargetP(generator.getTargetP() + 0.0);
generator.setTargetQ(generator.getTargetQ() + 0.0);
});
assertTrue(compareNetworksEQdata(expected, actual));
}
@Test
void microGridWithTieFlowMappedToEquivalentInjection() throws IOException, XMLStreamException {
ReadOnlyDataSource dataSource = CgmesConformity1ModifiedCatalog.microGridBaseCaseBEWithTieFlowMappedToEquivalentInjection().dataSource();
Network expected = new CgmesImport().importData(dataSource, NetworkFactory.findDefault(), importParams);
Network actual = exportImportBusBranch(expected, dataSource);
assertTrue(compareNetworksEQdata(expected, actual));
}
@Test
void microGridBaseCaseAssembledSwitchAtBoundary() throws XMLStreamException, IOException {
ReadOnlyDataSource dataSource = CgmesConformity1ModifiedCatalog.microGridBaseCaseAssembledSwitchAtBoundary().dataSource();
Network network = new CgmesImport().importData(dataSource, NetworkFactory.findDefault(), importParams);
// Define a tie flow at the boundary of a dangling line
TieLine tieLine = network.getTieLine("78736387-5f60-4832-b3fe-d50daf81b0a6 + 7f43f508-2496-4b64-9146-0a40406cbe49");
Area area = network.newArea()
.setId("controlAreaId")
.setName("controlAreaName")
.setAreaType(CgmesNames.CONTROL_AREA_TYPE_KIND_INTERCHANGE)
.setInterchangeTarget(Double.NaN)
.addAreaBoundary(tieLine.getDanglingLine2().getBoundary(), true)
.add();
area.addAlias("energyIdentCodeEic", CgmesNames.ENERGY_IDENT_CODE_EIC);
// The reimported network control area should contain one tie flow
Network actual = exportImportBusBranch(network, dataSource);
Area actualControlArea = actual.getArea("controlAreaId");
assertEquals(1, actualControlArea.getAreaBoundaryStream().count());
assertEquals("7f43f508-2496-4b64-9146-0a40406cbe49", actualControlArea.getAreaBoundaries().iterator().next().getBoundary().get().getDanglingLine().getId());
}
@Test
void microGrid() throws IOException, XMLStreamException {
ReadOnlyDataSource dataSource = CgmesConformity1Catalog.microGridType4BE().dataSource();
Network expected = new CgmesImport().importData(dataSource, NetworkFactory.findDefault(), importParams);
Network actual = exportImportBusBranch(expected, dataSource);
assertTrue(compareNetworksEQdata(expected, actual));
}
@Test
void microGridCreateEquivalentInjectionAliases() throws IOException, XMLStreamException {
ReadOnlyDataSource dataSource = CgmesConformity1Catalog.microGridBaseCaseBE().dataSource();
Network expected = new CgmesImport().importData(dataSource, NetworkFactory.findDefault(), importParams);
// Remove aliases of equivalent injections, so they will have to be created during export
for (DanglingLine danglingLine : expected.getDanglingLines(DanglingLineFilter.ALL)) {
danglingLine.removeProperty(Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + CgmesNames.EQUIVALENT_INJECTION);
danglingLine.removeProperty(Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + "EquivalentInjectionTerminal");
}
Network actual = exportImportBusBranch(expected, dataSource);
assertTrue(compareNetworksEQdata(expected, actual));
}
@Test
void nordic32() throws IOException, XMLStreamException {
ReadOnlyDataSource dataSource = new ResourceDataSource("nordic32", new ResourceSet("/", "nordic32.xiidm"));
Network network = new XMLImporter().importData(dataSource, NetworkFactory.findDefault(), null);
exportToCgmesEQ(network);
exportToCgmesTP(network);
// Import EQ & TP file, no additional information (boundaries) are required
Network actual = new CgmesImport().importData(new DirectoryDataSource(tmpDir, "exported"), NetworkFactory.findDefault(), null);
// The xiidm file does not contain ratedS values, but during the cgmes export process default values
// are exported for each transformer that are reading in the import process.
// we reset the default imported ratedS values before comparing
TwoWindingsTransformer twta = actual.getTwoWindingsTransformerStream().findFirst().orElseThrow();
network.getTwoWindingsTransformers().forEach(twtn -> twtn.setRatedS(twta.getRatedS()));
// Ignore OperationalLimitsGroup id
DifferenceEvaluator knownDiffs = DifferenceEvaluators.chain(
DifferenceEvaluators.Default,
ExportXmlCompare::numericDifferenceEvaluator,
ExportXmlCompare::ignoringNonEQ,
ExportXmlCompare::ignoringOperationalLimitsGroupId);
assertTrue(compareNetworksEQdata(network, actual, knownDiffs));
}
@Test
void nordic32SortTransformerEnds() throws IOException, XMLStreamException {
ReadOnlyDataSource dataSource = new ResourceDataSource("nordic32", new ResourceSet("/", "nordic32.xiidm"));
Network network = new XMLImporter().importData(dataSource, NetworkFactory.findDefault(), importParams);
exportToCgmesEQ(network, true);
exportToCgmesTP(network);
// Import EQ & TP file, no additional information (boundaries) are required
Network actual = new CgmesImport().importData(new DirectoryDataSource(tmpDir, "exported"), NetworkFactory.findDefault(), null);
// Before comparing, interchange ends in twoWindingsTransformers that do not follow the high voltage at end1 rule
prepareNetworkForSortedTransformerEndsComparison(network);
// The xiidm file does not contain ratedS values, but during the cgmes export process default values
// are exported for each transformer that are reading in the import process.
// we reset the default imported ratedS values before comparing
TwoWindingsTransformer twta = actual.getTwoWindingsTransformerStream().findFirst().orElseThrow();
network.getTwoWindingsTransformers().forEach(twtn -> twtn.setRatedS(twta.getRatedS()));
// Ignore OperationalLimitsGroup id
DifferenceEvaluator knownDiffs = DifferenceEvaluators.chain(
DifferenceEvaluators.Default,
ExportXmlCompare::numericDifferenceEvaluator,
ExportXmlCompare::ignoringNonEQ,
ExportXmlCompare::ignoringOperationalLimitsGroupId);
assertTrue(compareNetworksEQdata(network, actual, knownDiffs));
}
private void prepareNetworkForSortedTransformerEndsComparison(Network network) {
List<Pair<String, TwtRecord>> pairs = new ArrayList<>();
network.getTwoWindingsTransformerStream().filter(twt -> twt
.getTerminal1().getVoltageLevel().getNominalV() < twt.getTerminal2().getVoltageLevel().getNominalV())
.forEach(twt -> {
TwtRecord twtRecord = obtainRecord(twt);
pairs.add(Pair.of(twt.getId(), twtRecord));
});
pairs.forEach(pair -> {
TwoWindingsTransformer twt = network.getTwoWindingsTransformer(pair.getLeft());
twt.remove();
TwoWindingsTransformer newTwt = pair.getRight().getAdder().add();
Optional<CurrentLimits> currentLimits1 = pair.getRight().getCurrentLimits1();
if (currentLimits1.isPresent()) {
newTwt.newCurrentLimits1().setPermanentLimit(currentLimits1.get().getPermanentLimit()).add();
}
Optional<CurrentLimits> currentLimits2 = pair.getRight().getCurrentLimits2();
if (currentLimits2.isPresent()) {
newTwt.newCurrentLimits2().setPermanentLimit(currentLimits2.get().getPermanentLimit()).add();
}
pair.getRight().getAliases().forEach(aliasPair -> {
if (aliasPair.getLeft() == null) {
newTwt.addAlias(aliasPair.getRight());
} else {
newTwt.addAlias(aliasPair.getRight(), aliasPair.getLeft());
}
});
});
}
private TwtRecord obtainRecord(TwoWindingsTransformer twt) {
Substation substation = twt.getSubstation().orElseThrow();
double a0 = twt.getRatedU1() / twt.getRatedU2();
double a02 = a0 * a0;
TwoWindingsTransformerAdder adder = substation.newTwoWindingsTransformer()
.setId(twt.getId())
.setName(twt.getNameOrId())
.setBus1(twt.getTerminal2().getBusBreakerView().getBus().getId())
.setBus2(twt.getTerminal1().getBusBreakerView().getBus().getId())
.setR(twt.getR() * a02)
.setX(twt.getX() * a02)
.setG(twt.getG() / a02)
.setB(twt.getB() / a02)
.setRatedU1(twt.getRatedU2())
.setRatedU2(twt.getRatedU1());
CurrentLimits currentLimits1 = twt.getCurrentLimits1().orElse(null);
CurrentLimits currentLimits2 = twt.getCurrentLimits2().orElse(null);
List<Pair<String, String>> aliases = new ArrayList<>();
twt.getAliases().forEach(alias -> {
String type = twt.getAliasType(alias).orElse(null);
aliases.add(Pair.of(type, alias));
});
return new TwtRecord(adder, currentLimits2, currentLimits1, aliases);
}
private static final class TwtRecord {
private final TwoWindingsTransformerAdder adder;
private final CurrentLimits currentLimits1;
private final CurrentLimits currentLimits2;
private final List<Pair<String, String>> aliases;
private TwtRecord(TwoWindingsTransformerAdder adder, CurrentLimits currentLimits1, CurrentLimits currentLimits2,
List<Pair<String, String>> aliases) {
this.adder = adder;
this.currentLimits1 = currentLimits1;
this.currentLimits2 = currentLimits2;
this.aliases = aliases;
}
private TwoWindingsTransformerAdder getAdder() {
return adder;
}
private Optional<CurrentLimits> getCurrentLimits1() {
return Optional.ofNullable(currentLimits1);
}
private Optional<CurrentLimits> getCurrentLimits2() {
return Optional.ofNullable(currentLimits2);
}
private List<Pair<String, String>> getAliases() {
return aliases;
}
}
@Test
void bPerSectionTest() throws IOException, XMLStreamException {
ReadOnlyDataSource ds = CgmesConformity1Catalog.microGridType4BE().dataSource();
Network network = new CgmesImport().importData(ds, NetworkFactory.findDefault(), importParams);
ShuntCompensatorLinearModel sh = (ShuntCompensatorLinearModel) network.getShuntCompensator("d771118f-36e9-4115-a128-cc3d9ce3e3da").getModel();
assertEquals(0.024793, sh.getBPerSection(), 0.0);
sh.setBPerSection(1E-14);
Network reimported = exportImportBusBranch(network, ds);
sh = (ShuntCompensatorLinearModel) reimported.getShuntCompensator("d771118f-36e9-4115-a128-cc3d9ce3e3da").getModel();
assertEquals(1E-14, sh.getBPerSection(), 0.0);
}
@Test
void threeWindingsTransformerTest() throws IOException, XMLStreamException {
Network network = createThreeWindingTransformerNetwork();
String t3id = "threeWindingsTransformer1";
// Export an IIDM Network created from scratch, identifiers for tap changers will be created and stored in aliases
exportToCgmesEQ(network);
ThreeWindingsTransformer expected = network.getThreeWindingsTransformer(t3id);
// The 3-winding transformer has a ratio and phase tap changer at every end
Network network1 = new CgmesImport().importData(new DirectoryDataSource(tmpDir, "exportedEq"), NetworkFactory.findDefault(), null);
ThreeWindingsTransformer actual1 = network1.getThreeWindingsTransformer(t3id);
for (int k = 1; k <= 3; k++) {
String aliasType;
aliasType = Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + CgmesNames.RATIO_TAP_CHANGER + k;
assertEquals(
expected.getAliasFromType(aliasType).get(),
actual1.getAliasFromType(aliasType).get());
aliasType = Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + CgmesNames.PHASE_TAP_CHANGER + k;
assertEquals(
expected.getAliasFromType(aliasType).get(),
actual1.getAliasFromType(aliasType).get());
}
// Export an IIDM Network that has been imported from CGMES,
// identifiers for tap changers must be preserved
exportToCgmesEQ(network1);
Network network2 = new CgmesImport().importData(new DirectoryDataSource(tmpDir, "exportedEq"), NetworkFactory.findDefault(), null);
ThreeWindingsTransformer actual2 = network2.getThreeWindingsTransformer(t3id);
for (int k = 1; k <= 3; k++) {
String aliasType;
aliasType = Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + CgmesNames.RATIO_TAP_CHANGER + k;
assertEquals(
expected.getAliasFromType(aliasType).get(),
actual2.getAliasFromType(aliasType).get());
aliasType = Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + CgmesNames.PHASE_TAP_CHANGER + k;
assertEquals(
expected.getAliasFromType(aliasType).get(),
actual2.getAliasFromType(aliasType).get());
}
}
@Test
void twoWindingsTransformerCgmesExportTest() throws IOException, XMLStreamException {
Network network = FourSubstationsNodeBreakerFactory.create();
TwoWindingsTransformer twt = network.getTwoWindingsTransformer("TWT");
assertEquals(225.0, twt.getTerminal1().getVoltageLevel().getNominalV(), 0.0);
assertEquals(400.0, twt.getTerminal2().getVoltageLevel().getNominalV(), 0.0);
// Change the tap position to have a ratio != 1.0
// Models are only equivalent if G and B are zero
twt.setB(0.0);
twt.getRatioTapChanger().setTapPosition(0);
// Voltage at both ends of the transformer
Bus bus400 = twt.getTerminal2().getBusView().getBus();
bus400.setV(400.0).setAngle(0.0);
Bus bus225 = twt.getTerminal1().getBusView().getBus();
bus225.setV(264.38396259257394).setAngle(2.4025237265837864);
BranchData twtData = new BranchData(twt, 0.0, false, false);
// Export network as cgmes files and re-import again,
// the ends of the transformer must be sorted
// to have the high nominal voltage at end1
Network networkSorted = exportImportNodeBreakerNoBoundaries(network);
TwoWindingsTransformer twtSorted = networkSorted.getTwoWindingsTransformer("TWT");
assertEquals(400.0, twtSorted.getTerminal1().getVoltageLevel().getNominalV(), 0.0);
assertEquals(225.0, twtSorted.getTerminal2().getVoltageLevel().getNominalV(), 0.0);
assertTrue(compareCurrentLimits(twt.getCurrentLimits1().orElse(null), twtSorted.getCurrentLimits2().orElse(null)));
assertTrue(compareCurrentLimits(twt.getCurrentLimits2().orElse(null), twtSorted.getCurrentLimits1().orElse(null)));
// Voltage at both ends of the transformer
Bus busS400 = twtSorted.getTerminal1().getBusView().getBus();
busS400.setV(400.0).setAngle(0.0);
Bus busS225 = twtSorted.getTerminal2().getBusView().getBus();
busS225.setV(264.38396259257394).setAngle(2.4025237265837864);
BranchData twtDataSorted = new BranchData(twtSorted, 0.0, false, false);
double tol = 0.0000001;
assertEquals(twtData.getComputedP1(), twtDataSorted.getComputedP2(), tol);
assertEquals(twtData.getComputedQ1(), twtDataSorted.getComputedQ2(), tol);
assertEquals(twtData.getComputedP2(), twtDataSorted.getComputedP1(), tol);
assertEquals(twtData.getComputedQ2(), twtDataSorted.getComputedQ1(), tol);
}
@Test
void twoWindingsTransformerWithShuntAdmittanceCgmesExportTest() throws IOException, XMLStreamException {
Network network = FourSubstationsNodeBreakerFactory.create();
TwoWindingsTransformer twt = network.getTwoWindingsTransformer("TWT");
assertEquals(225.0, twt.getTerminal1().getVoltageLevel().getNominalV(), 0.0);
assertEquals(400.0, twt.getTerminal2().getVoltageLevel().getNominalV(), 0.0);
// Change the tap position to have a ratio != 1.0
twt.getRatioTapChanger().setTapPosition(0);
// Voltage at both ends of the transformer
Bus bus400 = twt.getTerminal2().getBusView().getBus();
bus400.setV(400.0).setAngle(0.0);
Bus bus225 = twt.getTerminal1().getBusView().getBus();
bus225.setV(264.38396259257394).setAngle(2.4025237265837864);
BranchData twtData = new BranchData(twt, 0.0, false, false);
// Export network as cgmes files and re-import again,
// the ends of the transformer must be sorted
// to have the high nominal voltage at end1
Network networkSorted = exportImportNodeBreakerNoBoundaries(network);
TwoWindingsTransformer twtSorted = networkSorted.getTwoWindingsTransformer("TWT");
assertEquals(400.0, twtSorted.getTerminal1().getVoltageLevel().getNominalV(), 0.0);
assertEquals(225.0, twtSorted.getTerminal2().getVoltageLevel().getNominalV(), 0.0);
assertTrue(compareCurrentLimits(twt.getCurrentLimits1().orElse(null), twtSorted.getCurrentLimits2().orElse(null)));
assertTrue(compareCurrentLimits(twt.getCurrentLimits2().orElse(null), twtSorted.getCurrentLimits1().orElse(null)));
// Voltage at both ends of the transformer
Bus busS400 = twtSorted.getTerminal1().getBusView().getBus();
busS400.setV(400.0).setAngle(0.0);
Bus busS225 = twtSorted.getTerminal2().getBusView().getBus();
busS225.setV(264.38396259257394).setAngle(2.4025237265837864);
BranchData twtDataSorted = new BranchData(twtSorted, 0.0, false, false);
// Models are only equivalent if G and B are zero
double tol = 0.0000001;
assertEquals(twtData.getComputedP1(), twtDataSorted.getComputedP2(), tol);
assertEquals(-12.553777142703378, twtData.getComputedQ1(), tol);
assertEquals(-7.446222857261597, twtDataSorted.getComputedQ2(), tol);
assertEquals(twtData.getComputedP2(), twtDataSorted.getComputedP1(), tol);
assertEquals(7.871048170667905, twtData.getComputedQ2(), tol);
assertEquals(2.751048170611625, twtDataSorted.getComputedQ1(), tol);
}
@Test
void threeWindingsTransformerCgmesExportTest() throws IOException, XMLStreamException {
Network network = ThreeWindingsTransformerNetworkFactory.createWithUnsortedEndsAndCurrentLimits();
ThreeWindingsTransformer twt = network.getThreeWindingsTransformer("3WT");
assertEquals(11.0, twt.getLeg1().getTerminal().getVoltageLevel().getNominalV(), 0.0);
assertEquals(132.0, twt.getLeg2().getTerminal().getVoltageLevel().getNominalV(), 0.0);
assertEquals(33.0, twt.getLeg3().getTerminal().getVoltageLevel().getNominalV(), 0.0);
// Set the voltage at each end for calculating flows and voltage at the star bus
Bus bus132 = twt.getLeg2().getTerminal().getBusView().getBus();
bus132.setV(135.0).setAngle(0.0);
Bus bus33 = twt.getLeg3().getTerminal().getBusView().getBus();
bus33.setV(28.884977348881097).setAngle(-0.7602433704291399);
Bus bus11 = twt.getLeg1().getTerminal().getBusView().getBus();
bus11.setV(11.777636198340568).setAngle(-0.78975650100671);
TwtData twtData = new TwtData(twt, 0.0, false);
// Export network as cgmes files and re-import again,
// the ends of the transformer must be sorted
// in concordance with nominal voltage
Network networkSorted = exportImportNodeBreakerNoBoundaries(network);
ThreeWindingsTransformer twtSorted = networkSorted.getThreeWindingsTransformer("3WT");
assertEquals(132.0, twtSorted.getLeg1().getTerminal().getVoltageLevel().getNominalV(), 0.0);
assertEquals(33.0, twtSorted.getLeg2().getTerminal().getVoltageLevel().getNominalV(), 0.0);
assertEquals(11.0, twtSorted.getLeg3().getTerminal().getVoltageLevel().getNominalV(), 0.0);
assertTrue(compareCurrentLimits(twt.getLeg2().getCurrentLimits().orElse(null), twtSorted.getLeg1().getCurrentLimits().orElse(null)));
assertTrue(compareCurrentLimits(twt.getLeg3().getCurrentLimits().orElse(null), twtSorted.getLeg2().getCurrentLimits().orElse(null)));
assertTrue(compareCurrentLimits(twt.getLeg1().getCurrentLimits().orElse(null), twtSorted.getLeg3().getCurrentLimits().orElse(null)));
// Set the voltage at each end for calculating flows and voltage at the star bus
Bus busS132 = twtSorted.getLeg1().getTerminal().getBusView().getBus();
busS132.setV(135.0).setAngle(0.0);
Bus busS33 = twtSorted.getLeg2().getTerminal().getBusView().getBus();
busS33.setV(28.884977348881097).setAngle(-0.7602433704291399);
Bus busS11 = twtSorted.getLeg3().getTerminal().getBusView().getBus();
busS11.setV(11.777636198340568).setAngle(-0.78975650100671);
TwtData twtDataSorted = new TwtData(twtSorted, 0.0, false);
// star bus voltage must be checked in per unit as it depends on the ratedU0 (vnominal0 = ratedU0)
double tol = 0.0000001;
assertEquals(twtData.getStarU() / twt.getRatedU0(), twtDataSorted.getStarU() / twtDataSorted.getRatedU0(), tol);
assertEquals(twtData.getStarTheta(), twtDataSorted.getStarTheta(), tol);
assertEquals(twtData.getComputedP(ThreeSides.ONE), twtDataSorted.getComputedP(ThreeSides.THREE), tol);
assertEquals(twtData.getComputedQ(ThreeSides.ONE), twtDataSorted.getComputedQ(ThreeSides.THREE), tol);
assertEquals(twtData.getComputedP(ThreeSides.TWO), twtDataSorted.getComputedP(ThreeSides.ONE), tol);
assertEquals(twtData.getComputedQ(ThreeSides.TWO), twtDataSorted.getComputedQ(ThreeSides.ONE), tol);
assertEquals(twtData.getComputedP(ThreeSides.THREE), twtDataSorted.getComputedP(ThreeSides.TWO), tol);
assertEquals(twtData.getComputedQ(ThreeSides.THREE), twtDataSorted.getComputedQ(ThreeSides.TWO), tol);
}
private static boolean compareCurrentLimits(CurrentLimits expected, CurrentLimits actual) {
if (expected == null && actual == null) {
return true;
}
if (expected != null && actual != null) {
return expected.getPermanentLimit() == actual.getPermanentLimit();
}
return false;
}
@Test
void testLoadGroups() throws XMLStreamException, IOException {
ReadOnlyDataSource dataSource = CgmesConformity1ModifiedCatalog.microGridBaseCaseBEConformNonConformLoads().dataSource();
Network expected = new CgmesImport().importData(dataSource, NetworkFactory.findDefault(), importParams);
Network actual = exportImportBusBranch(expected, dataSource);
assertTrue(compareNetworksEQdata(expected, actual));
}
@Test
void microGridCgmesExportPreservingOriginalClassesOfLoads() throws IOException, XMLStreamException {
ReadOnlyDataSource dataSource = Cgmes3ModifiedCatalog.microGridBaseCaseAllTypesOfLoads().dataSource();
importParams.put("iidm.import.cgmes.convert-boundary", "true");
Network expected = Network.read(dataSource, importParams);
importParams.put("iidm.import.cgmes.convert-boundary", "false");
Network actual = exportImportNodeBreaker(expected, dataSource);
assertEquals(loadsCreatedFromOriginalClassCount(expected, CgmesNames.ASYNCHRONOUS_MACHINE), loadsCreatedFromOriginalClassCount(actual, CgmesNames.ASYNCHRONOUS_MACHINE));
assertEquals(loadsCreatedFromOriginalClassCount(expected, CgmesNames.ENERGY_SOURCE), loadsCreatedFromOriginalClassCount(actual, CgmesNames.ENERGY_SOURCE));
assertEquals(loadsCreatedFromOriginalClassCount(expected, CgmesNames.SV_INJECTION), loadsCreatedFromOriginalClassCount(actual, CgmesNames.SV_INJECTION));
assertEquals(loadsCreatedFromOriginalClassCount(expected, CgmesNames.ENERGY_CONSUMER), loadsCreatedFromOriginalClassCount(actual, CgmesNames.ENERGY_CONSUMER));
assertEquals(loadsCreatedFromOriginalClassCount(expected, CgmesNames.CONFORM_LOAD), loadsCreatedFromOriginalClassCount(actual, CgmesNames.CONFORM_LOAD));
assertEquals(loadsCreatedFromOriginalClassCount(expected, CgmesNames.NONCONFORM_LOAD), loadsCreatedFromOriginalClassCount(actual, CgmesNames.NONCONFORM_LOAD));
assertEquals(loadsCreatedFromOriginalClassCount(expected, CgmesNames.STATION_SUPPLY), loadsCreatedFromOriginalClassCount(actual, CgmesNames.STATION_SUPPLY));
// Areas must be preserved
// The input test case contains 2 control areas of type interchange,
// that must be exported and reimported
// Avoid comparing targetP and targetQ, as reimport does not consider the SSH file
expected.getGenerators().forEach(expectedGenerator -> {
Generator actualGenerator = actual.getGenerator(expectedGenerator.getId());
actualGenerator.setTargetP(expectedGenerator.getTargetP());
actualGenerator.setTargetQ(expectedGenerator.getTargetQ());
});
DifferenceEvaluator knownDiffs = DifferenceEvaluators.chain(
DifferenceEvaluators.Default,
ExportXmlCompare::numericDifferenceEvaluator,
ExportXmlCompare::ignoringSubstationNumAttributes,
ExportXmlCompare::ignoringSubstationLookup,
ExportXmlCompare::ignoringGeneratorAttributes,
ExportXmlCompare::ignoringLoadChildNodeListLength);
assertTrue(compareNetworksEQdata(expected, actual, knownDiffs));
}
private static long loadsCreatedFromOriginalClassCount(Network network, String originalClass) {
return network.getLoadStream().filter(load -> loadOriginalClass(load, originalClass)).count();
}
private static boolean loadOriginalClass(Load load, String originalClass) {
String cgmesClass = load.getProperty(Conversion.PROPERTY_CGMES_ORIGINAL_CLASS);
return cgmesClass != null && cgmesClass.equals(originalClass);
}
@Test
void testExportEquivalentInjectionBaseVoltage() throws IOException {
// Ensure equivalent injections outside boundaries are exported with a reference to a base voltage
// Create a minimal network with a generator labelled as CGMES equivalent injection
Network network = Network.create("testEIexport", "IIDM");
VoltageLevel vl = network.newVoltageLevel().setId("VL1").setNominalV(400.0).setTopologyKind(TopologyKind.BUS_BREAKER).add();
vl.getBusBreakerView().newBus().setId("Bus1").add();
Generator g = vl.newGenerator().setId("Generator1").setBus("Bus1")
.setVoltageRegulatorOn(true).setTargetV(400)
.setTargetP(0).setMinP(0).setMaxP(10)
.add();
g.setProperty(Conversion.PROPERTY_CGMES_ORIGINAL_CLASS, "EquivalentInjection");
// Export to CGMES only the EQ instance file
Properties exportParams = new Properties();
exportParams.put(CgmesExport.PROFILES, "EQ");
String basename = "test-EI-export";
network.write("CGMES", exportParams, tmpDir.resolve(basename));
// Read the exported EQ file
String eqFilename = String.format("%s_%s.xml", basename, "EQ");
String eqFileContent = Files.readString(tmpDir.resolve(eqFilename));
// Obtain the equivalent injection reference to base voltage
Pattern eiBaseVoltageRegex = Pattern.compile("(?s)<cim:EquivalentInjection rdf:ID=\"_Generator1\".*ConductingEquipment.BaseVoltage rdf:resource=\"#(.*?)\".*</cim:EquivalentInjection>");
Matcher matcher = eiBaseVoltageRegex.matcher(eqFileContent);
assertTrue(matcher.find());
String eiBaseVoltageId = matcher.group(1);
// Obtain the (unique) base voltage defined in the EQ file
Pattern baseVoltageDefinitionRegex = Pattern.compile("cim:BaseVoltage rdf:ID=\"(.*?)\"");
matcher = baseVoltageDefinitionRegex.matcher(eqFileContent);
assertTrue(matcher.find());
String baseVoltageId = matcher.group(1);
// Check that the equivalent injection base voltage is the base voltage defined in the exported EQ file
assertEquals(baseVoltageId, eiBaseVoltageId);
}
@Test
void miniGridCgmesExportPreservingOriginalClassesOfGenerators() throws IOException, XMLStreamException {
ReadOnlyDataSource dataSource = Cgmes3Catalog.miniGrid().dataSource();
Properties properties = new Properties();
properties.setProperty("iidm.import.cgmes.convert-boundary", "true");
Network expected = new CgmesImport().importData(dataSource, NetworkFactory.findDefault(), properties);
Network actual = exportImportNodeBreaker(expected, dataSource);
assertEquals(generatorsCreatedFromOriginalClassCount(expected, "SynchronousMachine"), generatorsCreatedFromOriginalClassCount(actual, "SynchronousMachine"));
assertEquals(generatorsCreatedFromOriginalClassCount(expected, "ExternalNetworkInjection"), generatorsCreatedFromOriginalClassCount(actual, "ExternalNetworkInjection"));
assertEquals(generatorsCreatedFromOriginalClassCount(expected, "EquivalentInjection"), generatorsCreatedFromOriginalClassCount(actual, "EquivalentInjection"));
// Avoid comparing targetP and targetQ, as reimport does not consider the SSH file
expected.getGenerators().forEach(expectedGenerator -> {
Generator actualGenerator = actual.getGenerator(expectedGenerator.getId());
actualGenerator.setTargetP(expectedGenerator.getTargetP());
actualGenerator.setTargetQ(expectedGenerator.getTargetQ());
});
DifferenceEvaluator knownDiffs = DifferenceEvaluators.chain(
DifferenceEvaluators.Default,
ExportXmlCompare::numericDifferenceEvaluator,
ExportXmlCompare::ignoringSubstationNumAttributes,
ExportXmlCompare::ignoringSubstationLookup);
compareNetworksEQdata(expected, actual, knownDiffs);
}
private static long generatorsCreatedFromOriginalClassCount(Network network, String originalClass) {
return network.getGeneratorStream().filter(generator -> generatorOriginalClass(generator, originalClass)).count();
}
private static boolean generatorOriginalClass(Generator generator, String originalClass) {
String cgmesClass = generator.getProperty(Conversion.PROPERTY_CGMES_ORIGINAL_CLASS);
return cgmesClass != null && cgmesClass.equals(originalClass);
}
@Test
void equivalentShuntTest() throws IOException {
ReadOnlyDataSource ds = CgmesConformity1ModifiedCatalog.microGridBaseCaseBEEquivalentShunt().dataSource();
Network network = new CgmesImport().importData(ds, NetworkFactory.findDefault(), importParams);
// Export as cgmes
Path outputPath = tmpDir.resolve("temp.cgmesExport");
Files.createDirectories(outputPath);
String baseName = "microGridEquivalentShunt";
new CgmesExport().export(network, new Properties(), new DirectoryDataSource(outputPath, baseName));
// re-import after adding the original boundary files
copyBoundary(outputPath, baseName, ds);
Network actual = new CgmesImport().importData(new DirectoryDataSource(outputPath, baseName), NetworkFactory.findDefault(), importParams);
ShuntCompensator expectedEquivalentShunt = network.getShuntCompensator("d771118f-36e9-4115-a128-cc3d9ce3e3da");
ShuntCompensator actualEquivalentShunt = actual.getShuntCompensator("d771118f-36e9-4115-a128-cc3d9ce3e3da");
assertTrue(equivalentShuntsAreEqual(expectedEquivalentShunt, actualEquivalentShunt));
}
@Test
void equivalentShuntWithZeroSectionCountTest() throws IOException {
ReadOnlyDataSource ds = CgmesConformity1ModifiedCatalog.microGridBaseCaseBEEquivalentShunt().dataSource();
Network network = new CgmesImport().importData(ds, NetworkFactory.findDefault(), importParams);
ShuntCompensator equivalentShunt = network.getShuntCompensator("d771118f-36e9-4115-a128-cc3d9ce3e3da");
equivalentShunt.setSectionCount(0);
// Export as cgmes
Path outputPath = tmpDir.resolve("temp.cgmesExport");
Files.createDirectories(outputPath);
String baseName = "microGridEquivalentShunt";
new CgmesExport().export(network, new Properties(), new DirectoryDataSource(outputPath, baseName));
// re-import after adding the original boundary files
copyBoundary(outputPath, baseName, ds);
Network actual = new CgmesImport().importData(new DirectoryDataSource(outputPath, baseName), NetworkFactory.findDefault(), importParams);
ShuntCompensator actualEquivalentShunt = actual.getShuntCompensator("d771118f-36e9-4115-a128-cc3d9ce3e3da");
assertTrue(equivalentShuntsAreEqual(equivalentShunt, actualEquivalentShunt));
// Terminal is disconnected in the actual network as equivalent shunts with
// sectionCount equals to zero are declared as disconnected in the SSH
assertTrue(equivalentShunt.getTerminal().isConnected());
assertFalse(actualEquivalentShunt.getTerminal().isConnected());
}
private static void copyBoundary(Path outputFolder, String baseName, ReadOnlyDataSource originalDataSource) throws IOException {
String eqbd = originalDataSource.listNames(".*EQ_BD.*").stream().findFirst().orElse(null);
if (eqbd != null) {
try (InputStream is = originalDataSource.newInputStream(eqbd)) {
Files.copy(is, outputFolder.resolve(baseName + "_EQ_BD.xml"));
}
}
}
private static boolean equivalentShuntsAreEqual(ShuntCompensator expectedShunt, ShuntCompensator actualShunt) {
if (expectedShunt.getMaximumSectionCount() != actualShunt.getMaximumSectionCount()
|| expectedShunt.getSectionCount() != actualShunt.getSectionCount()
|| expectedShunt.getModelType() != actualShunt.getModelType()
|| expectedShunt.getPropertyNames().size() != actualShunt.getPropertyNames().size()) {
return false;
}
if (expectedShunt.getPropertyNames().stream().anyMatch(propertyName -> !propertyInBothAndEqual(expectedShunt, actualShunt, propertyName))) {
return false;
}
ShuntCompensatorLinearModel expectedModel = (ShuntCompensatorLinearModel) expectedShunt.getModel();
ShuntCompensatorLinearModel actualModel = (ShuntCompensatorLinearModel) actualShunt.getModel();
return expectedModel.getGPerSection() == actualModel.getGPerSection()
&& expectedModel.getBPerSection() == actualModel.getBPerSection();
}
private static boolean propertyInBothAndEqual(ShuntCompensator expected, ShuntCompensator actual, String propertyName) {
if (!actual.hasProperty(propertyName)) {
return false;
}
return expected.getProperty(propertyName).equals(actual.getProperty(propertyName));
}
@Test
void tapChangerControlDefineControlTest() throws IOException {
ReadOnlyDataSource ds = Cgmes3Catalog.microGrid().dataSource();
Network network = new CgmesImport().importData(ds, NetworkFactory.findDefault(), importParams);
TwoWindingsTransformer twtNetwork = network.getTwoWindingsTransformer("e8a7eaec-51d6-4571-b3d9-c36d52073c33");
twtNetwork.getPhaseTapChanger().setRegulationMode(PhaseTapChanger.RegulationMode.ACTIVE_POWER_CONTROL)
.setRegulationValue(75.24)
.setTargetDeadband(2.0)
.setRegulationTerminal(twtNetwork.getTerminal1());
// Export as cgmes
Path outputPath = tmpDir.resolve("temp.cgmesExport");
Files.createDirectories(outputPath);
String baseName = "microGridTapChangerDefineControl";
new CgmesExport().export(network, new Properties(), new DirectoryDataSource(outputPath, baseName));
// re-import after adding the original boundary files
copyBoundary(outputPath, baseName, ds);
Network actual = new CgmesImport().importData(new DirectoryDataSource(outputPath, baseName), NetworkFactory.findDefault(), importParams);
TwoWindingsTransformer twtActual = actual.getTwoWindingsTransformer("e8a7eaec-51d6-4571-b3d9-c36d52073c33");
assertEquals(twtNetwork.getPhaseTapChanger().getRegulationMode().name(), twtActual.getPhaseTapChanger().getRegulationMode().name());
assertEquals(twtNetwork.getPhaseTapChanger().getRegulationValue(), twtActual.getPhaseTapChanger().getRegulationValue());
assertEquals(twtNetwork.getPhaseTapChanger().getTargetDeadband(), twtActual.getPhaseTapChanger().getTargetDeadband());
}
@Test
void tapChangerControlDefineRatioTapChangerAndPhaseTapChangerTest() throws IOException {
ReadOnlyDataSource ds = Cgmes3Catalog.miniGrid().dataSource();
Network network = Network.read(ds, importParams);
TwoWindingsTransformer twtNetwork = network.getTwoWindingsTransformer("ceb5d06a-a7ff-4102-a620-7f3ea5fb4a51");
twtNetwork.newRatioTapChanger()
.setLowTapPosition(0)
.setTapPosition(0)
.beginStep()
.setRho(1.0)
.endStep()
.setTargetV(twtNetwork.getTerminal1().getVoltageLevel().getNominalV())
.setTargetDeadband(2.0)
.setRegulationTerminal(twtNetwork.getTerminal1())
.add();
twtNetwork.newPhaseTapChanger()
.setLowTapPosition(0)
.setTapPosition(0)
.beginStep()
.setRho(1.0)
.setAlpha(0)
.endStep()
.setRegulationMode(PhaseTapChanger.RegulationMode.ACTIVE_POWER_CONTROL)
.setRegulationValue(75.24)
.setTargetDeadband(2.0)
.setRegulationTerminal(twtNetwork.getTerminal1())
.add();
// Export as cgmes
Path outputPath = tmpDir.resolve("temp.cgmesExport");
Files.createDirectories(outputPath);
String baseName = "microGridTapChangerDefineRatioTapChangerAndPhaseTapChanger";
network.write("CGMES", null, new DirectoryDataSource(outputPath, baseName));
// re-import after adding the original boundary files
copyBoundary(outputPath, baseName, ds);
Network actual = new CgmesImport().importData(new DirectoryDataSource(outputPath, baseName), NetworkFactory.findDefault(), importParams);
TwoWindingsTransformer twtActual = actual.getTwoWindingsTransformer("ceb5d06a-a7ff-4102-a620-7f3ea5fb4a51");
assertEquals(twtNetwork.getRatioTapChanger().getTargetV(), twtActual.getRatioTapChanger().getTargetV());
assertEquals(twtNetwork.getRatioTapChanger().getTargetDeadband(), twtActual.getRatioTapChanger().getTargetDeadband());
assertEquals(twtNetwork.getPhaseTapChanger().getRegulationMode().name(), twtActual.getPhaseTapChanger().getRegulationMode().name());
assertEquals(twtNetwork.getPhaseTapChanger().getRegulationValue(), twtActual.getPhaseTapChanger().getRegulationValue());
assertEquals(twtNetwork.getPhaseTapChanger().getTargetDeadband(), twtActual.getPhaseTapChanger().getTargetDeadband());
}
@Test
void tapChangerControlDefineRatioTapChangerAndPhaseTapChangerT3wLeg1Test() throws IOException {
ReadOnlyDataSource ds = Cgmes3Catalog.microGrid().dataSource();
Network network = new CgmesImport().importData(ds, NetworkFactory.findDefault(), importParams);
ThreeWindingsTransformer twtNetwork = network.getThreeWindingsTransformer("84ed55f4-61f5-4d9d-8755-bba7b877a246");
addRatioTapChangerAndPhaseTapChanger(twtNetwork.getLeg1());
// Export as cgmes
Path outputPath = tmpDir.resolve("temp.cgmesExport");
Files.createDirectories(outputPath);
String baseName = "microGridTapChangerDefineRatioTapChangerAndPhaseTapChangerLeg1";
new CgmesExport().export(network, new Properties(), new DirectoryDataSource(outputPath, baseName));
// re-import after adding the original boundary files
copyBoundary(outputPath, baseName, ds);
Network actual = new CgmesImport().importData(new DirectoryDataSource(outputPath, baseName), NetworkFactory.findDefault(), importParams);
ThreeWindingsTransformer twtActual = actual.getThreeWindingsTransformer("84ed55f4-61f5-4d9d-8755-bba7b877a246");
checkLeg(twtNetwork.getLeg1(), twtActual.getLeg1());
}
@Test
void tapChangerControlDefineRatioTapChangerAndPhaseTapChangerT3wLeg2Test() throws IOException {
ReadOnlyDataSource ds = Cgmes3Catalog.miniGrid().dataSource();
Network network = new CgmesImport().importData(ds, NetworkFactory.findDefault(), importParams);
ThreeWindingsTransformer twtNetwork = network.getThreeWindingsTransformer("411b5401-0a43-404a-acb4-05c3d7d0c95c");
addRatioTapChangerAndPhaseTapChanger(twtNetwork.getLeg2());
// Export as cgmes
Path outputPath = tmpDir.resolve("temp.cgmesExport");
Files.createDirectories(outputPath);
String baseName = "microGridTapChangerDefineRatioTapChangerAndPhaseTapChangerLeg2";
new CgmesExport().export(network, new Properties(), new DirectoryDataSource(outputPath, baseName));
// re-import after adding the original boundary files
copyBoundary(outputPath, baseName, ds);
Network actual = new CgmesImport().importData(new DirectoryDataSource(outputPath, baseName), NetworkFactory.findDefault(), importParams);
ThreeWindingsTransformer twtActual = actual.getThreeWindingsTransformer("411b5401-0a43-404a-acb4-05c3d7d0c95c");
checkLeg(twtNetwork.getLeg2(), twtActual.getLeg2());
}
@Test
void tapChangerControlDefineRatioTapChangerAndPhaseTapChangerT3wLeg3Test() throws IOException {
ReadOnlyDataSource ds = Cgmes3Catalog.miniGrid().dataSource();
Network network = new CgmesImport().importData(ds, NetworkFactory.findDefault(), importParams);
ThreeWindingsTransformer twtNetwork = network.getThreeWindingsTransformer("411b5401-0a43-404a-acb4-05c3d7d0c95c");
addRatioTapChangerAndPhaseTapChanger(twtNetwork.getLeg3());
// Export as cgmes
Path outputPath = tmpDir.resolve("temp.cgmesExport");
Files.createDirectories(outputPath);
String baseName = "microGridTapChangerDefineRatioTapChangerAndPhaseTapChangerLeg3";
new CgmesExport().export(network, new Properties(), new DirectoryDataSource(outputPath, baseName));
// re-import after adding the original boundary files
copyBoundary(outputPath, baseName, ds);
Network actual = new CgmesImport().importData(new DirectoryDataSource(outputPath, baseName), NetworkFactory.findDefault(), importParams);
ThreeWindingsTransformer twtActual = actual.getThreeWindingsTransformer("411b5401-0a43-404a-acb4-05c3d7d0c95c");
checkLeg(twtNetwork.getLeg3(), twtActual.getLeg3());
}
private static void addRatioTapChangerAndPhaseTapChanger(ThreeWindingsTransformer.Leg leg) {
leg.newRatioTapChanger()
.setLowTapPosition(0)
.setTapPosition(0)
.beginStep()
.setRho(1.0)
.endStep()
.setTargetV(leg.getTerminal().getVoltageLevel().getNominalV())
.setTargetDeadband(2.0)
.setRegulationTerminal(leg.getTerminal())
.add();
leg.newPhaseTapChanger()
.setLowTapPosition(0)
.setTapPosition(0)
.beginStep()
.setRho(1.0)
.setAlpha(0)
.endStep()
.setRegulationMode(PhaseTapChanger.RegulationMode.ACTIVE_POWER_CONTROL)
.setRegulationValue(75.24)
.setTargetDeadband(2.0)
.setRegulationTerminal(leg.getTerminal())
.add();
}
private static void checkLeg(ThreeWindingsTransformer.Leg legNetwork, ThreeWindingsTransformer.Leg legActual) {
assertEquals(legNetwork.getRatioTapChanger().getTargetV(), legActual.getRatioTapChanger().getTargetV());
assertEquals(legNetwork.getRatioTapChanger().getTargetDeadband(), legActual.getRatioTapChanger().getTargetDeadband());
assertEquals(legNetwork.getPhaseTapChanger().getRegulationMode().name(), legActual.getPhaseTapChanger().getRegulationMode().name());
assertEquals(legNetwork.getPhaseTapChanger().getRegulationValue(), legActual.getPhaseTapChanger().getRegulationValue());
assertEquals(legNetwork.getPhaseTapChanger().getTargetDeadband(), legActual.getPhaseTapChanger().getTargetDeadband());
}
@Test
void fossilFuelExportAndImportTest() throws IOException {
Network network = createOneGeneratorNetwork();
// Define fossilFuelType property
Generator expectedGenerator = network.getGenerator("generator1");
expectedGenerator.setEnergySource(EnergySource.THERMAL);
String expectedFuelType = "gas;lignite";
expectedGenerator.setProperty(Conversion.PROPERTY_FOSSIL_FUEL_TYPE, expectedFuelType);
// Export as cgmes
Path outputPath = tmpDir.resolve("temp.cgmesExport");
Files.createDirectories(outputPath);
String baseName = "oneGeneratorFossilFuel";
new CgmesExport().export(network, new Properties(), new DirectoryDataSource(outputPath, baseName));
// re-import
Network actual = new CgmesImport().importData(new DirectoryDataSource(outputPath, baseName), NetworkFactory.findDefault(), new Properties());
Generator actualGenerator = actual.getGenerator("generator1");
// check the fuelType property
String actualFuelType = actualGenerator.getProperty(Conversion.PROPERTY_FOSSIL_FUEL_TYPE);
assertEquals(expectedFuelType, actualFuelType);
}
@Test
void hydroPowerPlantExportAndImportTest() throws IOException {
Network network = createOneGeneratorNetwork();
// Define hydroPowerPlant property
Generator expectedGenerator = network.getGenerator("generator1");
expectedGenerator.setEnergySource(EnergySource.HYDRO);
String expectedStorageKind = "pumpedStorage";
expectedGenerator.setProperty(Conversion.PROPERTY_HYDRO_PLANT_STORAGE_TYPE, expectedStorageKind);
// Export as cgmes
Path outputPath = tmpDir.resolve("temp.cgmesExport");
Files.createDirectories(outputPath);
String baseName = "oneGeneratorFossilHydroPowerPlant";
new CgmesExport().export(network, new Properties(), new DirectoryDataSource(outputPath, baseName));
// re-import
Network actual = new CgmesImport().importData(new DirectoryDataSource(outputPath, baseName), NetworkFactory.findDefault(), new Properties());
Generator actualGenerator = actual.getGenerator("generator1");
// check the storage kind property
String actualStorageKind = actualGenerator.getProperty(Conversion.PROPERTY_HYDRO_PLANT_STORAGE_TYPE);
assertEquals(expectedStorageKind, actualStorageKind);
}
@Test
void synchronousMachineKindExportAndImportTest() throws IOException {
Network network = createOneGeneratorNetwork();
// Define the synchronous machine kind property
Generator expectedGenerator = network.getGenerator("generator1");
expectedGenerator.setMinP(-50.0).setMaxP(0.0).setTargetP(-10.0);
String expectedSynchronousMachineKind = "motorOrCondenser";
expectedGenerator.setProperty(Conversion.PROPERTY_CGMES_SYNCHRONOUS_MACHINE_TYPE, expectedSynchronousMachineKind);
String expectedOperatingMode = "motor";
expectedGenerator.setProperty(Conversion.PROPERTY_CGMES_SYNCHRONOUS_MACHINE_OPERATING_MODE, expectedOperatingMode);
// Export as cgmes
Path outputPath = tmpDir.resolve("temp.cgmesExport");
Files.createDirectories(outputPath);
String baseName = "oneGeneratorSynchronousMachineKind";
new CgmesExport().export(network, new Properties(), new DirectoryDataSource(outputPath, baseName));
// re-import
Network actual = new CgmesImport().importData(new DirectoryDataSource(outputPath, baseName), NetworkFactory.findDefault(), new Properties());
Generator actualGenerator = actual.getGenerator("generator1");
// check the synchronous machine kind
String actualSynchronousMachineKind = actualGenerator.getProperty(Conversion.PROPERTY_CGMES_SYNCHRONOUS_MACHINE_TYPE);
assertEquals(expectedSynchronousMachineKind, actualSynchronousMachineKind);
String actualOperatingMode = actualGenerator.getProperty(Conversion.PROPERTY_CGMES_SYNCHRONOUS_MACHINE_OPERATING_MODE);
assertEquals(expectedOperatingMode, actualOperatingMode);
}
@Test
void phaseTapChangerTapChangerControlEQTest() throws IOException {
String exportFolder = "/test-pst-tcc";
String baseName = "testPstTcc";
Network network;
String eq;
try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) {
Path tmpDir = Files.createDirectory(fs.getPath(exportFolder));
Properties exportParams = new Properties();
exportParams.put(CgmesExport.PROFILES, "EQ");
// PST with FIXED_TAP
network = PhaseShifterTestCaseFactory.createWithTargetDeadband();
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithoutAttribute(eq, "_PS1_PTC_RC", "_PS1_PT_T_2", "activePower");
// PST local with ACTIVE_POWER_CONTROL
network = PhaseShifterTestCaseFactory.createLocalActivePowerWithTargetDeadband();
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_PS1_PT_T_2", "activePower");
network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().setRegulating(true);
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_PS1_PT_T_2", "activePower");
// PST local with CURRENT_LIMITER
network = PhaseShifterTestCaseFactory.createLocalCurrentLimiterWithTargetDeadband();
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_PS1_PT_T_2", "currentFlow");
network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().setRegulating(true);
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_PS1_PT_T_2", "currentFlow");
// PST remote with CURRENT_LIMITER
network = PhaseShifterTestCaseFactory.createRemoteCurrentLimiterWithTargetDeadband();
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_LD2_EC_T_1", "currentFlow");
network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().setRegulating(true);
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_LD2_EC_T_1", "currentFlow");
// PST remote with ACTIVE_POWER_CONTROL
network = PhaseShifterTestCaseFactory.createRemoteActivePowerWithTargetDeadband();
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_LD2_EC_T_1", "activePower");
network.getTwoWindingsTransformer("PS1").getPhaseTapChanger().setRegulating(true);
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_PS1_PTC_RC", "_LD2_EC_T_1", "activePower");
}
}
@Test
void ratioTapChangerTapChangerControlEQTest() throws IOException {
String exportFolder = "/test-rtc-tcc";
String baseName = "testRtcTcc";
Network network;
String eq;
try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) {
Path tmpDir = Files.createDirectory(fs.getPath(exportFolder));
Properties exportParams = new Properties();
exportParams.put(CgmesExport.PROFILES, "EQ");
// RTC without control
network = EurostagTutorialExample1Factory.createWithoutRtcControl();
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithoutAttribute(eq, "_NHV2_NLOAD_RTC_RC", "", "dummy");
// RTC local with VOLTAGE
network = EurostagTutorialExample1Factory.create();
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_NHV2_NLOAD_RTC_RC", "_NHV2_NLOAD_PT_T_2", "voltage");
network.getTwoWindingsTransformer("NHV2_NLOAD").getRatioTapChanger().setRegulating(false);
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_NHV2_NLOAD_RTC_RC", "_NHV2_NLOAD_PT_T_2", "voltage");
// RTC local with REACTIVE_POWER
network = EurostagTutorialExample1Factory.createWithReactiveTcc();
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_NHV2_NLOAD_RTC_RC", "_NHV2_NLOAD_PT_T_2", "reactivePower");
network.getTwoWindingsTransformer("NHV2_NLOAD").getRatioTapChanger().setRegulating(false);
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_NHV2_NLOAD_RTC_RC", "_NHV2_NLOAD_PT_T_2", "reactivePower");
// RTC remote with VOLTAGE
network = EurostagTutorialExample1Factory.createRemoteVoltageTcc();
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_NHV2_NLOAD_RTC_RC", "_GEN_SM_T_1", "voltage");
network.getTwoWindingsTransformer("NHV2_NLOAD").getRatioTapChanger().setRegulating(false);
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_NHV2_NLOAD_RTC_RC", "_GEN_SM_T_1", "voltage");
// RTC remote with REACTIVE_POWER
network = EurostagTutorialExample1Factory.createRemoteReactiveTcc();
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_NHV2_NLOAD_RTC_RC", "_GEN_SM_T_1", "reactivePower");
network.getTwoWindingsTransformer("NHV2_NLOAD").getRatioTapChanger().setRegulating(false);
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_NHV2_NLOAD_RTC_RC", "_GEN_SM_T_1", "reactivePower");
// 3w without control
network = EurostagTutorialExample1Factory.createWith3wWithoutControl();
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithoutAttribute(eq, "_NGEN_V2_NHV1_RTC_RC", "", "dummy");
// 3w with local voltage control
network = EurostagTutorialExample1Factory.createWith3wWithVoltageControl();
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_NGEN_V2_NHV1_RTC_RC", "_NGEN_V2_NHV1_PT_T_1", "voltage");
// 3w with local reactive control
network = EurostagTutorialExample1Factory.create3wWithReactiveTcc();
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_NGEN_V2_NHV1_RTC_RC", "_NGEN_V2_NHV1_PT_T_1", "reactivePower");
network.getThreeWindingsTransformer("NGEN_V2_NHV1").getLeg1().getRatioTapChanger().setRegulating(false);
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_NGEN_V2_NHV1_RTC_RC", "_NGEN_V2_NHV1_PT_T_1", "reactivePower");
// 3w with remote voltage
network = EurostagTutorialExample1Factory.create3wRemoteVoltageTcc();
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_NGEN_V2_NHV1_RTC_RC", "_GEN_SM_T_1", "voltage");
network.getThreeWindingsTransformer("NGEN_V2_NHV1").getLeg1().getRatioTapChanger().setRegulating(false);
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_NGEN_V2_NHV1_RTC_RC", "_GEN_SM_T_1", "voltage");
// 3w with remote reactive
network = EurostagTutorialExample1Factory.create3wRemoteReactiveTcc();
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_NGEN_V2_NHV1_RTC_RC", "_GEN_SM_T_1", "reactivePower");
network.getThreeWindingsTransformer("NGEN_V2_NHV1").getLeg1().getRatioTapChanger().setRegulating(false);
eq = getEQ(network, baseName, tmpDir, exportParams);
testTcTccWithAttribute(eq, "_NGEN_V2_NHV1_RTC_RC", "_GEN_SM_T_1", "reactivePower");
}
}
@Test
void staticVarCompensatorRegulatingControlEQTest() throws IOException {
String exportFolder = "/test-svc-rc";
String baseName = "testSvcRc";
Network network;
String eq;
try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) {
Path tmpDir = Files.createDirectory(fs.getPath(exportFolder));
Properties exportParams = new Properties();
exportParams.put(CgmesExport.PROFILES, "EQ");
// SVC VOLTAGE
// Local
network = SvcTestCaseFactory.createLocalVoltageControl();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SVC2_RC", "_SVC2_SVC_T_1", "voltage");
// Remote
network = SvcTestCaseFactory.createRemoteVoltageControl();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SVC2_RC", "_L2_EC_T_1", "voltage");
// SVC REACTIVE_POWER
// Local
network = SvcTestCaseFactory.createLocalReactiveControl();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SVC2_RC", "_SVC2_SVC_T_1", "reactivePower");
// Remote
network = SvcTestCaseFactory.createRemoteReactiveControl();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SVC2_RC", "_L2_EC_T_1", "reactivePower");
// SVC OFF
// Local
network = SvcTestCaseFactory.createLocalOffNoTarget();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRCWithoutAttribute(eq, "_SVC2_RC", "_SVC2_SVC_T_1", "dummy");
network = SvcTestCaseFactory.createLocalOffReactiveTarget();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SVC2_RC", "_SVC2_SVC_T_1", "reactivePower");
network = SvcTestCaseFactory.createLocalOffVoltageTarget();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SVC2_RC", "_SVC2_SVC_T_1", "voltage");
network = SvcTestCaseFactory.createLocalOffBothTarget();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SVC2_RC", "_SVC2_SVC_T_1", "voltage");
// Remote
network = SvcTestCaseFactory.createRemoteOffNoTarget();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SVC2_RC", "_L2_EC_T_1", "voltage");
network = SvcTestCaseFactory.createRemoteOffReactiveTarget();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SVC2_RC", "_L2_EC_T_1", "reactivePower");
network = SvcTestCaseFactory.createRemoteOffVoltageTarget();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SVC2_RC", "_L2_EC_T_1", "voltage");
network = SvcTestCaseFactory.createRemoteOffBothTarget();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SVC2_RC", "_L2_EC_T_1", "voltage");
}
}
@Test
void shuntCompensatorRegulatingControlEQTest() throws IOException {
String exportFolder = "/test-sc-rc";
String baseName = "testScRc";
Network network;
String eq;
try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) {
Path tmpDir = Files.createDirectory(fs.getPath(exportFolder));
Properties exportParams = new Properties();
exportParams.put(CgmesExport.PROFILES, "EQ");
// SC linear
network = ShuntTestCaseFactory.create();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_LOAD_EC_T_1", "voltage");
testRcEqRCWithoutAttribute(eq, "", "", "reactivePower");
network = ShuntTestCaseFactory.createLocalLinear();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_SHUNT_SC_T_1", "voltage");
testRcEqRCWithoutAttribute(eq, "", "", "reactivePower");
network = ShuntTestCaseFactory.createDisabledRemoteLinear();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_LOAD_EC_T_1", "voltage");
testRcEqRCWithoutAttribute(eq, "", "", "reactivePower");
network = ShuntTestCaseFactory.createDisabledLocalLinear();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_SHUNT_SC_T_1", "voltage");
testRcEqRCWithoutAttribute(eq, "", "", "reactivePower");
network = ShuntTestCaseFactory.createLocalLinearNoTarget();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRCWithoutAttribute(eq, "_SHUNT_RC", "", "");
network = ShuntTestCaseFactory.createRemoteLinearNoTarget();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_LOAD_EC_T_1", "voltage");
testRcEqRCWithoutAttribute(eq, "", "", "reactivePower");
// SC nonlinear
network = ShuntTestCaseFactory.createNonLinear();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_LOAD_EC_T_1", "voltage");
testRcEqRCWithoutAttribute(eq, "", "", "reactivePower");
network = ShuntTestCaseFactory.createLocalNonLinear();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_SHUNT_SC_T_1", "voltage");
testRcEqRCWithoutAttribute(eq, "", "", "reactivePower");
network = ShuntTestCaseFactory.createDisabledRemoteNonLinear();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_LOAD_EC_T_1", "voltage");
testRcEqRCWithoutAttribute(eq, "", "", "reactivePower");
network = ShuntTestCaseFactory.createDisabledLocalNonLinear();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_SHUNT_SC_T_1", "voltage");
network = ShuntTestCaseFactory.createLocalNonLinearNoTarget();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRCWithoutAttribute(eq, "_SHUNT_RC", "", "");
network = ShuntTestCaseFactory.createRemoteNonLinearNoTarget();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_SHUNT_RC", "_LOAD_EC_T_1", "voltage");
testRcEqRCWithoutAttribute(eq, "", "", "reactivePower");
}
}
@Test
void generatorRegulatingControlEQTest() throws IOException {
String exportFolder = "/test-gen-rc";
String baseName = "testGenRc";
Network network;
String eq;
try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) {
Path tmpDir = Files.createDirectory(fs.getPath(exportFolder));
Properties exportParams = new Properties();
exportParams.put(CgmesExport.PROFILES, "EQ");
// Generator local voltage
network = EurostagTutorialExample1Factory.create();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_GEN_RC", "_GEN_SM_T_1", "voltage");
network.getGenerator("GEN").setVoltageRegulatorOn(false);
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_GEN_RC", "_GEN_SM_T_1", "voltage");
// Generator remote voltage
network = EurostagTutorialExample1Factory.createWithRemoteVoltageGenerator();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_GEN_RC", "_NHV2_NLOAD_PT_T_1", "voltage");
network.getGenerator("GEN").setVoltageRegulatorOn(false);
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_GEN_RC", "_NHV2_NLOAD_PT_T_1", "voltage");
// Generator with remote voltage regulation exported in local regulation mode
Properties exportInLocalRegulationModeParams = new Properties();
exportInLocalRegulationModeParams.put(CgmesExport.PROFILES, "EQ");
exportInLocalRegulationModeParams.put(CgmesExport.EXPORT_GENERATORS_IN_LOCAL_REGULATION_MODE, true);
network = EurostagTutorialExample1Factory.createWithRemoteVoltageGenerator();
eq = getEQ(network, baseName, tmpDir, exportInLocalRegulationModeParams);
testRcEqRcWithAttribute(eq, "_GEN_RC", "_GEN_SM_T_1", "voltage");
// Generator with local reactive
network = EurostagTutorialExample1Factory.createWithLocalReactiveGenerator();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_GEN_RC", "_GEN_SM_T_1", "reactivePower");
network.getGenerator("GEN").getExtension(RemoteReactivePowerControl.class).setEnabled(false);
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_GEN_RC", "_GEN_SM_T_1", "reactivePower");
// Generator with remote reactive
network = EurostagTutorialExample1Factory.createWithRemoteReactiveGenerator();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_GEN_RC", "_NHV2_NLOAD_PT_T_1", "reactivePower");
network.getGenerator("GEN").getExtension(RemoteReactivePowerControl.class).setEnabled(false);
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_GEN_RC", "_NHV2_NLOAD_PT_T_1", "reactivePower");
// Generator with local reactive and voltage
network = EurostagTutorialExample1Factory.createWithLocalReactiveAndVoltageGenerator();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_GEN_RC", "_GEN_SM_T_1", "voltage");
network.getGenerator("GEN").setVoltageRegulatorOn(false);
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_GEN_RC", "_GEN_SM_T_1", "reactivePower");
network.getGenerator("GEN").getExtension(RemoteReactivePowerControl.class).setEnabled(false);
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_GEN_RC", "_GEN_SM_T_1", "voltage");
network.getGenerator("GEN").setVoltageRegulatorOn(true);
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_GEN_RC", "_GEN_SM_T_1", "voltage");
// Generator with remote reactive and voltage
network = EurostagTutorialExample1Factory.createWithRemoteReactiveAndVoltageGenerators();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_GEN_RC", "_NHV2_NLOAD_PT_T_1", "voltage");
network.getGenerator("GEN").setVoltageRegulatorOn(false);
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_GEN_RC", "_NHV2_NLOAD_PT_T_1", "reactivePower");
network.getGenerator("GEN").getExtension(RemoteReactivePowerControl.class).setEnabled(false);
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_GEN_RC", "_NHV2_NLOAD_PT_T_1", "voltage");
network.getGenerator("GEN").setVoltageRegulatorOn(true);
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRcWithAttribute(eq, "_GEN_RC", "_NHV2_NLOAD_PT_T_1", "voltage");
// Generator without control
network = EurostagTutorialExample1Factory.createWithoutControl();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRCWithoutAttribute(eq, "_GEN_RC", "", "dummy");
// Generator with remote terminal without control
network = EurostagTutorialExample1Factory.createRemoteWithoutControl();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRCWithoutAttribute(eq, "_GEN_RC", "", "dummy");
// Generator without control capability
network = EurostagTutorialExample1Factory.create();
network.getGenerator("GEN").newMinMaxReactiveLimits().setMaxQ(0).setMinQ(0).add();
eq = getEQ(network, baseName, tmpDir, exportParams);
testRcEqRCWithoutAttribute(eq, "_GEN_RC", "", "dummy");
}
}
private void testTcTccWithoutAttribute(String eq, String rcID, String terID, String rcMode) {
assertFalse(eq.contains("cim:TapChangerControl rdf:ID=\"" + rcID + "\""));
assertFalse(eq.contains("cim:TapChanger.TapChangerControl rdf:resource=\"#" + rcID + "\""));
assertFalse(eq.contains("RegulatingControlModeKind." + rcMode));
assertFalse(eq.contains("cim:RegulatingControl.Terminal rdf:resource=\"#" + terID + "\""));
}
private void testTcTccWithAttribute(String eq, String rcID, String terID, String rcMode) {
assertTrue(eq.contains("cim:TapChangerControl rdf:ID=\"" + rcID + "\""));
assertTrue(eq.contains("cim:TapChanger.TapChangerControl rdf:resource=\"#" + rcID + "\""));
assertTrue(eq.contains("RegulatingControlModeKind." + rcMode));
assertTrue(eq.contains("cim:RegulatingControl.Terminal rdf:resource=\"#" + terID + "\""));
}
private void testRcEqRCWithoutAttribute(String eq, String rcID, String terID, String rcMode) {
assertFalse(eq.contains("cim:RegulatingControl rdf:ID=\"" + rcID + "\""));
assertFalse(eq.contains("cim:RegulatingCondEq.RegulatingControl rdf:resource=\"#" + rcID + "\""));
// dummy kind is used when false assertion would trigger because other RCs are present from other equipment
assertFalse(eq.contains("RegulatingControlModeKind." + rcMode));
assertFalse(eq.contains("cim:RegulatingControl.Terminal rdf:resource=\"#" + terID + "\""));
}
private void testRcEqRcWithAttribute(String eq, String rcID, String terID, String rcMode) {
assertTrue(eq.contains("cim:RegulatingControl rdf:ID=\"" + rcID + "\""));
assertTrue(eq.contains("cim:RegulatingCondEq.RegulatingControl rdf:resource=\"#" + rcID + "\""));
assertTrue(eq.contains("RegulatingControlModeKind." + rcMode));
assertTrue(eq.contains("cim:RegulatingControl.Terminal rdf:resource=\"#" + terID + "\""));
}
private String getEQ(Network network, String baseName, Path tmpDir, Properties exportParams) throws IOException {
new CgmesExport().export(network, exportParams, new DirectoryDataSource(tmpDir, baseName));
return Files.readString(tmpDir.resolve(baseName + "_EQ.xml"));
}
private Network createOneGeneratorNetwork() {
Network network = NetworkFactory.findDefault().createNetwork("network", "test");
Substation substation1 = network.newSubstation()
.setId("substation1")
.setCountry(Country.FR)
.setTso("TSO1")
.setGeographicalTags("region1")
.add();
VoltageLevel voltageLevel1 = substation1.newVoltageLevel()
.setId("voltageLevel1")
.setNominalV(400)
.setTopologyKind(TopologyKind.NODE_BREAKER)
.add();
voltageLevel1.getNodeBreakerView()
.newBusbarSection()
.setId("busbarSection1")
.setNode(0)
.add();
Generator generator1 = voltageLevel1.newGenerator()
.setId("generator1")
.setNode(1)
.setMinP(0.0)
.setMaxP(100.0)
.setTargetP(25.0)
.setTargetQ(10.0)
.setVoltageRegulatorOn(false)
.add();
generator1.newMinMaxReactiveLimits().setMinQ(-50.0).setMaxQ(50.0).add();
voltageLevel1.getNodeBreakerView().newInternalConnection().setNode1(0).setNode2(1).add();
return network;
}
private Network exportImportNodeBreaker(Network expected, ReadOnlyDataSource dataSource) throws IOException, XMLStreamException {
return exportImport(expected, dataSource, false, true, false);
}
private Network exportImportBusBranch(Network expected, ReadOnlyDataSource dataSource) throws IOException, XMLStreamException {
return exportImport(expected, dataSource, true, true, false);
}
private Network exportImportBusBranchNoBoundaries(Network expected, ReadOnlyDataSource dataSource) throws IOException, XMLStreamException {
return exportImport(expected, dataSource, true, false, false);
}
private Network exportImportNodeBreakerNoBoundaries(Network expected) throws IOException, XMLStreamException {
return exportImport(expected, null, false, false, true);
}
private Network createThreeWindingTransformerNetwork() {
Network network = NetworkFactory.findDefault().createNetwork("network", "test");
Substation substation1 = network.newSubstation()
.setId("substation1")
.setCountry(Country.FR)
.setTso("TSO1")
.setGeographicalTags("region1")
.add();
VoltageLevel voltageLevel1 = substation1.newVoltageLevel()
.setId("voltageLevel1")
.setNominalV(400)
.setTopologyKind(TopologyKind.NODE_BREAKER)
.add();
VoltageLevel voltageLevel2 = substation1.newVoltageLevel()
.setId("voltageLevel2")
.setNominalV(220)
.setTopologyKind(TopologyKind.NODE_BREAKER)
.add();
VoltageLevel voltageLevel3 = substation1.newVoltageLevel()
.setId("voltageLevel3")
.setNominalV(60)
.setTopologyKind(TopologyKind.NODE_BREAKER)
.add();
VoltageLevel.NodeBreakerView topology1 = voltageLevel1.getNodeBreakerView();
BusbarSection voltageLevel1BusbarSection1 = topology1.newBusbarSection()
.setId("voltageLevel1BusbarSection1")
.setNode(0)
.add();
VoltageLevel.NodeBreakerView topology2 = voltageLevel2.getNodeBreakerView();
BusbarSection voltageLevel1BusbarSection2 = topology2.newBusbarSection()
.setId("voltageLevel1BusbarSection2")
.setNode(0)
.add();
VoltageLevel.NodeBreakerView topology3 = voltageLevel3.getNodeBreakerView();
BusbarSection voltageLevel1BusbarSection3 = topology3.newBusbarSection()
.setId("voltageLevel1BusbarSection3")
.setNode(0)
.add();
ThreeWindingsTransformerAdder threeWindingsTransformerAdder1 = substation1.newThreeWindingsTransformer()
.setId("threeWindingsTransformer1")
.setRatedU0(400);
threeWindingsTransformerAdder1.newLeg1()
.setNode(1)
.setR(0.001)
.setX(0.000001)
.setB(0)
.setG(0)
.setRatedU(400)
.setVoltageLevel("voltageLevel1")
.add();
threeWindingsTransformerAdder1.newLeg2()
.setNode(1)
.setR(0.1)
.setX(0.00001)
.setB(0)
.setG(0)
.setRatedU(220)
.setVoltageLevel("voltageLevel2")
.add();
threeWindingsTransformerAdder1.newLeg3()
.setNode(1)
.setR(0.01)
.setX(0.0001)
.setB(0)
.setG(0)
.setRatedU(60)
.setVoltageLevel("voltageLevel3")
.add();
ThreeWindingsTransformer threeWindingsTransformer1 = threeWindingsTransformerAdder1.add();
threeWindingsTransformer1.getLeg1().newRatioTapChanger()
.setLowTapPosition(0)
.setTapPosition(0)
.beginStep()
.setR(0.01)
.setX(0.0001)
.setB(0)
.setG(0)
.setRho(1.1)
.endStep()
.add();
threeWindingsTransformer1.getLeg2().newRatioTapChanger()
.setLowTapPosition(0)
.setTapPosition(0)
.beginStep()
.setR(0.02)
.setX(0.0002)
.setB(0)
.setG(0)
.setRho(1.2)
.endStep()
.add();
threeWindingsTransformer1.getLeg3().newRatioTapChanger()
.setLowTapPosition(0)
.setTapPosition(0)
.beginStep()
.setR(0.03)
.setX(0.0003)
.setB(0)
.setG(0)
.setRho(1.3)
.endStep()
.add();
threeWindingsTransformer1.getLeg1().newPhaseTapChanger()
.setLowTapPosition(0)
.setTapPosition(0)
.beginStep()
.setR(0.01)
.setX(0.0001)
.setB(0)
.setG(0)
.setRho(1.1)
.setAlpha(10)
.endStep()
.add();
threeWindingsTransformer1.getLeg2().newPhaseTapChanger()
.setLowTapPosition(0)
.setTapPosition(0)
.beginStep()
.setR(0.02)
.setX(0.0002)
.setB(0)
.setG(0)
.setRho(1.2)
.setAlpha(20)
.endStep()
.add();
threeWindingsTransformer1.getLeg3().newPhaseTapChanger()
.setLowTapPosition(0)
.setTapPosition(0)
.beginStep()
.setR(0.03)
.setX(0.0003)
.setB(0)
.setG(0)
.setRho(1.3)
.setAlpha(30)
.endStep()
.add();
topology1.newDisconnector()
.setId("Disconnector1")
.setOpen(false)
.setNode1(threeWindingsTransformer1.getLeg1().getTerminal().getNodeBreakerView().getNode())
.setNode2(voltageLevel1BusbarSection1.getTerminal().getNodeBreakerView().getNode())
.add();
topology2.newDisconnector()
.setId("Disconnector2")
.setOpen(false)
.setNode1(threeWindingsTransformer1.getLeg2().getTerminal().getNodeBreakerView().getNode())
.setNode2(voltageLevel1BusbarSection2.getTerminal().getNodeBreakerView().getNode())
.add();
topology3.newDisconnector()
.setId("Disconnector3")
.setOpen(false)
.setNode1(threeWindingsTransformer1.getLeg3().getTerminal().getNodeBreakerView().getNode())
.setNode2(voltageLevel1BusbarSection3.getTerminal().getNodeBreakerView().getNode())
.add();
return network;
}
private Network exportImport(Network expected, ReadOnlyDataSource dataSource, boolean importTP, boolean importBD, boolean transformersWithHighestVoltageAtEnd1) throws IOException, XMLStreamException {
Path exportedEq = exportToCgmesEQ(expected, transformersWithHighestVoltageAtEnd1);
// From reference data source we use only boundaries
Path repackaged = tmpDir.resolve("repackaged.zip");
Repackager r = new Repackager(dataSource)
.with("test_EQ.xml", exportedEq);
if (importTP) {
r.with("test_TP.xml", Repackager::tp);
}
if (importBD) {
r.with("test_EQ_BD.xml", Repackager::eqBd)
.with("test_TP_BD.xml", Repackager::tpBd);
}
r.zip(repackaged);
// Import with new EQ
// There is no need to create the IIDM-CGMES mappings
// We are reading only an EQ, we won't have TP data in the input
// And to compare the expected and actual networks we are dropping all IIDM-CGMES mapping context information
return Network.read(repackaged, LocalComputationManager.getDefault(), ImportConfig.load(), importParams);
}
private Path exportToCgmesEQ(Network network) throws IOException, XMLStreamException {
return exportToCgmesEQ(network, false);
}
private Path exportToCgmesEQ(Network network, boolean transformersWithHighestVoltageAtEnd1) throws IOException, XMLStreamException {
// Export CGMES EQ file
Path exportedEq = tmpDir.resolve("exportedEq.xml");
try (OutputStream os = new BufferedOutputStream(Files.newOutputStream(exportedEq))) {
XMLStreamWriter writer = XmlUtil.initializeWriter(true, " ", os);
CgmesExportContext context = new CgmesExportContext(network)
.setExportEquipment(true)
.setExportTransformersWithHighestVoltageAtEnd1(transformersWithHighestVoltageAtEnd1);
EquipmentExport.write(network, writer, context);
}
return exportedEq;
}
private Path exportToCgmesTP(Network network) throws IOException, XMLStreamException {
// Export CGMES EQ file
Path exportedTp = tmpDir.resolve("exportedTp.xml");
try (OutputStream os = new BufferedOutputStream(Files.newOutputStream(exportedTp))) {
XMLStreamWriter writer = XmlUtil.initializeWriter(true, " ", os);
CgmesExportContext context = new CgmesExportContext(network);
TopologyExport.write(network, writer, context);
}
return exportedTp;
}
private boolean compareNetworksEQdata(Network expected, Network actual) {
DifferenceEvaluator knownDiffs = DifferenceEvaluators.chain(
DifferenceEvaluators.Default,
ExportXmlCompare::numericDifferenceEvaluator,
ExportXmlCompare::ignoringNonEQ);
return compareNetworksEQdata(expected, actual, knownDiffs);
}
private boolean compareNetworksEQdata(Network expected, Network actual, DifferenceEvaluator knownDiffs) {
Network expectedNetwork = prepareNetworkForEQComparison(expected);
Network actualNetwork = prepareNetworkForEQComparison(actual);
// Export original and only EQ
ExportOptions exportOptions = new ExportOptions();
// Do not export extensions
exportOptions.setExtensions(Collections.emptySet());
exportOptions.setSorted(true);
Path expectedPath = tmpDir.resolve("expected.xml");
Path actualPath = tmpDir.resolve("actual.xml");
NetworkSerDe.write(expectedNetwork, exportOptions, expectedPath);
NetworkSerDe.write(actualNetwork, exportOptions, actualPath);
NetworkSerDe.validate(actualPath);
// Compare
compareTemporaryLimits(Network.read(expectedPath), Network.read(actualPath));
return ExportXmlCompare.compareEQNetworks(expectedPath, actualPath, knownDiffs);
}
private void compareTemporaryLimits(Network expected, Network actual) {
for (Line line : actual.getLines()) {
Identifiable identifiable = expected.getIdentifiable(line.getId());
if (identifiable instanceof Branch) {
compareBranchLimits((Branch) identifiable, line);
} else {
compareFlowBranchLimits((FlowsLimitsHolder) identifiable, line);
}
}
for (TwoWindingsTransformer twt : actual.getTwoWindingsTransformers()) {
compareBranchLimits((Branch) expected.getIdentifiable(twt.getId()), twt);
}
for (ThreeWindingsTransformer twt : actual.getThreeWindingsTransformers()) {
ThreeWindingsTransformer expectedTwt = (ThreeWindingsTransformer) expected.getIdentifiable(twt.getId());
compareFlowLimits(expectedTwt.getLeg1(), twt.getLeg1());
compareFlowLimits(expectedTwt.getLeg2(), twt.getLeg2());
compareFlowLimits(expectedTwt.getLeg3(), twt.getLeg3());
}
for (DanglingLine danglingLine : actual.getDanglingLines(DanglingLineFilter.ALL)) {
compareFlowLimits((FlowsLimitsHolder) expected.getIdentifiable(danglingLine.getId()), danglingLine);
}
}
private void compareBranchLimits(Branch<?> expected, Branch<?> actual) {
actual.getActivePowerLimits1().ifPresent(lim -> compareLoadingLimits(expected.getActivePowerLimits1().orElse(null), lim));
actual.getActivePowerLimits2().ifPresent(lim -> compareLoadingLimits(expected.getActivePowerLimits2().orElse(null), lim));
actual.getApparentPowerLimits1().ifPresent(lim -> compareLoadingLimits(expected.getApparentPowerLimits1().orElse(null), lim));
actual.getApparentPowerLimits2().ifPresent(lim -> compareLoadingLimits(expected.getApparentPowerLimits2().orElse(null), lim));
actual.getCurrentLimits1().ifPresent(lim -> compareLoadingLimits(expected.getCurrentLimits1().orElse(null), lim));
actual.getCurrentLimits2().ifPresent(lim -> compareLoadingLimits(expected.getCurrentLimits2().orElse(null), lim));
}
private void compareFlowBranchLimits(FlowsLimitsHolder expected, Line actual) {
actual.getActivePowerLimits1().ifPresent(lim -> compareLoadingLimits(expected.getActivePowerLimits().orElse(null), lim));
actual.getActivePowerLimits2().ifPresent(lim -> compareLoadingLimits(expected.getActivePowerLimits().orElse(null), lim));
actual.getApparentPowerLimits1().ifPresent(lim -> compareLoadingLimits(expected.getApparentPowerLimits().orElse(null), lim));
actual.getApparentPowerLimits2().ifPresent(lim -> compareLoadingLimits(expected.getApparentPowerLimits().orElse(null), lim));
actual.getCurrentLimits1().ifPresent(lim -> compareLoadingLimits(expected.getCurrentLimits().orElse(null), lim));
actual.getCurrentLimits2().ifPresent(lim -> compareLoadingLimits(expected.getCurrentLimits().orElse(null), lim));
}
private void compareFlowLimits(FlowsLimitsHolder expected, FlowsLimitsHolder actual) {
actual.getActivePowerLimits().ifPresent(lim -> compareLoadingLimits(expected.getActivePowerLimits().orElse(null), lim));
actual.getApparentPowerLimits().ifPresent(lim -> compareLoadingLimits(expected.getApparentPowerLimits().orElse(null), lim));
actual.getCurrentLimits().ifPresent(lim -> compareLoadingLimits(expected.getCurrentLimits().orElse(null), lim));
}
private void compareLoadingLimits(LoadingLimits expected, LoadingLimits actual) {
if (!actual.getTemporaryLimits().isEmpty()) {
assertFalse(expected.getTemporaryLimits().isEmpty());
for (LoadingLimits.TemporaryLimit temporaryLimit : actual.getTemporaryLimits()) {
int acceptableDuration = temporaryLimit.getAcceptableDuration();
assertEquals(expected.getTemporaryLimit(acceptableDuration).getValue(), temporaryLimit.getValue(), 0.0);
}
} else {
assertTrue(expected.getTemporaryLimits().isEmpty());
}
}
private Network prepareNetworkForEQComparison(Network network) {
network.getAliases().forEach(network::removeAlias);
network.getIdentifiables().forEach(identifiable -> identifiable.getAliases().forEach(identifiable::removeAlias));
network.getVoltageLevels().forEach(vl ->
vl.getBusView().getBuses().forEach(bus -> {
bus.setV(Double.NaN);
bus.setAngle(Double.NaN);
})
);
network.getIdentifiables().forEach(identifiable -> {
if (identifiable instanceof Bus) {
// Nothing to do
} else if (identifiable instanceof BusbarSection) {
// Nothing to do
} else if (identifiable instanceof ShuntCompensator) {
ShuntCompensator shuntCompensator = (ShuntCompensator) identifiable;
shuntCompensator.setVoltageRegulatorOn(false);
shuntCompensator.setTargetV(Double.NaN);
shuntCompensator.setTargetDeadband(Double.NaN);
shuntCompensator.getTerminal().setQ(0.0);
shuntCompensator.getTerminal().setP(0.0);
} else if (identifiable instanceof Generator) {
Generator generator = (Generator) identifiable;
generator.setVoltageRegulatorOn(false);
generator.setTargetV(Double.NaN);
generator.getTerminal().setP(0.0).setQ(0.0);
} else if (identifiable instanceof StaticVarCompensator) {
StaticVarCompensator staticVarCompensator = (StaticVarCompensator) identifiable;
staticVarCompensator.setRegulationMode(StaticVarCompensator.RegulationMode.OFF).setVoltageSetpoint(0.0);
staticVarCompensator.getTerminal().setP(0.0).setQ(0.0);
} else if (identifiable instanceof VscConverterStation) {
VscConverterStation converter = (VscConverterStation) identifiable;
converter.setVoltageRegulatorOn(false);
converter.setLossFactor(0.8f);
converter.setVoltageSetpoint(Double.NaN);
converter.getTerminal().setP(0.0).setQ(0.0);
} else if (identifiable instanceof LccConverterStation) {
LccConverterStation converter = (LccConverterStation) identifiable;
converter.setPowerFactor(0.8f);
converter.getTerminal().setP(0.0).setQ(0.0);
} else if (identifiable instanceof Injection) {
Injection injection = (Injection) identifiable;
injection.getTerminal().setP(0.0).setQ(0.0);
} else if (identifiable instanceof HvdcLine) {
HvdcLine hvdcLine = (HvdcLine) identifiable;
hvdcLine.setActivePowerSetpoint(0.0);
hvdcLine.setMaxP(0.0);
hvdcLine.getConverterStation1().getTerminal().setP(0.0).setQ(0.0);
hvdcLine.getConverterStation2().getTerminal().setP(0.0).setQ(0.0);
} else if (identifiable instanceof Branch) {
Branch branch = (Branch) identifiable;
branch.getTerminal1().setP(0.0).setQ(0.0);
branch.getTerminal2().setP(0.0).setQ(0.0);
} else if (identifiable instanceof ThreeWindingsTransformer) {
ThreeWindingsTransformer threeWindingsTransformer = (ThreeWindingsTransformer) identifiable;
threeWindingsTransformer.getLeg1().getTerminal().setP(0.0).setQ(0.0);
threeWindingsTransformer.getLeg2().getTerminal().setP(0.0).setQ(0.0);
threeWindingsTransformer.getLeg3().getTerminal().setP(0.0).setQ(0.0);
}
});
for (Load load : network.getLoads()) {
load.setP0(0.0).setQ0(0.0);
}
for (Area area : network.getAreas()) {
area.setInterchangeTarget(0.0);
}
network.removeExtension(CgmesModelExtension.class);
network.removeExtension(CgmesMetadataModels.class);
network.removeExtension(CimCharacteristics.class);
return network;
}
private static Network allGeneratingUnitTypesNetwork() {
Network network = NetworkFactory.findDefault().createNetwork("network", "test");
Substation substation1 = network.newSubstation()
.setId("substation1")
.setCountry(Country.FR)
.setTso("TSO1")
.setGeographicalTags("region1")
.add();
VoltageLevel voltageLevel1 = substation1.newVoltageLevel()
.setId("voltageLevel1")
.setNominalV(400)
.setTopologyKind(TopologyKind.NODE_BREAKER)
.add();
VoltageLevel.NodeBreakerView topology1 = voltageLevel1.getNodeBreakerView();
topology1.newBusbarSection()
.setId("voltageLevel1BusbarSection1")
.setNode(0)
.add();
voltageLevel1.newGenerator()
.setId("other")
.setNode(1)
.setMinP(0.0)
.setMaxP(100.0)
.setTargetP(25.0)
.setTargetQ(10.0)
.setVoltageRegulatorOn(false)
.add();
voltageLevel1.newGenerator()
.setId("nuclear")
.setNode(2)
.setMinP(0.0)
.setMaxP(100.0)
.setTargetP(25.0)
.setTargetQ(10.0)
.setVoltageRegulatorOn(false)
.setEnergySource(EnergySource.NUCLEAR)
.add();
voltageLevel1.newGenerator()
.setId("thermal")
.setNode(3)
.setMinP(0.0)
.setMaxP(100.0)
.setTargetP(25.0)
.setTargetQ(10.0)
.setVoltageRegulatorOn(false)
.setEnergySource(EnergySource.THERMAL)
.add();
voltageLevel1.newGenerator()
.setId("hydro")
.setNode(4)
.setMinP(0.0)
.setMaxP(100.0)
.setTargetP(25.0)
.setTargetQ(10.0)
.setVoltageRegulatorOn(false)
.setEnergySource(EnergySource.HYDRO)
.add();
voltageLevel1.newGenerator()
.setId("solar")
.setNode(5)
.setMinP(0.0)
.setMaxP(100.0)
.setTargetP(25.0)
.setTargetQ(10.0)
.setVoltageRegulatorOn(false)
.setEnergySource(EnergySource.SOLAR)
.add();
Generator windOnshore = voltageLevel1.newGenerator()
.setId("wind_onshore")
.setNode(6)
.setMinP(0.0)
.setMaxP(100.0)
.setTargetP(25.0)
.setTargetQ(10.0)
.setVoltageRegulatorOn(false)
.setEnergySource(EnergySource.WIND)
.add();
Generator windOffshore = voltageLevel1.newGenerator()
.setId("wind_offshore")
.setNode(7)
.setMinP(0.0)
.setMaxP(100.0)
.setTargetP(25.0)
.setTargetQ(10.0)
.setVoltageRegulatorOn(false)
.setEnergySource(EnergySource.WIND)
.add();
topology1.newInternalConnection().setNode1(0).setNode2(1).add();
topology1.newInternalConnection().setNode1(0).setNode2(2).add();
topology1.newInternalConnection().setNode1(0).setNode2(3).add();
topology1.newInternalConnection().setNode1(0).setNode2(4).add();
topology1.newInternalConnection().setNode1(0).setNode2(5).add();
topology1.newInternalConnection().setNode1(0).setNode2(6).add();
topology1.newInternalConnection().setNode1(0).setNode2(7).add();
windOnshore.setProperty(Conversion.PROPERTY_WIND_GEN_UNIT_TYPE, "onshore");
windOffshore.setProperty(Conversion.PROPERTY_WIND_GEN_UNIT_TYPE, "offshore");
return network;
}
@Test
void generatingUnitTypesTest() throws IOException {
Network network = allGeneratingUnitTypesNetwork();
// Export as cgmes
String eqXml = writeCgmesProfile(network, "EQ", tmpDir);
assertTrue(eqXml.contains("<cim:GeneratingUnit rdf:ID=\"_other_GU\">"));
assertTrue(eqXml.contains("<cim:NuclearGeneratingUnit rdf:ID=\"_nuclear_NGU\">"));
assertTrue(eqXml.contains("<cim:ThermalGeneratingUnit rdf:ID=\"_thermal_TGU\">"));
assertTrue(eqXml.contains("<cim:HydroGeneratingUnit rdf:ID=\"_hydro_HGU\">"));
assertTrue(eqXml.contains("<cim:SolarGeneratingUnit rdf:ID=\"_solar_SGU\">"));
assertTrue(eqXml.contains("<cim:WindGeneratingUnit rdf:ID=\"_wind_onshore_WGU\">"));
assertTrue(eqXml.contains("<cim:WindGeneratingUnit rdf:ID=\"_wind_offshore_WGU\">"));
String sPattern = "<cim:WindGeneratingUnit rdf:ID=\"${rdfId}\">.*?" +
"<cim:WindGeneratingUnit.windGenUnitType rdf:resource=\"http://iec.ch/TC57/2013/CIM-schema-cim16#WindGenUnitKind.(.*?)\"/>";
Pattern onshorePattern = Pattern.compile(sPattern.replace("${rdfId}", "_wind_onshore_WGU"), Pattern.DOTALL);
assertEquals("onshore", getFirstMatch(eqXml, onshorePattern));
Pattern offshorePattern = Pattern.compile(sPattern.replace("${rdfId}", "_wind_offshore_WGU"), Pattern.DOTALL);
assertEquals("offshore", getFirstMatch(eqXml, offshorePattern));
}
}