diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesExport.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesExport.java index e5369dbd89a..34dc4b4f6c9 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesExport.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/CgmesExport.java @@ -13,10 +13,7 @@ import com.powsybl.cgmes.conversion.naming.NamingStrategy; import com.powsybl.cgmes.conversion.naming.NamingStrategyFactory; import com.powsybl.cgmes.extensions.CgmesMetadataModels; -import com.powsybl.cgmes.model.CgmesMetadataModel; -import com.powsybl.cgmes.model.CgmesMetadataModelImpl; -import com.powsybl.cgmes.model.CgmesNamespace; -import com.powsybl.cgmes.model.CgmesSubset; +import com.powsybl.cgmes.model.*; import com.powsybl.commons.config.PlatformConfig; import com.powsybl.commons.datasource.DataSource; import com.powsybl.commons.exceptions.UncheckedXmlStreamException; @@ -28,6 +25,7 @@ import com.powsybl.commons.xml.XmlUtil; import com.powsybl.iidm.network.*; import com.powsybl.triplestore.api.PropertyBag; +import com.powsybl.triplestore.api.PropertyBags; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,6 +40,8 @@ import java.util.stream.Collectors; import static com.powsybl.cgmes.conversion.CgmesReports.inconsistentProfilesTPRequiredReport; +import static com.powsybl.cgmes.conversion.naming.CgmesObjectReference.Part.CONTROL_AREA; +import static com.powsybl.cgmes.conversion.naming.CgmesObjectReference.refTyped; /** * @author Luma Zamarreño {@literal } @@ -78,6 +78,49 @@ public List getParameters() { public void export(Network network, Properties parameters, DataSource dataSource, ReportNode reportNode) { Objects.requireNonNull(network); + CgmesExportContext context = createContext(network, parameters, reportNode); + + // Export the network + if (Parameter.readBoolean(getFormat(), parameters, CGM_EXPORT_PARAMETER, defaultValueConfig)) { + exportCGM(network, dataSource, context); + } else { + exportIGM(network, dataSource, context); + } + } + + public void createDefaultControlAreaInterchange(Network network) { + createDefaultControlAreaInterchange(network, null); + } + + public void createDefaultControlAreaInterchange(Network network, Properties parameters) { + Objects.requireNonNull(network); + + CgmesExportContext context = createContext(network, parameters, ReportNode.NO_OP); + + String controlAreaId = context.getNamingStrategy().getCgmesId(refTyped(network), CONTROL_AREA); + Area area = network.newArea() + .setAreaType("ControlAreaTypeKind.Interchange") + .setId(controlAreaId) + .setName("Network") + .add(); + ReferenceDataProvider referenceDataProvider = context.getReferenceDataProvider(); + if (referenceDataProvider != null && referenceDataProvider.getSourcingActor().containsKey(CgmesNames.ENERGY_IDENT_CODE_EIC)) { + area.addAlias(referenceDataProvider.getSourcingActor().get(CgmesNames.ENERGY_IDENT_CODE_EIC), CgmesNames.ENERGY_IDENT_CODE_EIC); + } + double currentInterchange = 0; + Set boundaryDcNodes = getBoundaryDcNodes(referenceDataProvider); + for (DanglingLine danglingLine : CgmesExportUtil.getBoundaryDanglingLines(network)) { + // Our exchange should be referred the boundary + area.newAreaBoundary() + .setAc(isAcBoundary(danglingLine, boundaryDcNodes)) + .setBoundary(danglingLine.getBoundary()) + .add(); + currentInterchange += danglingLine.getBoundary().getP(); + } + area.setInterchangeTarget(currentInterchange); + } + + private CgmesExportContext createContext(Network network, Properties parameters, ReportNode reportNode) { // Determine reference data (boundaries, base voltages and other sourcing references) for the export String sourcingActorName = Parameter.readString(getFormat(), parameters, SOURCING_ACTOR_PARAMETER, defaultValueConfig); String countryName = getCountry(network); @@ -90,12 +133,30 @@ public void export(Network network, Properties parameters, DataSource dataSource CgmesExportContext context = new CgmesExportContext(network, referenceDataProvider, namingStrategy); addParametersToContext(context, parameters, reportNode, referenceDataProvider); - // Export the network - if (Parameter.readBoolean(getFormat(), parameters, CGM_EXPORT_PARAMETER, defaultValueConfig)) { - exportCGM(network, dataSource, context); + return context; + } + + private Set getBoundaryDcNodes(ReferenceDataProvider referenceDataProvider) { + if (referenceDataProvider == null) { + return Collections.emptySet(); + } + PropertyBags boundaryNodes = referenceDataProvider.getBoundaryNodes(); + if (boundaryNodes == null) { + return Collections.emptySet(); } else { - exportIGM(network, dataSource, context); + return boundaryNodes.stream() + .filter(node -> node.containsKey("topologicalNodeDescription") && node.get("topologicalNodeDescription").startsWith("HVDC")) + .map(node -> node.getId(CgmesNames.TOPOLOGICAL_NODE)) + .collect(Collectors.toSet()); + } + } + + private boolean isAcBoundary(DanglingLine danglingLine, Set boundaryDcNodes) { + String dlBoundaryNode = danglingLine.getProperty(Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + CgmesNames.TOPOLOGICAL_NODE_BOUNDARY); + if (dlBoundaryNode != null) { + return !boundaryDcNodes.contains(dlBoundaryNode); } + return true; } /** diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/Conversion.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/Conversion.java index 757dd5787ac..fc1568b1b92 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/Conversion.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/Conversion.java @@ -231,13 +231,8 @@ public Network convert(ReportNode reportNode) { } if (config.importControlAreas()) { - context.pushReportNode(CgmesReports.convertingElementTypeReport(reportNode, CgmesNames.CONTROL_AREA)); - network.newExtension(CgmesControlAreasAdder.class).add(); - CgmesControlAreas cgmesControlAreas = network.getExtension(CgmesControlAreas.class); - cgmes.controlAreas().forEach(ca -> createControlArea(cgmesControlAreas, ca)); - cgmes.tieFlows().forEach(tf -> addTieFlow(context, cgmesControlAreas, tf)); - cgmesControlAreas.cleanIfEmpty(); - context.popReportNode(); + convert(cgmes.controlAreas(), CgmesNames.CONTROL_AREA, context); + convert(cgmes.tieFlows(), CgmesNames.TIE_FLOW, context); } context.pushReportNode(CgmesReports.convertingElementTypeReport(reportNode, CgmesNames.REGULATING_CONTROL)); @@ -401,33 +396,6 @@ private static void completeVoltagesAndAngles(Network network) { network.getTieLines().forEach(tieLine -> AbstractConductingEquipmentConversion.calculateVoltageAndAngleInBoundaryBus(tieLine.getDanglingLine1(), tieLine.getDanglingLine2())); } - private static void createControlArea(CgmesControlAreas cgmesControlAreas, PropertyBag ca) { - String controlAreaId = ca.getId("ControlArea"); - cgmesControlAreas.newCgmesControlArea() - .setId(controlAreaId) - .setName(ca.getLocal("name")) - .setEnergyIdentificationCodeEic(ca.getLocal("energyIdentCodeEic")) - .setNetInterchange(ca.asDouble("netInterchange", Double.NaN)) - .setPTolerance(ca.asDouble("pTolerance", Double.NaN)) - .add(); - } - - private static void addTieFlow(Context context, CgmesControlAreas cgmesControlAreas, PropertyBag tf) { - String controlAreaId = tf.getId("ControlArea"); - CgmesControlArea cgmesControlArea = cgmesControlAreas.getCgmesControlArea(controlAreaId); - if (cgmesControlArea == null) { - context.ignored("Tie Flow", String.format("Tie Flow %s refers to a non-existing control area", tf.getId("TieFlow"))); - return; - } - String terminalId = tf.getId("terminal"); - Boundary boundary = context.terminalMapping().findBoundary(terminalId, context.cgmes()); - if (boundary != null) { - cgmesControlArea.add(boundary); - return; - } - RegulatingTerminalMapper.mapForTieFlow(terminalId, context).ifPresent(cgmesControlArea::add); - } - private void convert(PropertyBags elements, String elementType, Context context) { context.pushReportNode(CgmesReports.convertingElementTypeReport(context.getReportNode(), elementType)); for (PropertyBag element : elements) { @@ -452,6 +420,8 @@ private void convert(PropertyBags elements, String elementType, Context context) case CgmesNames.SERIES_COMPENSATOR -> new SeriesCompensatorConversion(element, context); case CgmesNames.OPERATIONAL_LIMIT -> new OperationalLimitConversion(element, context); case CgmesNames.SV_INJECTION -> new SvInjectionConversion(element, context); + case CgmesNames.CONTROL_AREA -> new ControlAreaConversion(element, context); + case CgmesNames.TIE_FLOW -> new TieFlowConversion(element, context); default -> throw new IllegalArgumentException("Invalid elementType."); }; if (c.insideBoundary()) { diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/RegulatingTerminalMapper.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/RegulatingTerminalMapper.java index e85443331c5..dc94ce656de 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/RegulatingTerminalMapper.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/RegulatingTerminalMapper.java @@ -28,7 +28,7 @@ * @author Luma Zamarreño {@literal } * @author José Antonio Marqués {@literal } */ -final class RegulatingTerminalMapper { +public final class RegulatingTerminalMapper { private RegulatingTerminalMapper() { // Empty constructor for utility class @@ -105,7 +105,7 @@ private static Stream allTerminals(VoltageLevel vl, Set< .filter(terminal -> vertices.contains(terminalToVertex.apply(terminal))); } - static class TerminalAndSign { + public static class TerminalAndSign { private final Terminal terminal; private final int sign; diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/ControlAreaConversion.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/ControlAreaConversion.java new file mode 100644 index 00000000000..f61c4efc30c --- /dev/null +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/ControlAreaConversion.java @@ -0,0 +1,47 @@ +/** + Copyright (c) 2024, 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.elements; + +import com.powsybl.cgmes.conversion.Context; +import com.powsybl.cgmes.model.CgmesNames; +import com.powsybl.iidm.network.Area; +import com.powsybl.triplestore.api.PropertyBag; + +/** + * @author Luma Zamarreño {@literal } + */ +public class ControlAreaConversion extends AbstractIdentifiedObjectConversion { + + public ControlAreaConversion(PropertyBag area, Context context) { + super(CgmesNames.CONTROL_AREA, area, context); + } + + @Override + public boolean valid() { + return true; + } + + @Override + public void convert() { + String controlAreaId = p.getId(CgmesNames.CONTROL_AREA); + String type = p.getLocal("controlAreaType"); + Area area = context.network().newArea() + .setAreaType(type) // Copy the type defined by CGMES + .setId(controlAreaId) + .setName(p.getLocal("name")) + .setInterchangeTarget(p.asDouble("netInterchange", Double.NaN)) + .add(); + if (p.containsKey(CgmesNames.P_TOLERANCE)) { + String pTolerance = p.get(CgmesNames.P_TOLERANCE); + area.setProperty(CgmesNames.P_TOLERANCE, pTolerance); + } + if (p.containsKey(CgmesNames.ENERGY_IDENT_CODE_EIC)) { + area.addAlias(p.get(CgmesNames.ENERGY_IDENT_CODE_EIC), CgmesNames.ENERGY_IDENT_CODE_EIC); + } + } +} diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/TieFlowConversion.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/TieFlowConversion.java new file mode 100644 index 00000000000..985b8d8c04d --- /dev/null +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/TieFlowConversion.java @@ -0,0 +1,63 @@ +/** + Copyright (c) 2024, 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.elements; + +import com.powsybl.cgmes.conversion.Context; +import com.powsybl.cgmes.conversion.RegulatingTerminalMapper; +import com.powsybl.cgmes.model.CgmesNames; +import com.powsybl.cgmes.model.CgmesTerminal; +import com.powsybl.iidm.network.Area; +import com.powsybl.iidm.network.Boundary; +import com.powsybl.triplestore.api.PropertyBag; + +/** + * @author Luma Zamarreño {@literal } + */ +public class TieFlowConversion extends AbstractIdentifiedObjectConversion { + + public TieFlowConversion(PropertyBag tieFlow, Context context) { + super(CgmesNames.TIE_FLOW, tieFlow, context); + } + + @Override + public boolean valid() { + return true; + } + + @Override + public void convert() { + String controlAreaId = p.getId(CgmesNames.CONTROL_AREA); + Area area = context.network().getArea(controlAreaId); + if (area == null) { + context.ignored("Tie Flow", String.format("Tie Flow %s refers to a non-existing control area", p.getId("TieFlow"))); + return; + } + String terminalId = p.getId("terminal"); + boolean isAc = isConsideredAcTieFlow(terminalId); + Boundary boundary = context.terminalMapping().findBoundary(terminalId, context.cgmes()); + if (boundary != null) { + area.newAreaBoundary() + .setAc(isAc) + .setBoundary(boundary) + .add(); + return; + } + RegulatingTerminalMapper.mapForTieFlow(terminalId, context) + .ifPresent(t -> area.newAreaBoundary() + .setAc(isAc) + .setTerminal(t) + .add()); + } + + private boolean isConsideredAcTieFlow(String terminalId) { + CgmesTerminal cgmesTerminal = context.cgmes().terminal(terminalId); + String node = cgmesTerminal.topologicalNode() == null ? cgmesTerminal.connectivityNode() : cgmesTerminal.topologicalNode(); + boolean isDc = context.boundary().isHvdc(node); + return !isDc; + } +} diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportContext.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportContext.java index 409b0376e1f..26c87c95f29 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportContext.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportContext.java @@ -154,6 +154,10 @@ public CgmesExportContext(Network network, ReferenceDataProvider referenceDataPr } } + public ReferenceDataProvider getReferenceDataProvider() { + return referenceDataProvider; + } + private CgmesTopologyKind networkTopologyKind(Network network) { for (VoltageLevel vl : network.getVoltageLevels()) { if (vl.getTopologyKind().equals(TopologyKind.NODE_BREAKER)) { @@ -180,7 +184,6 @@ public void addIidmMappings(Network network) { addIidmMappingsStaticVarCompensators(network); addIidmMappingsEndsAndTapChangers(network); addIidmMappingsEquivalentInjection(network); - addIidmMappingsControlArea(network); } private void addIidmMappingsSubstations(Network network) { @@ -531,24 +534,6 @@ private void addIidmMappingsEquivalentInjection(Network network) { } } - private void addIidmMappingsControlArea(Network network) { - CgmesControlAreas cgmesControlAreas = network.getExtension(CgmesControlAreas.class); - if (cgmesControlAreas == null) { - network.newExtension(CgmesControlAreasAdder.class).add(); - cgmesControlAreas = network.getExtension(CgmesControlAreas.class); - String cgmesControlAreaId = namingStrategy.getCgmesId(refTyped(network), CONTROL_AREA); - cgmesControlAreas.newCgmesControlArea() - .setId(cgmesControlAreaId) - .setName("Network") - .setEnergyIdentificationCodeEic("Network--1") - .add(); - CgmesControlArea cgmesControlArea = cgmesControlAreas.getCgmesControlArea(cgmesControlAreaId); - for (DanglingLine danglingLine : CgmesExportUtil.getBoundaryDanglingLines(network)) { - cgmesControlArea.add(danglingLine.getTerminal()); - } - } - } - public int getCimVersion() { return cim.getVersion(); } diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/EquipmentExport.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/EquipmentExport.java index 1ecfdecb705..ec069d43c99 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/EquipmentExport.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/EquipmentExport.java @@ -1383,69 +1383,66 @@ private static void writeAcdcConverterDCTerminal(String id, String conductingEqu } private static void writeControlAreas(String energyAreaId, Network network, String cimNamespace, String euNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { - CgmesControlAreas cgmesControlAreas = network.getExtension(CgmesControlAreas.class); - for (CgmesControlArea cgmesControlArea : cgmesControlAreas.getCgmesControlAreas()) { - writeControlArea(cgmesControlArea, energyAreaId, cimNamespace, euNamespace, writer, context, network); + // Log a warning if we are a stand-alone network (an IGM) and no control area is being exported + long numControlAreas = network.getAreaStream().filter(a -> a.getAreaType().equals("ControlAreaTypeKind.Interchange")).count(); + int numSubnetworks = network.getSubnetworks().size(); + if (numControlAreas == 0 && numSubnetworks == 0) { + LOG.warn("No control area of type interchange is being exported"); + } + + for (Area area : network.getAreas()) { + if (area.getAreaType().equals("ControlAreaTypeKind.Interchange")) { + writeControlArea(area, energyAreaId, cimNamespace, euNamespace, writer, context); + } } } - private static void writeControlArea(CgmesControlArea cgmesControlArea, String energyAreaId, String cimNamespace, String euNamespace, - XMLStreamWriter writer, CgmesExportContext context, Network network) throws XMLStreamException { + private static void writeControlArea(Area controlArea, String energyAreaId, String cimNamespace, String euNamespace, + XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { // Original control area identifiers may not respect mRID rules, so we pass it through naming strategy // to obtain always valid mRID identifiers - String controlAreaCgmesId = context.getNamingStrategy().getCgmesId(cgmesControlArea.getId()); - ControlAreaEq.write(controlAreaCgmesId, cgmesControlArea.getName(), cgmesControlArea.getEnergyIdentificationCodeEIC(), energyAreaId, cimNamespace, euNamespace, writer, context); - for (Terminal terminal : cgmesControlArea.getTerminals()) { - Connectable c = terminal.getConnectable(); - if (c instanceof DanglingLine dl) { - if (network.isBoundaryElement(dl)) { - String tieFlowId = context.getNamingStrategy().getCgmesId(refTyped(c), TIE_FLOW); - String terminalId = context.getNamingStrategy().getCgmesIdFromAlias(dl, Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + TERMINAL_BOUNDARY); - TieFlowEq.write(tieFlowId, controlAreaCgmesId, terminalId, cimNamespace, writer, context); - } else { - LOG.error("Unsupported tie flow at TieLine boundary {}", dl.getId()); - } - } else { - LOG.warn("Ignored tie flow at {}: should be a dangling line to retrieve boundary terminal", terminal.getConnectable().getId()); - } + String controlAreaCgmesId = context.getNamingStrategy().getCgmesId(controlArea.getId()); + String energyIdentCodeEic = controlArea.getAliasFromType(CgmesNames.ENERGY_IDENT_CODE_EIC).orElse(""); + ControlAreaEq.write(controlAreaCgmesId, controlArea.getNameOrId(), energyIdentCodeEic, energyAreaId, cimNamespace, euNamespace, writer, context); + for (AreaBoundary areaBoundary : controlArea.getAreaBoundaries()) { + TieFlow.from(areaBoundary, context).ifPresent(tieFlow -> + TieFlowEq.write(tieFlow.id(), controlAreaCgmesId, tieFlow.terminalId(), cimNamespace, writer, context) + ); } - for (Boundary boundary : cgmesControlArea.getBoundaries()) { - String terminalId = getTieFlowBoundaryTerminal(boundary, context, network); + } + + private record TieFlow(String id, String terminalId) { + static Optional from(AreaBoundary areaBoundary, CgmesExportContext context) { + return areaBoundary.getTerminal().map(terminal -> from(terminal, context)) + .orElse(areaBoundary.getBoundary().flatMap(boundary -> from(boundary, context))); + } + + static Optional from(Terminal terminal, CgmesExportContext context) { + return Optional.of(new TieFlow( + context.getNamingStrategy().getCgmesId(refTyped(terminal.getConnectable()), TIE_FLOW), + CgmesExportUtil.getTerminalId(terminal, context))); + } + + static Optional from(Boundary boundary, CgmesExportContext context) { + String terminalId = getTieFlowBoundaryTerminal(boundary, context); if (terminalId != null) { - String tieFlowId = context.getNamingStrategy().getCgmesId(ref(terminalId), TIE_FLOW); - TieFlowEq.write(tieFlowId, controlAreaCgmesId, terminalId, cimNamespace, writer, context); + return Optional.of(new TieFlow( + context.getNamingStrategy().getCgmesId(ref(terminalId), TIE_FLOW), + terminalId)); + } else { + return Optional.empty(); } } } - private static String getTieFlowBoundaryTerminal(Boundary boundary, CgmesExportContext context, Network network) { + private static String getTieFlowBoundaryTerminal(Boundary boundary, CgmesExportContext context) { DanglingLine dl = boundary.getDanglingLine(); - if (network.isBoundaryElement(dl)) { - return context.getNamingStrategy().getCgmesIdFromAlias(dl, Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + TERMINAL_BOUNDARY); - } else { - // This means the boundary corresponds to a TieLine. - // Because the network should not be a merging view, - // the only way to have a TieLine in the model is that - // the original data for the network contained both halves of the TieLine. - // That is, the initial CGMES data contains the two ACLSs at each side of one boundary point. - - // Currently, we are exporting TieLines in the EQ as a single ACLS, - // We are not exporting the individual halves of the tie line as separate equipment. - // So we do not have terminals for the boundary points. - - // This error should be fixed exporting the two halves of the TieLine to the EQ, - // with their corresponding terminals. - // Also, the boundary node should not be exported but referenced, - // as it should be defined in the boundary, not in the instance EQ file. - - LOG.error("Unsupported tie flow at TieLine boundary {}", dl.getId()); - return null; - } + return context.getNamingStrategy().getCgmesIdFromAlias(dl, Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + TERMINAL_BOUNDARY); } private static void writeTerminals(Network network, Map mapTerminal2Id, Map mapNodeKey2NodeId, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { - for (Connectable c : network.getConnectables()) { // TODO write boundary terminals for tie lines from CGMES + for (Connectable c : network.getConnectables()) { if (context.isExportedEquipment(c)) { for (Terminal t : c.getTerminals()) { writeTerminal(t, mapTerminal2Id, mapNodeKey2NodeId, cimNamespace, writer, context); diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/ReferenceDataProvider.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/ReferenceDataProvider.java index 3b5cb874f99..d1ffee74ea4 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/ReferenceDataProvider.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/ReferenceDataProvider.java @@ -37,6 +37,7 @@ public class ReferenceDataProvider { private final Map baseVoltagesByNominalVoltage = new HashMap<>(); private String equipmentBoundaryId = null; private String topologyBoundaryId = null; + private PropertyBags boundaryNodes = null; private boolean loaded = false; @@ -58,6 +59,10 @@ public String getBaseVoltage(double nominalV) { return baseVoltagesByNominalVoltage.get(nominalV); } + public PropertyBags getBoundaryNodes() { + return boundaryNodes; + } + public PropertyBag getSourcingActor() { ensureReferenceDataIsLoaded(); return sourcingActor; @@ -89,6 +94,7 @@ private void ensureReferenceDataIsLoaded() { loadBoundaryModelIds(); loadBaseVoltages(); loadSourcingActor(); + loadBoundaryNodes(); loaded = true; } @@ -138,6 +144,13 @@ private void loadBaseVoltages() { ))); } + private void loadBoundaryNodes() { + if (referenceData == null) { + return; + } + boundaryNodes = referenceData.boundaryNodes(); + } + private void loadSourcingActor() { if (referenceData != null) { if (sourcingActorName == null || sourcingActorName.isEmpty()) { diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/SteadyStateHypothesisExport.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/SteadyStateHypothesisExport.java index 3e994d5370d..200eaa22292 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/SteadyStateHypothesisExport.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/SteadyStateHypothesisExport.java @@ -10,8 +10,6 @@ import com.powsybl.cgmes.conversion.CgmesExport; import com.powsybl.cgmes.conversion.Conversion; import com.powsybl.cgmes.conversion.export.elements.RegulatingControlEq; -import com.powsybl.cgmes.extensions.CgmesControlArea; -import com.powsybl.cgmes.extensions.CgmesControlAreas; import com.powsybl.cgmes.extensions.CgmesTapChanger; import com.powsybl.cgmes.extensions.CgmesTapChangers; import com.powsybl.cgmes.model.CgmesMetadataModel; @@ -851,20 +849,26 @@ private static String generatingUnitClassname(Injection i) { } private static void writeControlAreas(Network network, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { - CgmesControlAreas areas = network.getExtension(CgmesControlAreas.class); - for (CgmesControlArea area : areas.getCgmesControlAreas()) { - writeControlArea(area, cimNamespace, writer, context); + for (Area area : network.getAreas()) { + if (area.getAreaType().equals("ControlAreaTypeKind.Interchange")) { + writeControlArea(area, cimNamespace, writer, context); + } } } - private static void writeControlArea(CgmesControlArea area, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { - String areaId = context.getNamingStrategy().getCgmesId(area.getId()); + private static void writeControlArea(Area controlArea, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { + String areaId = context.getNamingStrategy().getCgmesId(controlArea.getId()); CgmesExportUtil.writeStartAbout("ControlArea", areaId, cimNamespace, writer, context); writer.writeStartElement(cimNamespace, "ControlArea.netInterchange"); - writer.writeCharacters(CgmesExportUtil.format(area.getNetInterchange())); + double netInterchange = controlArea.getInterchangeTarget().orElse(Double.NaN); + writer.writeCharacters(CgmesExportUtil.format(netInterchange)); writer.writeEndElement(); - writer.writeStartElement(cimNamespace, "ControlArea.pTolerance"); - writer.writeCharacters(CgmesExportUtil.format(area.getPTolerance())); + double pTolerance; + if (controlArea.hasProperty("pTolerance")) { + pTolerance = Double.parseDouble(controlArea.getProperty("pTolerance")); + writer.writeStartElement(cimNamespace, "ControlArea.pTolerance"); + writer.writeCharacters(CgmesExportUtil.format(pTolerance)); + } writer.writeEndElement(); writer.writeEndElement(); } diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/ControlAreaEq.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/ControlAreaEq.java index 0f05ff1e15e..6709096be92 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/ControlAreaEq.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/ControlAreaEq.java @@ -22,10 +22,10 @@ public final class ControlAreaEq { private static final String CONTROL_AREA_TYPE = "ControlAreaTypeKind.Interchange"; - public static void write(String id, String controlAreaName, String energyIdentificationCodeEIC, String energyAreaId, String cimNamespace, String euNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { + public static void write(String id, String controlAreaName, String energyIdentCodeEIC, String energyAreaId, String cimNamespace, String euNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { CgmesExportUtil.writeStartIdName("ControlArea", id, controlAreaName, cimNamespace, writer, context); writer.writeStartElement(euNamespace, "IdentifiedObject.energyIdentCodeEic"); - writer.writeCharacters(energyIdentificationCodeEIC); + writer.writeCharacters(energyIdentCodeEIC); writer.writeEndElement(); writer.writeEmptyElement(cimNamespace, "ControlArea.type"); writer.writeAttribute(RDF_NAMESPACE, CgmesNames.RESOURCE, cimNamespace + CONTROL_AREA_TYPE); diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/TieFlowEq.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/TieFlowEq.java index f685fab3e6d..91996898a60 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/TieFlowEq.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/elements/TieFlowEq.java @@ -9,6 +9,7 @@ import com.powsybl.cgmes.conversion.export.CgmesExportContext; import com.powsybl.cgmes.conversion.export.CgmesExportUtil; +import com.powsybl.commons.PowsyblException; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; @@ -18,14 +19,18 @@ */ public final class TieFlowEq { - public static void write(String id, String controlAreaId, String terminalId, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException { - CgmesExportUtil.writeStartId("TieFlow", id, false, cimNamespace, writer, context); - CgmesExportUtil.writeReference("TieFlow.ControlArea", controlAreaId, cimNamespace, writer, context); - CgmesExportUtil.writeReference("TieFlow.Terminal", terminalId, cimNamespace, writer, context); - writer.writeStartElement(cimNamespace, "TieFlow.positiveFlowIn"); - writer.writeCharacters("true"); // always true - writer.writeEndElement(); - writer.writeEndElement(); + public static void write(String id, String controlAreaId, String terminalId, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) { + try { + CgmesExportUtil.writeStartId("TieFlow", id, false, cimNamespace, writer, context); + CgmesExportUtil.writeReference("TieFlow.ControlArea", controlAreaId, cimNamespace, writer, context); + CgmesExportUtil.writeReference("TieFlow.Terminal", terminalId, cimNamespace, writer, context); + writer.writeStartElement(cimNamespace, "TieFlow.positiveFlowIn"); + writer.writeCharacters("true"); // always true + writer.writeEndElement(); + writer.writeEndElement(); + } catch (XMLStreamException x) { + throw new PowsyblException(x); + } } private TieFlowEq() { diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/TieFlowConversionTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/TieFlowConversionTest.java index 1f78d2f3517..6babf4909a6 100644 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/TieFlowConversionTest.java +++ b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/TieFlowConversionTest.java @@ -8,11 +8,10 @@ package com.powsybl.cgmes.conversion.test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.io.IOException; - +import com.powsybl.cgmes.conversion.CgmesImport; +import com.powsybl.commons.datasource.ResourceDataSource; +import com.powsybl.commons.datasource.ResourceSet; +import com.powsybl.iidm.network.Area; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,12 +19,14 @@ import com.powsybl.cgmes.conformity.Cgmes3ModifiedCatalog; import com.powsybl.cgmes.conformity.CgmesConformity1ModifiedCatalog; import com.powsybl.cgmes.conversion.Conversion; -import com.powsybl.cgmes.extensions.CgmesControlArea; -import com.powsybl.cgmes.extensions.CgmesControlAreas; import com.powsybl.cgmes.model.GridModelReference; import com.powsybl.iidm.network.IdentifiableType; import com.powsybl.iidm.network.Network; +import java.util.Properties; + +import static org.junit.jupiter.api.Assertions.*; + /** * @author Luma Zamarreño {@literal } * @author José Antonio Marqués {@literal } @@ -33,63 +34,75 @@ class TieFlowConversionTest { @Test - void smallBaseCaseTieFlowMappedToSwitch() throws IOException { + void smallBaseCaseTieFlowMappedToSwitch() { Conversion.Config config = new Conversion.Config(); Network n = networkModel(Cgmes3ModifiedCatalog.smallGridBaseCaseTieFlowMappedToSwitch(), config); - CgmesControlAreas cgmesControlAreas = n.getExtension(CgmesControlAreas.class); - assertEquals(1, cgmesControlAreas.getCgmesControlAreas().size()); + assertEquals(1, n.getAreaStream().count()); - cgmesControlAreas.getCgmesControlAreas().forEach(cgmesControlArea -> { - assertEquals(1, cgmesControlArea.getTerminals().size()); - assertEquals(2, cgmesControlArea.getBoundaries().size()); - assertTrue(containsTerminal(cgmesControlArea, "044ef2e7-c766-11e1-8775-005056c00008", IdentifiableType.DANGLING_LINE)); - }); + Area controlArea = n.getAreas().iterator().next(); + assertEquals(1, controlArea.getAreaBoundaryStream().filter(b -> b.getTerminal().isPresent()).count()); + assertEquals(2, controlArea.getAreaBoundaryStream().filter(b -> b.getBoundary().isPresent()).count()); + assertTrue(containsTerminal(controlArea, "044ef2e7-c766-11e1-8775-005056c00008", IdentifiableType.DANGLING_LINE)); } @Test - void smallBaseCaseTieFlowMappedToEquivalentInjection() throws IOException { + void smallBaseCaseTieFlowMappedToEquivalentInjection() { Conversion.Config config = new Conversion.Config(); Network n = networkModel(Cgmes3ModifiedCatalog.smallGridBaseCaseTieFlowMappedToEquivalentInjection(), config); - CgmesControlAreas cgmesControlAreas = n.getExtension(CgmesControlAreas.class); - assertEquals(1, cgmesControlAreas.getCgmesControlAreas().size()); + assertEquals(1, n.getAreaStream().count()); - cgmesControlAreas.getCgmesControlAreas().forEach(cgmesControlArea -> { - assertEquals(0, cgmesControlArea.getTerminals().size()); - assertEquals(3, cgmesControlArea.getBoundaries().size()); - assertTrue(containsBoundary(cgmesControlArea, "044ef2e7-c766-11e1-8775-005056c00008", IdentifiableType.DANGLING_LINE)); - }); + Area controlArea = n.getAreas().iterator().next(); + assertEquals(0, controlArea.getAreaBoundaryStream().filter(b -> b.getTerminal().isPresent()).count()); + assertEquals(3, controlArea.getAreaBoundaryStream().filter(b -> b.getBoundary().isPresent()).count()); + assertTrue(containsBoundary(controlArea, "044ef2e7-c766-11e1-8775-005056c00008", IdentifiableType.DANGLING_LINE)); } @Test - void microGridBaseCaseBEWithTieFlowMappedToEquivalentInjection() throws IOException { + void microGridBaseCaseBEWithTieFlowMappedToEquivalentInjection() { Conversion.Config config = new Conversion.Config(); Network n = networkModel(CgmesConformity1ModifiedCatalog.microGridBaseCaseBEWithTieFlowMappedToEquivalentInjection(), config); - CgmesControlAreas cgmesControlAreas = n.getExtension(CgmesControlAreas.class); - assertEquals(1, cgmesControlAreas.getCgmesControlAreas().size()); + assertEquals(1, n.getAreaStream().count()); - cgmesControlAreas.getCgmesControlAreas().forEach(cgmesControlArea -> { - assertEquals(4, cgmesControlArea.getTerminals().size()); - assertEquals(1, cgmesControlArea.getBoundaries().size()); - assertTrue(containsBoundary(cgmesControlArea, "17086487-56ba-4979-b8de-064025a6b4da", IdentifiableType.DANGLING_LINE)); - }); + Area controlArea = n.getAreas().iterator().next(); + assertEquals(4, controlArea.getAreaBoundaryStream().filter(b -> b.getTerminal().isPresent()).count()); + assertEquals(1, controlArea.getAreaBoundaryStream().filter(b -> b.getBoundary().isPresent()).count()); + assertTrue(containsBoundary(controlArea, "17086487-56ba-4979-b8de-064025a6b4da", IdentifiableType.DANGLING_LINE)); } @Test - void microGridBaseCaseBEWithTieFlowMappedToSwitch() throws IOException { + void microGridBaseCaseBEWithTieFlowMappedToSwitch() { Conversion.Config config = new Conversion.Config(); Network n = networkModel(CgmesConformity1ModifiedCatalog.microGridBaseCaseBEWithTieFlowMappedToSwitch(), config); - CgmesControlAreas cgmesControlAreas = n.getExtension(CgmesControlAreas.class); - assertEquals(1, cgmesControlAreas.getCgmesControlAreas().size()); + assertEquals(1, n.getAreaStream().count()); - cgmesControlAreas.getCgmesControlAreas().forEach(cgmesControlArea -> { - assertEquals(5, cgmesControlArea.getTerminals().size()); - assertEquals(0, cgmesControlArea.getBoundaries().size()); - assertTrue(containsTerminal(cgmesControlArea, "17086487-56ba-4979-b8de-064025a6b4da", IdentifiableType.DANGLING_LINE)); - }); + Area controlArea = n.getAreas().iterator().next(); + assertEquals(5, controlArea.getAreaBoundaryStream().filter(b -> b.getTerminal().isPresent()).count()); + assertEquals(0, controlArea.getAreaBoundaryStream().filter(b -> b.getBoundary().isPresent()).count()); + assertTrue(containsTerminal(controlArea, "17086487-56ba-4979-b8de-064025a6b4da", IdentifiableType.DANGLING_LINE)); + } + + @Test + void testHvdcTieFlow() { + Network n = Network.read(new ResourceDataSource("HvdcTieFlow", + new ResourceSet("/", "HvdcTieFlow_EQ.xml", "HvdcTieFlow_EQBD.xml", "HvdcTieFlow_TPBD.xml"))); + assertNotNull(n); + // The first and only boundary inside the control area must be boundary and HVDC + assertTrue(n.getArea("Control_Area").getAreaBoundaries().iterator().next().getBoundary().isPresent()); + assertFalse(n.getArea("Control_Area").getAreaBoundaries().iterator().next().isAc()); + + Properties importConvertingBoundary = new Properties(); + importConvertingBoundary.put(CgmesImport.CONVERT_BOUNDARY, "true"); + Network n2 = Network.read(new ResourceDataSource("TieFlows", + new ResourceSet("/", "HvdcTieFlow_EQ.xml", "HvdcTieFlow_EQBD.xml", "HvdcTieFlow_TPBD.xml")), + importConvertingBoundary); + assertNotNull(n2); + // The first and only boundary inside the control area must be a terminal and HVDC + assertTrue(n2.getArea("Control_Area").getAreaBoundaries().iterator().next().getTerminal().isPresent()); + assertFalse(n2.getArea("Control_Area").getAreaBoundaries().iterator().next().isAc()); } private Network networkModel(GridModelReference testGridModel, Conversion.Config config) { @@ -97,24 +110,28 @@ private Network networkModel(GridModelReference testGridModel, Conversion.Config return ConversionUtil.networkModel(testGridModel, config); } - private static boolean containsTerminal(CgmesControlArea cgmesControlArea, String connectableId, IdentifiableType identifiableType) { - boolean ok = cgmesControlArea.getTerminals().stream().anyMatch(t -> isConnectableOk(connectableId, identifiableType, - t.getConnectable().getId(), t.getConnectable().getType())); + private static boolean containsTerminal(Area controlArea, String connectableId, IdentifiableType identifiableType) { + boolean ok = controlArea.getAreaBoundaryStream().filter(b -> b.getTerminal().isPresent()).anyMatch(t -> isConnectableOk(connectableId, identifiableType, + t.getTerminal().get().getConnectable().getId(), t.getTerminal().get().getConnectable().getType())); if (!ok) { LOG.info("Terminal to find connectableId {} identifiableType {}", connectableId, identifiableType); - cgmesControlArea.getTerminals().forEach(t -> LOG.info("Terminal inside cgmesControlArea connectableId {} identifiableType {}", - t.getConnectable().getId(), t.getConnectable().getType())); + controlArea.getAreaBoundaryStream().filter(b -> b.getTerminal().isPresent()).forEach(b -> LOG.info("Terminal inside cgmesControlArea connectableId {} identifiableType {}", + b.getTerminal().get().getConnectable().getId(), b.getTerminal().get().getConnectable().getType())); } return ok; } - private static boolean containsBoundary(CgmesControlArea cgmesControlArea, String connectableId, IdentifiableType identifiableType) { - boolean ok = cgmesControlArea.getBoundaries().stream().anyMatch(b -> isConnectableOk(connectableId, identifiableType, - b.getDanglingLine().getId(), b.getDanglingLine().getType())); + private static boolean containsBoundary(Area controlArea, String connectableId, IdentifiableType identifiableType) { + boolean ok = controlArea.getAreaBoundaryStream() + .filter(b -> b.getBoundary().isPresent()) + .anyMatch(b -> isConnectableOk(connectableId, identifiableType, + b.getBoundary().get().getDanglingLine().getId(), b.getBoundary().get().getDanglingLine().getType())); if (!ok) { LOG.info("Boundary to find connectableId {} identifiableType {}", connectableId, identifiableType); - cgmesControlArea.getBoundaries().forEach(b -> LOG.info("Boundary inside cgmesControlArea danglingLineId {}}", - b.getDanglingLine().getId())); + controlArea.getAreaBoundaryStream() + .filter(b -> b.getBoundary().isPresent()) + .forEach(b -> LOG.info("Boundary inside cgmesControlArea danglingLineId {}}", + b.getBoundary().get().getDanglingLine().getId())); } return ok; } diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/conformity/modified/CgmesConformity1ModifiedConversionTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/conformity/modified/CgmesConformity1ModifiedConversionTest.java index c85bf88011b..7848b322cf0 100644 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/conformity/modified/CgmesConformity1ModifiedConversionTest.java +++ b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/conformity/modified/CgmesConformity1ModifiedConversionTest.java @@ -15,8 +15,6 @@ import com.powsybl.cgmes.conversion.CgmesModelExtension; import com.powsybl.cgmes.conversion.Conversion; import com.powsybl.cgmes.conversion.test.ConversionUtil; -import com.powsybl.cgmes.extensions.CgmesControlArea; -import com.powsybl.cgmes.extensions.CgmesControlAreas; import com.powsybl.cgmes.extensions.CgmesMetadataModels; import com.powsybl.cgmes.model.*; import com.powsybl.commons.PowsyblException; @@ -327,12 +325,12 @@ void microBETieFlow() { Network network = new CgmesImport().importData(CgmesConformity1ModifiedCatalog.microGridBaseCaseBEWithTieFlow().dataSource(), NetworkFactory.findDefault(), importParams); - CgmesControlAreas cgmesControlAreas = network.getExtension(CgmesControlAreas.class); - CgmesControlArea cgmesControlArea = cgmesControlAreas.getCgmesControlArea("BECONTROLAREA"); - assertEquals("BE", cgmesControlArea.getName()); - assertEquals("10BE------1", cgmesControlArea.getEnergyIdentificationCodeEIC()); - assertEquals(-205.90011555672567, cgmesControlArea.getNetInterchange(), 0.0); - assertEquals(5, cgmesControlArea.getTerminals().size()); + Area area = network.getArea("BECONTROLAREA"); + assertEquals("ControlAreaTypeKind.Interchange", area.getAreaType()); + assertEquals("BE", area.getNameOrId()); + assertEquals("10BE------1", area.getAliasFromType(CgmesNames.ENERGY_IDENT_CODE_EIC).get()); + assertEquals(-205.90011555672567, area.getInterchangeTarget().getAsDouble(), 0.0); + assertEquals(5, area.getAreaBoundaryStream().count()); } @Test @@ -863,7 +861,7 @@ void miniNodeBreakerMissingSubstationRegion() { @Test void smallBusBranchTieFlowWithoutControlArea() { Network network = new CgmesImport().importData(CgmesConformity1ModifiedCatalog.smallBusBranchTieFlowsWithoutControlArea().dataSource(), NetworkFactory.findDefault(), importParams); - assertNull(network.getExtension(CgmesControlAreas.class)); + assertEquals(0, network.getAreaCount()); } @Test diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/CgmesExportTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/CgmesExportTest.java index 18b05913d20..fe23770690c 100644 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/CgmesExportTest.java +++ b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/CgmesExportTest.java @@ -672,5 +672,52 @@ void testCanGeneratorControl() throws IOException { } } + @Test + void networkWithoutControlAreaInterchange() throws IOException { + Network network = DanglingLineNetworkFactory.create(); + assertEquals(0, network.getAreaCount()); + + try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) { + Path tmpDir = Files.createDirectory(fs.getPath("/temp")); + String baseName = "dl-net"; + + // Exporting with default behaviour, no default control area is written + Path tmpDirNoCA = tmpDir.resolve("network-no-ca"); + Files.createDirectories(tmpDirNoCA); + network.write("CGMES", null, tmpDirNoCA.resolve(baseName)); + Network networkNoCA = Network.read(new GenericReadOnlyDataSource(tmpDirNoCA, baseName)); + assertEquals(0, networkNoCA.getAreaCount()); + + // Explicit creation of a default control area + new CgmesExport().createDefaultControlAreaInterchange(network); + + // Check that exported files now have a control area definition + // No default value for tolerance + Path tmpDirWithCA = tmpDir.resolve("network-with-ca"); + Files.createDirectories(tmpDirWithCA); + network.write("CGMES", null, tmpDirWithCA.resolve(baseName)); + Network networkWithCA = Network.read(new GenericReadOnlyDataSource(tmpDirWithCA, baseName)); + assertEquals(1, networkWithCA.getAreaCount()); + Area areaExported = networkWithCA.getAreas().iterator().next(); + assertEquals(1, areaExported.getAreaBoundaryStream().count()); + assertEquals(-50, areaExported.getInterchangeTarget().orElse(Double.NaN)); + // No default value for tolerance + assertNull(areaExported.getProperty(CgmesNames.P_TOLERANCE)); + + // Check that tolerance is exported only if explicitly defined + Area area = network.getAreas().iterator().next(); + area.setProperty(CgmesNames.P_TOLERANCE, "1.01"); + Path tmpDirWithCaTolerance = tmpDir.resolve("network-with-ca-tolerance"); + Files.createDirectories(tmpDirWithCaTolerance); + network.write("CGMES", null, tmpDirWithCaTolerance.resolve(baseName)); + Network networkWithCaTolerance = Network.read(new GenericReadOnlyDataSource(tmpDirWithCaTolerance, baseName)); + assertEquals(1, networkWithCaTolerance.getAreaCount()); + areaExported = networkWithCaTolerance.getAreas().iterator().next(); + assertEquals(1, areaExported.getAreaBoundaryStream().count()); + assertEquals(-50, areaExported.getInterchangeTarget().orElse(Double.NaN)); + assertEquals("1.01", areaExported.getProperty(CgmesNames.P_TOLERANCE)); + } + } + private static final double EPSILON = 1e-10; } diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/EquipmentExportTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/EquipmentExportTest.java index 5a9977b2829..c075696099e 100644 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/EquipmentExportTest.java +++ b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/EquipmentExportTest.java @@ -69,6 +69,7 @@ class EquipmentExportTest extends AbstractSerDeTest { private Properties importParams; + @Override @BeforeEach public void setUp() throws IOException { super.setUp(); @@ -159,29 +160,22 @@ void microGridBaseCaseAssembledSwitchAtBoundary() throws XMLStreamException, IOE ReadOnlyDataSource dataSource = CgmesConformity1ModifiedCatalog.microGridBaseCaseAssembledSwitchAtBoundary().dataSource(); Network network = new CgmesImport().importData(dataSource, NetworkFactory.findDefault(), importParams); - network.newExtension(CgmesControlAreasAdder.class).add(); - CgmesControlAreas cgmesControlAreas = network.getExtension(CgmesControlAreas.class); - CgmesControlArea cgmesControlArea = cgmesControlAreas.newCgmesControlArea() + // 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") - .setEnergyIdentificationCodeEic("energyIdentCodeEic") - .setNetInterchange(Double.NaN) + .setAreaType("ControlAreaTypeKind.Interchange") + .setInterchangeTarget(Double.NaN) + .addAreaBoundary(tieLine.getDanglingLine2().getBoundary(), true) .add(); - TieLine tieLine = network.getTieLine("78736387-5f60-4832-b3fe-d50daf81b0a6 + 7f43f508-2496-4b64-9146-0a40406cbe49"); - cgmesControlArea.add(tieLine.getDanglingLine2().getBoundary()); - - // TODO(Luma) updated expected result after halves of tie lines are exported as equipment - // instead of an error logged and the tie flow ignored, - // the reimported network control area should contain one tie flow - Network actual = exportImportNodeBreaker(network, dataSource); - CgmesControlArea actualCgmesControlArea = actual.getExtension(CgmesControlAreas.class).getCgmesControlArea("controlAreaId"); - boolean tieFlowsAtTieLinesAreSupported = false; - if (tieFlowsAtTieLinesAreSupported) { - assertEquals(1, actualCgmesControlArea.getBoundaries().size()); - assertEquals("7f43f508-2496-4b64-9146-0a40406cbe49", actualCgmesControlArea.getBoundaries().iterator().next().getDanglingLine().getId()); - } else { - assertEquals(0, actualCgmesControlArea.getBoundaries().size()); - } + 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 @@ -589,7 +583,10 @@ void microGridCgmesExportPreservingOriginalClassesOfLoads() throws IOException, assertEquals(loadsCreatedFromOriginalClassCount(expected, CgmesNames.NONCONFORM_LOAD), loadsCreatedFromOriginalClassCount(actual, CgmesNames.NONCONFORM_LOAD)); assertEquals(loadsCreatedFromOriginalClassCount(expected, CgmesNames.STATION_SUPPLY), loadsCreatedFromOriginalClassCount(actual, CgmesNames.STATION_SUPPLY)); - // Avoid comparing targetP and targetQ (reimport does not consider the SSH file); + // Remove the default control area created in expected network during export + expected.getAreaStream().map(Area::getId).toList().forEach(a -> expected.getArea(a).remove()); + + // 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()); @@ -667,7 +664,7 @@ void miniGridCgmesExportPreservingOriginalClassesOfGenerators() throws IOExcepti assertEquals(generatorsCreatedFromOriginalClassCount(expected, "ExternalNetworkInjection"), generatorsCreatedFromOriginalClassCount(actual, "ExternalNetworkInjection")); assertEquals(generatorsCreatedFromOriginalClassCount(expected, "EquivalentInjection"), generatorsCreatedFromOriginalClassCount(actual, "EquivalentInjection")); - // Avoid comparing targetP and targetQ (reimport does not consider the SSH file); + // 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()); @@ -1697,7 +1694,7 @@ private boolean compareNetworksEQdata(Network expected, Network actual, Differen // Export original and only EQ ExportOptions exportOptions = new ExportOptions(); - exportOptions.setExtensions(Collections.emptySet()); + exportOptions.setExtensions(Set.of("cgmesControlAreas")); exportOptions.setSorted(true); Path expectedPath = tmpDir.resolve("expected.xml"); @@ -1834,6 +1831,9 @@ private Network prepareNetworkForEQComparison(Network network) { 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); diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/ExportXmlCompare.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/ExportXmlCompare.java index dca16ba77ba..334496af09a 100644 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/ExportXmlCompare.java +++ b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/ExportXmlCompare.java @@ -465,7 +465,7 @@ static ComparisonResult ignoringControlAreaNetInterchange(Comparison comparison, } if (comparison.getType() == ComparisonType.ATTR_NAME_LOOKUP) { Comparison.Detail control = comparison.getControlDetails(); - if (control.getValue().toString().equals("netInterchange") + if (control.getValue() != null && control.getValue().toString().equals("netInterchange") && control.getTarget().getLocalName().equals("controlArea")) { return ComparisonResult.EQUAL; } diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/StateVariablesExportTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/StateVariablesExportTest.java index 79362611b81..4caf2f8ae40 100644 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/StateVariablesExportTest.java +++ b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/StateVariablesExportTest.java @@ -57,6 +57,7 @@ class StateVariablesExportTest extends AbstractSerDeTest { private Properties importParams; + @Override @BeforeEach public void setUp() throws IOException { super.setUp(); @@ -585,6 +586,7 @@ private boolean test(ReadOnlyDataSource dataSource, boolean exportTp, boolean ex // Import original importParams.put("iidm.import.cgmes.create-cgmes-export-mapping", "true"); Network expected0 = new CgmesImport().importData(dataSource, NetworkFactory.findDefault(), importParams); + boolean originalNetworkHasAreas = expected0.getAreaCount() > 0; // Ensure all information in IIDM mapping extensions is created // Some mappings are not built until export is requested @@ -638,9 +640,14 @@ private boolean test(ReadOnlyDataSource dataSource, boolean exportTp, boolean ex .forEach(t -> t.setP(0.0).setQ(0.0)); // Export original and with new SV - // comparison without extensions, only Networks + // comparison without extensions, only Networks, to avoid differences in CgmesControlAreas ExportOptions exportOptions = new ExportOptions().setSorted(true); exportOptions.setExtensions(Collections.emptySet()); + // Also, if a default area was created during export to CGMES, remove it from the expected network + // The actual network will not have it, it is the original network directly exported as IIDM + if (!originalNetworkHasAreas) { + expected.getAreaStream().map(Area::getId).toList().forEach(a -> expected.getArea(a).remove()); + } Path expectedPath = tmpDir.resolve("expected.xml"); Path actualPath = tmpDir.resolve("actual.xml"); NetworkSerDe.write(expected, exportOptions, expectedPath); diff --git a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/SteadyStateHypothesisExportTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/SteadyStateHypothesisExportTest.java index 43102c5c030..6bb3605374b 100644 --- a/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/SteadyStateHypothesisExportTest.java +++ b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/SteadyStateHypothesisExportTest.java @@ -14,14 +14,13 @@ import com.powsybl.cgmes.conversion.CgmesImport; import com.powsybl.cgmes.conversion.export.CgmesExportContext; import com.powsybl.cgmes.conversion.export.SteadyStateHypothesisExport; -import com.powsybl.cgmes.extensions.CgmesControlArea; -import com.powsybl.cgmes.extensions.CgmesControlAreas; import com.powsybl.cgmes.model.CgmesNamespace; import com.powsybl.commons.datasource.DirectoryDataSource; import com.powsybl.commons.datasource.ReadOnlyDataSource; import com.powsybl.commons.test.AbstractSerDeTest; import com.powsybl.commons.xml.XmlUtil; import com.powsybl.computation.DefaultComputationManagerConfig; +import com.powsybl.iidm.network.Area; import com.powsybl.iidm.network.ImportConfig; import com.powsybl.iidm.network.Network; import com.powsybl.iidm.network.NetworkFactory; @@ -55,6 +54,7 @@ class SteadyStateHypothesisExportTest extends AbstractSerDeTest { private Properties importParams; + @Override @BeforeEach public void setUp() throws IOException { super.setUp(); @@ -163,9 +163,9 @@ private boolean test(ReadOnlyDataSource dataSource, DifferenceEvaluator knownDif Network actual = Network.read(repackaged, DefaultComputationManagerConfig.load().createShortTimeExecutionComputationManager(), ImportConfig.load(), importParams); - // Remove ControlAreas extension - expected.removeExtension(CgmesControlAreas.class); - actual.removeExtension(CgmesControlAreas.class); + // Remove Areas + expected.getAreaStream().map(Area::getId).toList().forEach(a -> expected.getArea(a).remove()); + actual.getAreaStream().map(Area::getId).toList().forEach(a -> actual.getArea(a).remove()); // Export original and with new SSH Path expectedPath = tmpDir.resolve("expected.xml"); @@ -256,16 +256,16 @@ void testUpdateControlArea() throws IOException { // Read network and check control area data Network be = Network.read(CgmesConformity3Catalog.microGridBaseCaseBE().dataSource(), importParams); - CgmesControlAreas controlAreas = be.getExtension(CgmesControlAreas.class); - assertNotNull(controlAreas); - assertFalse(controlAreas.getCgmesControlAreas().isEmpty()); - CgmesControlArea controlArea = controlAreas.getCgmesControlAreas().iterator().next(); - assertEquals(236.9798, controlArea.getNetInterchange(), 1e-10); - assertEquals(10, controlArea.getPTolerance(), 1e-10); + long numControlAreas = be.getAreaStream().filter(a -> a.getAreaType().equals("ControlAreaTypeKind.Interchange")).count(); + assertEquals(1, numControlAreas); + Area controlArea = be.getAreas().iterator().next(); + assertEquals(236.9798, controlArea.getInterchangeTarget().getAsDouble(), 1e-10); + double pTolerance = Double.parseDouble(controlArea.getProperty("pTolerance")); + assertEquals(10, pTolerance, 1e-10); // Update control area data - controlArea.setNetInterchange(controlArea.getNetInterchange() * 2); - controlArea.setPTolerance(controlArea.getPTolerance() / 2); + controlArea.setInterchangeTarget(controlArea.getInterchangeTarget().getAsDouble() * 2); + controlArea.setProperty("pTolerance", Double.toString(pTolerance / 2)); // Write and read the network to check serialization of the extension Path updatedXiidm = outputPath.resolve("BE-updated.xiidm"); diff --git a/cgmes/cgmes-conversion/src/test/resources/HvdcTieFlow_EQ.xml b/cgmes/cgmes-conversion/src/test/resources/HvdcTieFlow_EQ.xml new file mode 100644 index 00000000000..6b3427ff443 --- /dev/null +++ b/cgmes/cgmes-conversion/src/test/resources/HvdcTieFlow_EQ.xml @@ -0,0 +1,70 @@ + + + 2024-11-14T23:00:00Z + 2024-11-14T10:22:58Z + Test TieFlows + 001 + http://entsoe.eu/CIM/EquipmentCore/3/1 + http://entsoe.eu/CIM/EquipmentOperation/3/1 + powsybl.org + + + false + 0 + 0 + Line + 0 + 0 + 1 + Line + 0.1 + 0.1 + 0 + 1 + 0.1 + + + + Terminal 1 + 1 + + + + + Terminal 2 + 2 + + + + + Node Network + + + + VL1 + + + + + Substation1 + Substation1 + + + + France + + + IDF + + + + Control Area + + + + Tie Flow 1 + true + + + + diff --git a/cgmes/cgmes-conversion/src/test/resources/HvdcTieFlow_EQBD.xml b/cgmes/cgmes-conversion/src/test/resources/HvdcTieFlow_EQBD.xml new file mode 100644 index 00000000000..7c4e62cfb74 --- /dev/null +++ b/cgmes/cgmes-conversion/src/test/resources/HvdcTieFlow_EQBD.xml @@ -0,0 +1,25 @@ + + + + 2024-11-14T23:00:00Z + 2024-11-14T10:22:58Z + 001 + Test TieFlow + powsybl.org + http://entsoe.eu/CIM/EquipmentBoundary/3/1 + http://entsoe.eu/CIM/EquipmentBoundaryOperation/3/1 + + + 1 + 110 + + + Node Boundary + HVDC boundary + true + + + + TieLine HVDC + + diff --git a/cgmes/cgmes-conversion/src/test/resources/HvdcTieFlow_TPBD.xml b/cgmes/cgmes-conversion/src/test/resources/HvdcTieFlow_TPBD.xml new file mode 100644 index 00000000000..ad277389b58 --- /dev/null +++ b/cgmes/cgmes-conversion/src/test/resources/HvdcTieFlow_TPBD.xml @@ -0,0 +1,23 @@ + + + + 2024-11-14T23:00:00Z + 2024-11-14T10:22:58Z + 1 + Test TieFlow + powsybl.org + http://entsoe.eu/CIM/TopologyBoundary/3/1 + + + + + + + Boundary Node TP + + + true + + \ No newline at end of file diff --git a/cgmes/cgmes-conversion/src/test/resources/functional-logs/microGridBaseCaseBE-invalid-voltage-bus.txt b/cgmes/cgmes-conversion/src/test/resources/functional-logs/microGridBaseCaseBE-invalid-voltage-bus.txt index ba2c1eafac1..f12ee29c44f 100644 --- a/cgmes/cgmes-conversion/src/test/resources/functional-logs/microGridBaseCaseBE-invalid-voltage-bus.txt +++ b/cgmes/cgmes-conversion/src/test/resources/functional-logs/microGridBaseCaseBE-invalid-voltage-bus.txt @@ -34,6 +34,7 @@ Converting OperationalLimit. Converting SvInjection. Converting ControlArea. + Converting TieFlow. + Converting RegulatingControl. Equipment 955d9cd0-4a10-4031-b008-60c0dc340a07 has a regulating control with bad target value for voltage: 0.0. Equipment fe25f43a-7341-446e-a71a-8ab7119ba806 has a regulating control with bad target value for voltage: 0.0. diff --git a/cgmes/cgmes-conversion/src/test/resources/functional-logs/microGridBaseCaseBE-target-deadband.txt b/cgmes/cgmes-conversion/src/test/resources/functional-logs/microGridBaseCaseBE-target-deadband.txt index d81410a9eda..2205b19bee7 100644 --- a/cgmes/cgmes-conversion/src/test/resources/functional-logs/microGridBaseCaseBE-target-deadband.txt +++ b/cgmes/cgmes-conversion/src/test/resources/functional-logs/microGridBaseCaseBE-target-deadband.txt @@ -32,6 +32,7 @@ Converting OperationalLimit. Converting SvInjection. Converting ControlArea. + Converting TieFlow. + Converting RegulatingControl. Equipment 955d9cd0-4a10-4031-b008-60c0dc340a07 has a regulating control with bad target value for voltage: 0.0. Equipment 955d9cd0-4a10-4031-b008-60c0dc340a07 has a regulating control with bad target deadband: -0.5. diff --git a/cgmes/cgmes-conversion/src/test/resources/functional-logs/microGridBaseCaseBE.txt b/cgmes/cgmes-conversion/src/test/resources/functional-logs/microGridBaseCaseBE.txt index 178ad6e4db5..830f8d141eb 100644 --- a/cgmes/cgmes-conversion/src/test/resources/functional-logs/microGridBaseCaseBE.txt +++ b/cgmes/cgmes-conversion/src/test/resources/functional-logs/microGridBaseCaseBE.txt @@ -36,6 +36,7 @@ Converting OperationalLimit. Converting SvInjection. Converting ControlArea. + Converting TieFlow. + Converting RegulatingControl. Equipment 955d9cd0-4a10-4031-b008-60c0dc340a07 has a regulating control with bad target value for voltage: 0.0. Equipment fe25f43a-7341-446e-a71a-8ab7119ba806 has a regulating control with bad target value for voltage: 0.0. diff --git a/cgmes/cgmes-conversion/src/test/resources/functional-logs/miniGridNodeBreaker.txt b/cgmes/cgmes-conversion/src/test/resources/functional-logs/miniGridNodeBreaker.txt index 153490be383..dc74f59932f 100644 --- a/cgmes/cgmes-conversion/src/test/resources/functional-logs/miniGridNodeBreaker.txt +++ b/cgmes/cgmes-conversion/src/test/resources/functional-logs/miniGridNodeBreaker.txt @@ -33,6 +33,7 @@ Converting OperationalLimit. Converting SvInjection. Converting ControlArea. + Converting TieFlow. Converting RegulatingControl. Fixing issues with dangling lines. + Setting voltages and angles. diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlArea.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlArea.java deleted file mode 100644 index c0bf843e29c..00000000000 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlArea.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * 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.extensions; - -import com.powsybl.commons.PowsyblException; -import com.powsybl.iidm.network.Boundary; -import com.powsybl.iidm.network.Terminal; - -import java.util.Set; - -/** - * @author Miora Ralambotiana {@literal } - */ -public interface CgmesControlArea { - - String getId(); - - String getName(); - - String getEnergyIdentificationCodeEIC(); - - double getNetInterchange(); - - void add(Terminal terminal); - - void add(Boundary boundary); - - Set getTerminals(); - - Set getBoundaries(); - - default void setNetInterchange(double netInterchange) { - throw new PowsyblException("Unsupported method"); - } - - default double getPTolerance() { - throw new PowsyblException("Unsupported method"); - } - - default void setPTolerance(double pTolerance) { - throw new PowsyblException("Unsupported method"); - } -} diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdder.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdder.java deleted file mode 100644 index 224cbd2b023..00000000000 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdder.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * 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.extensions; - -import com.powsybl.commons.PowsyblException; - -/** - * @author Miora Ralambotiana {@literal } - */ -public interface CgmesControlAreaAdder { - - CgmesControlAreaAdder setId(String id); - - CgmesControlAreaAdder setName(String name); - - CgmesControlAreaAdder setEnergyIdentificationCodeEic(String energyIdentificationCodeEic); - - CgmesControlAreaAdder setNetInterchange(double netInterchange); - - default CgmesControlAreaAdder setPTolerance(double pTolerance) { - throw new PowsyblException("Unsupported method"); - } - - CgmesControlArea add(); -} diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdderImpl.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdderImpl.java deleted file mode 100644 index 6156b8b97e9..00000000000 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdderImpl.java +++ /dev/null @@ -1,67 +0,0 @@ -/** - * 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.extensions; - -import com.powsybl.commons.PowsyblException; - -import java.util.Objects; - -/** - * @author Miora Ralambotiana {@literal } - */ -class CgmesControlAreaAdderImpl implements CgmesControlAreaAdder { - - private final CgmesControlAreasImpl mapping; - private String id; - private String name; - private String energyIdentificationCodeEic; - private double netInterchange = Double.NaN; - private double pTolerance = Double.NaN; - - CgmesControlAreaAdderImpl(CgmesControlAreasImpl mapping) { - this.mapping = Objects.requireNonNull(mapping); - } - - @Override - public CgmesControlAreaAdder setId(String id) { - this.id = id; - return this; - } - - @Override - public CgmesControlAreaAdder setName(String name) { - this.name = name; - return this; - } - - @Override - public CgmesControlAreaAdder setEnergyIdentificationCodeEic(String energyIdentificationCodeEic) { - this.energyIdentificationCodeEic = energyIdentificationCodeEic; - return this; - } - - @Override - public CgmesControlAreaAdder setNetInterchange(double netInterchange) { - this.netInterchange = netInterchange; - return this; - } - - @Override - public CgmesControlAreaAdder setPTolerance(double pTolerance) { - this.pTolerance = pTolerance; - return this; - } - - @Override - public CgmesControlAreaImpl add() { - if (id == null) { - throw new PowsyblException("Undefined ID for CGMES control area"); - } - return new CgmesControlAreaImpl(id, name, energyIdentificationCodeEic, netInterchange, pTolerance, mapping); - } -} diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaImpl.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaImpl.java deleted file mode 100644 index 427bae1c5a9..00000000000 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaImpl.java +++ /dev/null @@ -1,94 +0,0 @@ -/** - * 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.extensions; - -import com.powsybl.iidm.network.Boundary; -import com.powsybl.iidm.network.Terminal; - -import java.util.*; - -/** - * @author Marcos de Miguel {@literal } - */ -class CgmesControlAreaImpl implements CgmesControlArea { - private final String id; - private final String name; - private final String energyIdentificationCodeEic; - private final Set terminals = new LinkedHashSet<>(); - private final Set boundaries = new LinkedHashSet<>(); - private double netInterchange; - private double pTolerance; - - CgmesControlAreaImpl(String id, String name, String energyIdentificationCodeEic, double netInterchange, double pTolerance, CgmesControlAreasImpl mapping) { - this.id = Objects.requireNonNull(id); - this.name = name; - this.energyIdentificationCodeEic = energyIdentificationCodeEic; - this.netInterchange = netInterchange; - this.pTolerance = pTolerance; - attach(mapping); - } - - private void attach(CgmesControlAreasImpl mapping) { - mapping.putCgmesControlArea(this); - } - - @Override - public String getId() { - return id; - } - - @Override - public String getName() { - return name; - } - - @Override - public String getEnergyIdentificationCodeEIC() { - return energyIdentificationCodeEic; - } - - @Override - public Set getTerminals() { - return Collections.unmodifiableSet(terminals); - } - - @Override - public Set getBoundaries() { - return Collections.unmodifiableSet(boundaries); - } - - @Override - public double getNetInterchange() { - return netInterchange; - } - - @Override - public void add(Terminal terminal) { - terminals.add(terminal); - } - - @Override - public void add(Boundary boundary) { - boundaries.add(boundary); - } - - @Override - public void setNetInterchange(double netInterchange) { - this.netInterchange = netInterchange; - } - - @Override - public double getPTolerance() { - return pTolerance; - } - - @Override - public void setPTolerance(double pTolerance) { - this.pTolerance = pTolerance; - } -} diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreas.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreas.java deleted file mode 100644 index b3095e31bfc..00000000000 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreas.java +++ /dev/null @@ -1,41 +0,0 @@ -/** - * 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.extensions; - -import java.util.Collection; - -import com.powsybl.commons.extensions.Extension; -import com.powsybl.iidm.network.Network; - -/** - * @author Marcos de Miguel {@literal } - */ -public interface CgmesControlAreas extends Extension { - - String NAME = "cgmesControlAreas"; - - CgmesControlAreaAdder newCgmesControlArea(); - - Collection getCgmesControlAreas(); - - CgmesControlArea getCgmesControlArea(String controlAreaId); - - boolean containsCgmesControlAreaId(String controlAreaId); - - default void cleanIfEmpty() { - if (getCgmesControlAreas().isEmpty()) { - getExtendable().removeExtension(CgmesControlAreas.class); - } - } - - @Override - default String getName() { - return NAME; - } - -} diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdder.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdder.java deleted file mode 100644 index 151f69b8c14..00000000000 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdder.java +++ /dev/null @@ -1,22 +0,0 @@ -/** - * 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.extensions; - -import com.powsybl.commons.extensions.ExtensionAdder; -import com.powsybl.iidm.network.Network; - -/** - * @author Marcos de Miguel {@literal } - */ -public interface CgmesControlAreasAdder extends ExtensionAdder { - - @Override - default Class getExtensionClass() { - return CgmesControlAreas.class; - } -} diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdderImpl.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdderImpl.java deleted file mode 100644 index efdfdb67704..00000000000 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdderImpl.java +++ /dev/null @@ -1,27 +0,0 @@ -/** - * 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.extensions; - -import com.powsybl.commons.extensions.AbstractExtensionAdder; -import com.powsybl.iidm.network.Network; - -/** - * @author Marcos de Miguel {@literal } - */ -class CgmesControlAreasAdderImpl extends AbstractExtensionAdder implements CgmesControlAreasAdder { - - CgmesControlAreasAdderImpl(Network extendable) { - super(extendable); - } - - @Override - protected CgmesControlAreas createExtension(Network extendable) { - return new CgmesControlAreasImpl(extendable); - } - -} diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdderImplProvider.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdderImplProvider.java deleted file mode 100644 index e5ef577432e..00000000000 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdderImplProvider.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * 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.extensions; - -import com.google.auto.service.AutoService; -import com.powsybl.commons.extensions.ExtensionAdderProvider; -import com.powsybl.iidm.network.Network; - -/** - * @author Marcos de Miguel {@literal } - */ -@AutoService(ExtensionAdderProvider.class) -public class CgmesControlAreasAdderImplProvider implements ExtensionAdderProvider { - - @Override - public String getImplementationName() { - return "Default"; - } - - @Override - public String getExtensionName() { - return CgmesControlAreas.NAME; - } - - @Override - public Class getAdderClass() { - return CgmesControlAreasAdderImpl.class; - } - - @Override - public CgmesControlAreasAdderImpl newAdder(Network extendable) { - return new CgmesControlAreasAdderImpl(extendable); - } - -} diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasImpl.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasImpl.java deleted file mode 100644 index 0074ec25ab8..00000000000 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasImpl.java +++ /dev/null @@ -1,54 +0,0 @@ -/** - * 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.extensions; - -import java.util.*; - -import com.powsybl.commons.PowsyblException; -import com.powsybl.commons.extensions.AbstractExtension; -import com.powsybl.iidm.network.Network; - -/** - * @author Marcos de Miguel {@literal } - */ -class CgmesControlAreasImpl extends AbstractExtension implements CgmesControlAreas { - - private final Map cgmesControlAreas = new HashMap<>(); - - CgmesControlAreasImpl(Network network) { - super(network); - } - - @Override - public CgmesControlAreaAdder newCgmesControlArea() { - return new CgmesControlAreaAdderImpl(this); - } - - @Override - public Collection getCgmesControlAreas() { - return Collections.unmodifiableCollection(cgmesControlAreas.values()); - } - - @Override - public CgmesControlArea getCgmesControlArea(String controlAreaId) { - return cgmesControlAreas.get(controlAreaId); - } - - @Override - public boolean containsCgmesControlAreaId(String controlAreaId) { - return cgmesControlAreas.containsKey(controlAreaId); - } - - void putCgmesControlArea(CgmesControlAreaImpl cgmesControlArea) { - Objects.requireNonNull(cgmesControlArea); - if (cgmesControlAreas.containsKey(cgmesControlArea.getId())) { - throw new PowsyblException(String.format("CGMES control area %s has already been added", cgmesControlArea.getId())); - } - cgmesControlAreas.put(cgmesControlArea.getId(), cgmesControlArea); - } -} diff --git a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasSerDe.java b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasSerDe.java deleted file mode 100644 index d88fd421fc9..00000000000 --- a/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasSerDe.java +++ /dev/null @@ -1,147 +0,0 @@ -/** - * 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.extensions; - -import com.google.auto.service.AutoService; -import com.powsybl.commons.PowsyblException; -import com.powsybl.commons.extensions.AbstractExtensionSerDe; -import com.powsybl.commons.extensions.ExtensionSerDe; -import com.powsybl.commons.io.TreeDataReader; -import com.powsybl.commons.io.TreeDataWriter; -import com.powsybl.commons.io.DeserializerContext; -import com.powsybl.commons.io.SerializerContext; -import com.powsybl.iidm.network.*; -import com.powsybl.iidm.serde.NetworkDeserializerContext; -import com.powsybl.iidm.serde.NetworkSerializerContext; -import com.powsybl.iidm.serde.TerminalRefSerDe; - -import java.util.Map; - -/** - * @author Marcos de Miguel {@literal } - */ -@AutoService(ExtensionSerDe.class) -public class CgmesControlAreasSerDe extends AbstractExtensionSerDe { - - private static final String CONTROL_AREA_ROOT_ELEMENT = "controlArea"; - private static final String CONTROL_AREA_ARRAY_ELEMENT = "controlAreas"; - public static final String TERMINAL_ROOT_ELEMENT = "terminal"; - public static final String TERMINAL_ARRAY_ELEMENT = "terminals"; - public static final String BOUNDARY_ROOT_ELEMENT = "boundary"; - public static final String BOUNDARY_ARRAY_ELEMENT = "boundaries"; - - public CgmesControlAreasSerDe() { - super("cgmesControlAreas", "network", CgmesControlAreas.class, "cgmesControlAreas.xsd", - "http://www.powsybl.org/schema/iidm/ext/cgmes_control_areas/1_0", "cca"); - } - - @Override - public Map getArrayNameToSingleNameMap() { - return Map.of(CONTROL_AREA_ARRAY_ELEMENT, CONTROL_AREA_ROOT_ELEMENT, - TERMINAL_ARRAY_ELEMENT, TERMINAL_ROOT_ELEMENT, - BOUNDARY_ARRAY_ELEMENT, BOUNDARY_ROOT_ELEMENT); - } - - @Override - public boolean isSerializable(CgmesControlAreas extension) { - return !extension.getCgmesControlAreas().isEmpty(); - } - - @Override - public void write(CgmesControlAreas extension, SerializerContext context) { - NetworkSerializerContext networkContext = (NetworkSerializerContext) context; - TreeDataWriter writer = networkContext.getWriter(); - writer.writeStartNodes(); - for (CgmesControlArea controlArea : extension.getCgmesControlAreas()) { - writer.writeStartNode(getNamespaceUri(), CONTROL_AREA_ROOT_ELEMENT); - writer.writeStringAttribute("id", controlArea.getId()); - writer.writeStringAttribute("name", controlArea.getName()); - writer.writeStringAttribute("energyIdentificationCodeEic", controlArea.getEnergyIdentificationCodeEIC()); - writer.writeDoubleAttribute("netInterchange", controlArea.getNetInterchange()); - writer.writeDoubleAttribute("pTolerance", controlArea.getPTolerance()); - - writer.writeStartNodes(); - for (Terminal terminal : controlArea.getTerminals()) { - TerminalRefSerDe.writeTerminalRef(terminal, networkContext, getNamespaceUri(), TERMINAL_ROOT_ELEMENT); - } - writer.writeEndNodes(); - - writer.writeStartNodes(); - for (Boundary boundary : controlArea.getBoundaries()) { - if (boundary.getDanglingLine() != null) { // TODO: delete this later, only for compatibility - writer.writeStartNode(getNamespaceUri(), BOUNDARY_ROOT_ELEMENT); - writer.writeStringAttribute("id", networkContext.getAnonymizer().anonymizeString(boundary.getDanglingLine().getId())); - - // TODO use TieLine Id and DanglingLine Id for reference instead of TieLine Id and Side - writer.writeEnumAttribute("side", getSide(boundary)); - writer.writeEndNode(); - } - } - writer.writeEndNodes(); - - writer.writeEndNode(); - } - writer.writeEndNodes(); - } - - private static TwoSides getSide(Boundary boundary) { - // a TieLine with two dangingLines inside - return boundary.getDanglingLine().getTieLine().map(tl -> { - if (tl.getDanglingLine1() == boundary.getDanglingLine()) { - return TwoSides.ONE; - } - return TwoSides.TWO; - }).orElse(null); - } - - @Override - public CgmesControlAreas read(Network extendable, DeserializerContext context) { - NetworkDeserializerContext networkContext = (NetworkDeserializerContext) context; - TreeDataReader reader = networkContext.getReader(); - extendable.newExtension(CgmesControlAreasAdder.class).add(); - CgmesControlAreas mapping = extendable.getExtension(CgmesControlAreas.class); - reader.readChildNodes(elementName -> { - if (elementName.equals(CONTROL_AREA_ROOT_ELEMENT)) { - CgmesControlArea cgmesControlArea = mapping.newCgmesControlArea() - .setId(reader.readStringAttribute("id")) - .setName(reader.readStringAttribute("name")) - .setEnergyIdentificationCodeEic(reader.readStringAttribute("energyIdentificationCodeEic")) - .setNetInterchange(reader.readDoubleAttribute("netInterchange")) - .setPTolerance(reader.readDoubleAttribute("pTolerance")) - .add(); - readBoundariesAndTerminals(networkContext, cgmesControlArea, extendable); - } else { - throw new PowsyblException("Unknown element name '" + elementName + "' in 'cgmesControlArea'"); - } - }); - return extendable.getExtension(CgmesControlAreas.class); - } - - private void readBoundariesAndTerminals(NetworkDeserializerContext networkContext, CgmesControlArea cgmesControlArea, Network network) { - TreeDataReader reader = networkContext.getReader(); - reader.readChildNodes(elementName -> { - switch (elementName) { - case BOUNDARY_ROOT_ELEMENT -> { - String id = networkContext.getAnonymizer().deanonymizeString(reader.readStringAttribute("id")); - TwoSides side = reader.readEnumAttribute("side", TwoSides.class); - Identifiable identifiable = network.getIdentifiable(id); - if (identifiable instanceof DanglingLine dl) { - cgmesControlArea.add(dl.getBoundary()); - } else if (identifiable instanceof TieLine tl) { - cgmesControlArea.add(tl.getDanglingLine(side).getBoundary()); - } else { - throw new PowsyblException("Unexpected Identifiable instance: " + identifiable.getClass()); - } - reader.readEndNode(); - } - case TERMINAL_ROOT_ELEMENT -> cgmesControlArea.add(TerminalRefSerDe.readTerminal(networkContext, network)); - default -> throw new PowsyblException("Unknown element name '" + elementName + "' in 'controlArea'"); - } - }); - } -} diff --git a/cgmes/cgmes-extensions/src/test/java/com/powsybl/cgmes/extensions/CgmesControlAreaTest.java b/cgmes/cgmes-extensions/src/test/java/com/powsybl/cgmes/extensions/CgmesControlAreaTest.java deleted file mode 100644 index 81ac08d7ed2..00000000000 --- a/cgmes/cgmes-extensions/src/test/java/com/powsybl/cgmes/extensions/CgmesControlAreaTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/** - * 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.extensions; - -import com.powsybl.commons.PowsyblException; -import com.powsybl.iidm.network.Network; -import com.powsybl.iidm.network.test.EurostagTutorialExample1Factory; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; -import static org.junit.jupiter.api.Assertions.assertEquals; - -/** - * @author Marcos de Miguel {@literal } - */ -class CgmesControlAreaTest { - - @Test - void test() { - Network network = EurostagTutorialExample1Factory.create(); - network.newExtension(CgmesControlAreasAdder.class).add(); - CgmesControlAreas extension = network.getExtension(CgmesControlAreas.class); - extension.newCgmesControlArea() - .setId("cgmesControlAreaId") - .setName("cgmesControlAreaName") - .setEnergyIdentificationCodeEic("energyIdentCodeEic") - .setNetInterchange(100.0) - .add() - .add(network.getLine("NHV1_NHV2_1").getTerminal1()); - - assertNotNull(extension); - assertTrue(extension.containsCgmesControlAreaId("cgmesControlAreaId")); - CgmesControlArea controlArea = extension.getCgmesControlArea("cgmesControlAreaId"); - assertNotNull(controlArea); - assertEquals("cgmesControlAreaId", controlArea.getId()); - assertEquals("cgmesControlAreaName", controlArea.getName()); - assertEquals("energyIdentCodeEic", controlArea.getEnergyIdentificationCodeEIC()); - assertEquals(100.0, controlArea.getNetInterchange(), 0.0); - assertEquals(1, controlArea.getTerminals().size()); - controlArea.getTerminals().forEach(t -> assertSame(network.getLine("NHV1_NHV2_1").getTerminal1(), t)); - } - - @Test - void invalid() { - Network network = EurostagTutorialExample1Factory.create(); - network.newExtension(CgmesControlAreasAdder.class).add(); - - try { - network.getExtension(CgmesControlAreas.class) - .newCgmesControlArea() - .setName("cgmesControlAreaName") - .setEnergyIdentificationCodeEic("energyIdentCodeEic") - .setNetInterchange(100.0) - .add() - .add(network.getLine("NHV1_NHV2_1").getTerminal1()); - fail(); - } catch (PowsyblException e) { - assertEquals("Undefined ID for CGMES control area", e.getMessage()); - } - } -} diff --git a/cgmes/cgmes-extensions/src/test/java/com/powsybl/cgmes/extensions/CgmesControlAreasSerDeTest.java b/cgmes/cgmes-extensions/src/test/java/com/powsybl/cgmes/extensions/CgmesControlAreasSerDeTest.java deleted file mode 100644 index fac05f9a391..00000000000 --- a/cgmes/cgmes-extensions/src/test/java/com/powsybl/cgmes/extensions/CgmesControlAreasSerDeTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/** - * 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.extensions; - -import com.powsybl.iidm.network.Network; -import com.powsybl.iidm.network.test.EurostagTutorialExample1Factory; -import org.junit.jupiter.api.Test; - -import java.io.IOException; -import java.time.ZonedDateTime; - -/** - * @author Marcos de Miguel {@literal } - */ -class CgmesControlAreasSerDeTest extends AbstractCgmesExtensionTest { - - @Test - void test() throws IOException { - Network network = EurostagTutorialExample1Factory.create(); - network.setCaseDate(ZonedDateTime.parse("2021-02-02T09:27:39.856+01:00")); - network.getVoltageLevel("VLGEN") - .getBusBreakerView() - .newBus() - .setId("NDL") - .add(); - network.getVoltageLevel("VLGEN") - .newDanglingLine() - .setP0(0.0) - .setQ0(0.0) - .setR(1.0) - .setX(1.0) - .setB(0.0) - .setG(0.0) - .setId("DL") - .setConnectableBus("NDL") - .setBus("NDL") - .add(); - network.newExtension(CgmesControlAreasAdder.class).add(); - network.getExtension(CgmesControlAreas.class).newCgmesControlArea() - .setId("cgmesControlAreaId") - .setName("cgmesControlAreaName") - .setEnergyIdentificationCodeEic("energyIdentCodeEic") - .setNetInterchange(100.0) - .add() - .add(network.getLine("NHV1_NHV2_1").getTerminal1()); - network.getExtension(CgmesControlAreas.class).getCgmesControlArea("cgmesControlAreaId").add(network.getDanglingLine("DL").getBoundary()); - - allFormatsRoundTripTest(network, "/eurostag_cgmes_control_area.xml"); - } -} diff --git a/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/CgmesNames.java b/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/CgmesNames.java index af5b71cdc0a..5d2f7a4d473 100644 --- a/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/CgmesNames.java +++ b/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/CgmesNames.java @@ -115,6 +115,7 @@ public final class CgmesNames { public static final String STATIC_VAR_COMPENSATOR = "StaticVarCompensator"; public static final String REGULATING_CONTROL = "RegulatingControl"; public static final String CONTROL_AREA = "ControlArea"; + public static final String TIE_FLOW = "TieFlow"; public static final String CONFORM_LOAD = "ConformLoad"; public static final String NONCONFORM_LOAD = "NonConformLoad"; public static final String ENERGY_CONSUMER = "EnergyConsumer"; @@ -145,6 +146,9 @@ public final class CgmesNames { public static final String ACTIVE_POWER_LIMIT = "ActivePowerLimit"; public static final String APPARENT_POWER_LIMIT = "ApparentPowerLimit"; + public static final String ENERGY_IDENT_CODE_EIC = "energyIdentCodeEic"; + public static final String P_TOLERANCE = "pTolerance"; + private CgmesNames() { } } diff --git a/cgmes/cgmes-model/src/main/resources/CIM16.sparql b/cgmes/cgmes-model/src/main/resources/CIM16.sparql index c137be21da9..2b0a3b1da26 100644 --- a/cgmes/cgmes-model/src/main/resources/CIM16.sparql +++ b/cgmes/cgmes-model/src/main/resources/CIM16.sparql @@ -137,7 +137,8 @@ GRAPH ?graphBDEQ { } GRAPH ?grapBDTP { ?ConnectivityNode cim:ConnectivityNode.TopologicalNode ?TopologicalNode . - ?TopologicalNode cim:IdentifiedObject.name ?topologicalNodeName + ?TopologicalNode cim:IdentifiedObject.name ?topologicalNodeName . + OPTIONAL { ?TopologicalNode cim:IdentifiedObject.description ?topologicalNodeDescription } } }