From 9bc3e5c2306930410e50d3e35328985d50f7e17f Mon Sep 17 00:00:00 2001 From: Luma Date: Fri, 20 Sep 2024 08:27:12 +0200 Subject: [PATCH 01/17] CGMES: remove extension for Control Areas, use iidm Area Signed-off-by: Luma --- .../powsybl/cgmes/conversion/Conversion.java | 29 ++-- .../cgmes/extensions/CgmesControlArea.java | 48 ------ .../extensions/CgmesControlAreaAdder.java | 30 ---- .../extensions/CgmesControlAreaAdderImpl.java | 67 -------- .../extensions/CgmesControlAreaImpl.java | 94 ----------- .../cgmes/extensions/CgmesControlAreas.java | 41 ----- .../extensions/CgmesControlAreasAdder.java | 22 --- .../CgmesControlAreasAdderImpl.java | 27 ---- .../CgmesControlAreasAdderImplProvider.java | 40 ----- .../extensions/CgmesControlAreasImpl.java | 54 ------- .../extensions/CgmesControlAreasSerDe.java | 147 ------------------ 11 files changed, 14 insertions(+), 585 deletions(-) delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlArea.java delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdder.java delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdderImpl.java delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaImpl.java delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreas.java delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdder.java delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdderImpl.java delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdderImplProvider.java delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasImpl.java delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasSerDe.java 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 869455c855a..bbd5a0f151b 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 @@ -228,11 +228,8 @@ public Network convert(ReportNode reportNode) { voltageAngles(nodes, context); if (config.importControlAreas()) { - 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(); + cgmes.controlAreas().forEach(ca -> createControlArea(context, ca)); + cgmes.tieFlows().forEach(tf -> addTieFlow(context, tf)); } // set all regulating controls @@ -351,31 +348,33 @@ private static void completeVoltagesAndAngles(Network network) { network.getTieLines().forEach(tieLine -> AbstractConductingEquipmentConversion.calculateVoltageAndAngleInBoundaryBus(tieLine.getDanglingLine1(), tieLine.getDanglingLine2())); } - private static void createControlArea(CgmesControlAreas cgmesControlAreas, PropertyBag ca) { + private static void createControlArea(Context context, PropertyBag ca) { String controlAreaId = ca.getId("ControlArea"); - cgmesControlAreas.newCgmesControlArea() + Area area = context.network().newArea() .setId(controlAreaId) .setName(ca.getLocal("name")) - .setEnergyIdentificationCodeEic(ca.getLocal("energyIdentCodeEic")) - .setNetInterchange(ca.asDouble("netInterchange", Double.NaN)) - .setPTolerance(ca.asDouble("pTolerance", Double.NaN)) + .setInterchangeTarget(ca.asDouble("netInterchange", Double.NaN)) .add(); + if (ca.containsKey("pTolerance")) { + area.setProperty("tolerance", ca.get("pTolerance")); + } + area.addAlias("energyIdentificationCodeEic"); } - private static void addTieFlow(Context context, CgmesControlAreas cgmesControlAreas, PropertyBag tf) { + private static void addTieFlow(Context context, PropertyBag tf) { String controlAreaId = tf.getId("ControlArea"); - CgmesControlArea cgmesControlArea = cgmesControlAreas.getCgmesControlArea(controlAreaId); - if (cgmesControlArea == null) { + 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", tf.getId("TieFlow"))); return; } String terminalId = tf.getId("terminal"); Boundary boundary = context.terminalMapping().findBoundary(terminalId, context.cgmes()); if (boundary != null) { - cgmesControlArea.add(boundary); + area.newAreaBoundary().setBoundary(boundary).add(); return; } - RegulatingTerminalMapper.mapForTieFlow(terminalId, context).ifPresent(cgmesControlArea::add); + RegulatingTerminalMapper.mapForTieFlow(terminalId, context).ifPresent(t -> area.newAreaBoundary().setTerminal(t).add()); } private void convert( 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'"); - } - }); - } -} From f164ae50ff08a7eeeb2689013d5870f1673b2644 Mon Sep 17 00:00:00 2001 From: Luma Date: Fri, 20 Sep 2024 08:35:03 +0200 Subject: [PATCH 02/17] add energy identification code EIC as alias Signed-off-by: Luma --- .../main/java/com/powsybl/cgmes/conversion/Conversion.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 bbd5a0f151b..d3c4254a9f4 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 @@ -358,7 +358,9 @@ private static void createControlArea(Context context, PropertyBag ca) { if (ca.containsKey("pTolerance")) { area.setProperty("tolerance", ca.get("pTolerance")); } - area.addAlias("energyIdentificationCodeEic"); + if (ca.containsKey("energyIdentCodeEic")) { + area.addAlias(ca.get("energyIdentCodeEic"), "energyIdentificationCodeEic"); + } } private static void addTieFlow(Context context, PropertyBag tf) { From 883136389e459e883e8f783c71374a2e31acbe10 Mon Sep 17 00:00:00 2001 From: Luma Date: Fri, 20 Sep 2024 17:08:12 +0200 Subject: [PATCH 03/17] do not delete existing cgmes extension Signed-off-by: Luma --- .../conversion/export/CgmesExportContext.java | 1 + .../cgmes/extensions/CgmesControlArea.java | 48 ++++++ .../extensions/CgmesControlAreaAdder.java | 30 ++++ .../extensions/CgmesControlAreaAdderImpl.java | 67 ++++++++ .../extensions/CgmesControlAreaImpl.java | 94 +++++++++++ .../cgmes/extensions/CgmesControlAreas.java | 41 +++++ .../extensions/CgmesControlAreasAdder.java | 22 +++ .../CgmesControlAreasAdderImpl.java | 27 ++++ .../CgmesControlAreasAdderImplProvider.java | 40 +++++ .../extensions/CgmesControlAreasImpl.java | 54 +++++++ .../extensions/CgmesControlAreasSerDe.java | 147 ++++++++++++++++++ 11 files changed, 571 insertions(+) create mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlArea.java create mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdder.java create mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdderImpl.java create mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaImpl.java create mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreas.java create mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdder.java create mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdderImpl.java create mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdderImplProvider.java create mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasImpl.java create mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasSerDe.java 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 a40a2338ad1..d9ffeb221e8 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 @@ -528,6 +528,7 @@ private void addIidmMappingsEquivalentInjection(Network network) { } private void addIidmMappingsControlArea(Network network) { + // FIXME(Luma) remove this use of CgmesControlAreas CgmesControlAreas cgmesControlAreas = network.getExtension(CgmesControlAreas.class); if (cgmesControlAreas == null) { network.newExtension(CgmesControlAreasAdder.class).add(); 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 new file mode 100644 index 00000000000..c0bf843e29c --- /dev/null +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlArea.java @@ -0,0 +1,48 @@ +/** + * 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 new file mode 100644 index 00000000000..224cbd2b023 --- /dev/null +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdder.java @@ -0,0 +1,30 @@ +/** + * 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 new file mode 100644 index 00000000000..6156b8b97e9 --- /dev/null +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdderImpl.java @@ -0,0 +1,67 @@ +/** + * 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 new file mode 100644 index 00000000000..427bae1c5a9 --- /dev/null +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaImpl.java @@ -0,0 +1,94 @@ +/** + * 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 new file mode 100644 index 00000000000..b3095e31bfc --- /dev/null +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreas.java @@ -0,0 +1,41 @@ +/** + * 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 new file mode 100644 index 00000000000..151f69b8c14 --- /dev/null +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdder.java @@ -0,0 +1,22 @@ +/** + * 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 new file mode 100644 index 00000000000..efdfdb67704 --- /dev/null +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdderImpl.java @@ -0,0 +1,27 @@ +/** + * 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 new file mode 100644 index 00000000000..e5ef577432e --- /dev/null +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdderImplProvider.java @@ -0,0 +1,40 @@ +/** + * 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 new file mode 100644 index 00000000000..0074ec25ab8 --- /dev/null +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasImpl.java @@ -0,0 +1,54 @@ +/** + * 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 new file mode 100644 index 00000000000..d88fd421fc9 --- /dev/null +++ b/cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasSerDe.java @@ -0,0 +1,147 @@ +/** + * 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'"); + } + }); + } +} From 38c02c987d204efb115e665f1550879447ee629e Mon Sep 17 00:00:00 2001 From: Luma Date: Fri, 20 Sep 2024 17:24:53 +0200 Subject: [PATCH 04/17] copy the cgmes control area type to the iidm area type Signed-off-by: Luma --- .../src/main/java/com/powsybl/cgmes/conversion/Conversion.java | 2 ++ 1 file changed, 2 insertions(+) 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 d3c4254a9f4..83d10f38d00 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 @@ -350,7 +350,9 @@ private static void completeVoltagesAndAngles(Network network) { private static void createControlArea(Context context, PropertyBag ca) { String controlAreaId = ca.getId("ControlArea"); + String type = ca.getLocal("controlAreaType"); Area area = context.network().newArea() + .setAreaType(type) // Copy the type defined by CGMES .setId(controlAreaId) .setName(ca.getLocal("name")) .setInterchangeTarget(ca.asDouble("netInterchange", Double.NaN)) From df99a96ad742b5ef48516532785395be54377d3c Mon Sep 17 00:00:00 2001 From: Luma Date: Wed, 25 Sep 2024 12:00:55 +0200 Subject: [PATCH 05/17] use iidm area for cgmes export of control areas, adjust unit tests Signed-off-by: Luma --- .../powsybl/cgmes/conversion/Conversion.java | 13 ++- .../conversion/export/CgmesExportContext.java | 24 +++--- .../conversion/export/EquipmentExport.java | 52 ++++++------ .../export/SteadyStateHypothesisExport.java | 25 ++++-- .../conversion/export/elements/TieFlowEq.java | 21 +++-- .../test/TieFlowConversionTest.java | 85 +++++++++---------- ...gmesConformity1ModifiedConversionTest.java | 13 ++- .../test/export/EquipmentExportTest.java | 9 +- .../test/export/ExportXmlCompare.java | 2 +- .../SteadyStateHypothesisExportTest.java | 26 +++--- 10 files changed, 144 insertions(+), 126 deletions(-) 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 83d10f38d00..3769fc107f3 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 @@ -358,7 +358,7 @@ private static void createControlArea(Context context, PropertyBag ca) { .setInterchangeTarget(ca.asDouble("netInterchange", Double.NaN)) .add(); if (ca.containsKey("pTolerance")) { - area.setProperty("tolerance", ca.get("pTolerance")); + area.setProperty("pTolerance", ca.get("pTolerance")); } if (ca.containsKey("energyIdentCodeEic")) { area.addAlias(ca.get("energyIdentCodeEic"), "energyIdentificationCodeEic"); @@ -375,10 +375,17 @@ private static void addTieFlow(Context context, PropertyBag tf) { String terminalId = tf.getId("terminal"); Boundary boundary = context.terminalMapping().findBoundary(terminalId, context.cgmes()); if (boundary != null) { - area.newAreaBoundary().setBoundary(boundary).add(); + area.newAreaBoundary() + .setAc(true) + .setBoundary(boundary) + .add(); return; } - RegulatingTerminalMapper.mapForTieFlow(terminalId, context).ifPresent(t -> area.newAreaBoundary().setTerminal(t).add()); + RegulatingTerminalMapper.mapForTieFlow(terminalId, context) + .ifPresent(t -> area.newAreaBoundary() + .setAc(true) + .setTerminal(t) + .add()); } private void convert( 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 d9ffeb221e8..d55d086e398 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 @@ -528,20 +528,22 @@ private void addIidmMappingsEquivalentInjection(Network network) { } private void addIidmMappingsControlArea(Network network) { - // FIXME(Luma) remove this use of CgmesControlAreas - 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) + // If no control area exists, create one for the whole network, containing the dangling lines as boundaries, + // but only if the network does not contain subnetworks + // FIXME(LUMA) check the use of the literal for CGMES "ControlAreaTypeKind.Interchange" and "energyIdentificationCodeEic" + long numControlAreas = network.getAreaStream().filter(a -> a.getAreaType().equals("ControlAreaTypeKind.Interchange")).count(); + long numSubnetworks = network.getSubnetworks().size(); + if (numControlAreas == 0 && numSubnetworks == 0) { + String controlAreaId = namingStrategy.getCgmesId(refTyped(network), CONTROL_AREA); + Area area = network.newArea() + .setAreaType("ControlAreaTypeKind.Interchange") + .setId(controlAreaId) .setName("Network") - .setEnergyIdentificationCodeEic("Network--1") .add(); - CgmesControlArea cgmesControlArea = cgmesControlAreas.getCgmesControlArea(cgmesControlAreaId); + // FIXME(Luma) unknown EIC, there is no good default value for it for (DanglingLine danglingLine : CgmesExportUtil.getBoundaryDanglingLines(network)) { - cgmesControlArea.add(danglingLine.getTerminal()); + // Our exchange should be referred the boundary + area.newAreaBoundary().setAc(true).setBoundary(danglingLine.getBoundary()).add(); } } } 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 a69c4f5fccc..1fc735bdd90 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 @@ -1354,38 +1354,42 @@ 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); + for (Area area : network.getAreas()) { + if (area.getAreaType().equals("ControlAreaTypeKind.Interchange")) { + writeControlArea(area, energyAreaId, cimNamespace, euNamespace, writer, context, network); + } } } - private static void writeControlArea(CgmesControlArea cgmesControlArea, String energyAreaId, String cimNamespace, String euNamespace, + private static void writeControlArea(Area controlArea, String energyAreaId, String cimNamespace, String euNamespace, XMLStreamWriter writer, CgmesExportContext context, Network network) 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); + String controlAreaCgmesId = context.getNamingStrategy().getCgmesId(controlArea.getId()); + String energyIdentificationCodeEIC = controlArea.getProperty("energyIdentificationCodeEIC"); + ControlAreaEq.write(controlAreaCgmesId, controlArea.getNameOrId(), energyIdentificationCodeEIC, energyAreaId, cimNamespace, euNamespace, writer, context); + for (AreaBoundary areaBoundary : controlArea.getAreaBoundaries()) { + areaBoundary.getTerminal().ifPresent(terminal -> { + 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.error("Unsupported tie flow at TieLine boundary {}", dl.getId()); + LOG.warn("Ignored tie flow at {}: should be a dangling line to retrieve boundary terminal", terminal.getConnectable().getId()); } - } else { - LOG.warn("Ignored tie flow at {}: should be a dangling line to retrieve boundary terminal", terminal.getConnectable().getId()); - } - } - for (Boundary boundary : cgmesControlArea.getBoundaries()) { - String terminalId = getTieFlowBoundaryTerminal(boundary, context, network); - if (terminalId != null) { - String tieFlowId = context.getNamingStrategy().getCgmesId(ref(terminalId), TIE_FLOW); - TieFlowEq.write(tieFlowId, controlAreaCgmesId, terminalId, cimNamespace, writer, context); - } + }); + areaBoundary.getBoundary().ifPresent(boundary -> { + String terminalId = getTieFlowBoundaryTerminal(boundary, context, network); + if (terminalId != null) { + String tieFlowId = context.getNamingStrategy().getCgmesId(ref(terminalId), TIE_FLOW); + TieFlowEq.write(tieFlowId, controlAreaCgmesId, terminalId, cimNamespace, writer, context); + } + }); } } 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 f0aa90ddd5e..31e7fae3ce5 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; @@ -843,20 +841,29 @@ 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(); + double pTolerance; + if (controlArea.hasProperty("pTolerance")) { + pTolerance = Double.parseDouble(controlArea.getProperty("pTolerance")); + } else { + // FIXME(Luma) check if QoCDC says something about this tolerance + pTolerance = 0.1 * netInterchange; + } writer.writeStartElement(cimNamespace, "ControlArea.pTolerance"); - writer.writeCharacters(CgmesExportUtil.format(area.getPTolerance())); + writer.writeCharacters(CgmesExportUtil.format(pTolerance)); writer.writeEndElement(); writer.writeEndElement(); } 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..a2d25e58cb3 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 @@ -11,8 +11,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.io.IOException; - +import com.powsybl.iidm.network.Area; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,8 +19,6 @@ 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; @@ -33,63 +30,55 @@ 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)); } private Network networkModel(GridModelReference testGridModel, Conversion.Config config) { @@ -97,24 +86,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 ce19719bc92..45c1ffbfa69 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,7 +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.*; @@ -327,12 +326,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("energyIdentificationCodeEic").get()); + assertEquals(-205.90011555672567, area.getInterchangeTarget().getAsDouble(), 0.0); + assertEquals(5, area.getAreaBoundaryStream().count()); } @Test 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 1c74cb09b75..921a8ec9d99 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 @@ -67,6 +67,7 @@ class EquipmentExportTest extends AbstractSerDeTest { private Properties importParams; + @Override @BeforeEach public void setUp() throws IOException { super.setUp(); @@ -172,13 +173,13 @@ void microGridBaseCaseAssembledSwitchAtBoundary() throws XMLStreamException, IOE // 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"); + Area actualControlArea = actual.getArea("controlAreaId"); boolean tieFlowsAtTieLinesAreSupported = false; if (tieFlowsAtTieLinesAreSupported) { - assertEquals(1, actualCgmesControlArea.getBoundaries().size()); - assertEquals("7f43f508-2496-4b64-9146-0a40406cbe49", actualCgmesControlArea.getBoundaries().iterator().next().getDanglingLine().getId()); + assertEquals(1, actualControlArea.getAreaBoundaryStream().count()); + assertEquals("7f43f508-2496-4b64-9146-0a40406cbe49", actualControlArea.getAreaBoundaries().iterator().next().getBoundary().get().getDanglingLine().getId()); } else { - assertEquals(0, actualCgmesControlArea.getBoundaries().size()); + assertNull(actualControlArea); } } 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 621962f15c5..707d12095a1 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 @@ -450,7 +450,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/SteadyStateHypothesisExportTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/SteadyStateHypothesisExportTest.java index bf5b4c2c7dd..f1cc0f26fc7 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"); From 9387a350cca95473dd81801f21ddb83990ccaf84 Mon Sep 17 00:00:00 2001 From: Luma Date: Thu, 26 Sep 2024 09:00:52 +0200 Subject: [PATCH 06/17] always set pTolerance; adjust unit tests Signed-off-by: Luma --- .../java/com/powsybl/cgmes/conversion/Conversion.java | 4 +++- .../conversion/test/export/EquipmentExportTest.java | 6 ++++++ .../conversion/test/export/StateVariablesExportTest.java | 9 ++++++++- 3 files changed, 17 insertions(+), 2 deletions(-) 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 3769fc107f3..40ba7c57f58 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 @@ -357,9 +357,11 @@ private static void createControlArea(Context context, PropertyBag ca) { .setName(ca.getLocal("name")) .setInterchangeTarget(ca.asDouble("netInterchange", Double.NaN)) .add(); + String pTolerance = "0"; if (ca.containsKey("pTolerance")) { - area.setProperty("pTolerance", ca.get("pTolerance")); + pTolerance = ca.get("pTolerance"); } + area.setProperty("pTolerance", pTolerance); if (ca.containsKey("energyIdentCodeEic")) { area.addAlias(ca.get("energyIdentCodeEic"), "energyIdentificationCodeEic"); } 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 921a8ec9d99..7c12baece21 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 @@ -576,6 +576,9 @@ 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)); + // 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 (reimport does not consider the SSH file); expected.getGenerators().forEach(expectedGenerator -> { Generator actualGenerator = actual.getGenerator(expectedGenerator.getId()); @@ -1813,6 +1816,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/StateVariablesExportTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/StateVariablesExportTest.java index d4dfeacc6ef..4e475548118 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); From 69026acca5fa26023fc1ef7f000c1bc356513400 Mon Sep 17 00:00:00 2001 From: Luma Date: Thu, 24 Oct 2024 10:55:45 +0200 Subject: [PATCH 07/17] EIC code and target for default control area created for export Signed-off-by: Luma --- .../com/powsybl/cgmes/conversion/Conversion.java | 14 +++++++------- .../conversion/export/CgmesExportContext.java | 8 ++++++-- .../cgmes/conversion/export/EquipmentExport.java | 4 ++-- .../conversion/export/elements/ControlAreaEq.java | 4 ++-- .../CgmesConformity1ModifiedConversionTest.java | 2 +- .../java/com/powsybl/cgmes/model/CgmesNames.java | 3 +++ 6 files changed, 21 insertions(+), 14 deletions(-) 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 6384d930e08..9fa5af3ad2d 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 @@ -399,7 +399,7 @@ private static void completeVoltagesAndAngles(Network network) { } private static void createControlArea(Context context, PropertyBag ca) { - String controlAreaId = ca.getId("ControlArea"); + String controlAreaId = ca.getId(CgmesNames.CONTROL_AREA); String type = ca.getLocal("controlAreaType"); Area area = context.network().newArea() .setAreaType(type) // Copy the type defined by CGMES @@ -408,17 +408,17 @@ private static void createControlArea(Context context, PropertyBag ca) { .setInterchangeTarget(ca.asDouble("netInterchange", Double.NaN)) .add(); String pTolerance = "0"; - if (ca.containsKey("pTolerance")) { - pTolerance = ca.get("pTolerance"); + if (ca.containsKey(CgmesNames.P_TOLERANCE)) { + pTolerance = ca.get(CgmesNames.P_TOLERANCE); } - area.setProperty("pTolerance", pTolerance); - if (ca.containsKey("energyIdentCodeEic")) { - area.addAlias(ca.get("energyIdentCodeEic"), "energyIdentificationCodeEic"); + area.setProperty(CgmesNames.P_TOLERANCE, pTolerance); + if (ca.containsKey(CgmesNames.ENERGY_IDENT_CODE_EIC)) { + area.addAlias(ca.get(CgmesNames.ENERGY_IDENT_CODE_EIC), CgmesNames.ENERGY_IDENT_CODE_EIC); } } private static void addTieFlow(Context context, PropertyBag tf) { - String controlAreaId = tf.getId("ControlArea"); + String controlAreaId = tf.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", tf.getId("TieFlow"))); 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 ab98f062d78..559bf9ae499 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 @@ -532,7 +532,6 @@ private void addIidmMappingsEquivalentInjection(Network network) { private void addIidmMappingsControlArea(Network network) { // If no control area exists, create one for the whole network, containing the dangling lines as boundaries, // but only if the network does not contain subnetworks - // FIXME(LUMA) check the use of the literal for CGMES "ControlAreaTypeKind.Interchange" and "energyIdentificationCodeEic" long numControlAreas = network.getAreaStream().filter(a -> a.getAreaType().equals("ControlAreaTypeKind.Interchange")).count(); long numSubnetworks = network.getSubnetworks().size(); if (numControlAreas == 0 && numSubnetworks == 0) { @@ -542,11 +541,16 @@ private void addIidmMappingsControlArea(Network network) { .setId(controlAreaId) .setName("Network") .add(); - // FIXME(Luma) unknown EIC, there is no good default value for it + 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; for (DanglingLine danglingLine : CgmesExportUtil.getBoundaryDanglingLines(network)) { // Our exchange should be referred the boundary area.newAreaBoundary().setAc(true).setBoundary(danglingLine.getBoundary()).add(); + currentInterchange += danglingLine.getBoundary().getP(); } + area.setInterchangeTarget(currentInterchange); } } 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 3c088435e91..d46de87df3c 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 @@ -1377,8 +1377,8 @@ private static void writeControlArea(Area controlArea, String energyAreaId, Stri // 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(controlArea.getId()); - String energyIdentificationCodeEIC = controlArea.getProperty("energyIdentificationCodeEIC"); - ControlAreaEq.write(controlAreaCgmesId, controlArea.getNameOrId(), energyIdentificationCodeEIC, energyAreaId, cimNamespace, euNamespace, writer, context); + 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()) { areaBoundary.getTerminal().ifPresent(terminal -> { Connectable c = terminal.getConnectable(); 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/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 45c1ffbfa69..2e5736aad8d 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 @@ -329,7 +329,7 @@ void microBETieFlow() { Area area = network.getArea("BECONTROLAREA"); assertEquals("ControlAreaTypeKind.Interchange", area.getAreaType()); assertEquals("BE", area.getNameOrId()); - assertEquals("10BE------1", area.getAliasFromType("energyIdentificationCodeEic").get()); + assertEquals("10BE------1", area.getAliasFromType(CgmesNames.ENERGY_IDENT_CODE_EIC).get()); assertEquals(-205.90011555672567, area.getInterchangeTarget().getAsDouble(), 0.0); assertEquals(5, area.getAreaBoundaryStream().count()); } 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..1542de6234e 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 @@ -145,6 +145,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() { } } From 20cd5e5399fb28079bacba6a5a4a6d52a3cc7eac Mon Sep 17 00:00:00 2001 From: Luma Date: Thu, 24 Oct 2024 12:30:20 +0200 Subject: [PATCH 08/17] p tolerance positive, by default 1% of net interchange Signed-off-by: Luma --- .../cgmes/conversion/export/SteadyStateHypothesisExport.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 31e7fae3ce5..0462b7a66be 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 @@ -859,8 +859,7 @@ private static void writeControlArea(Area controlArea, String cimNamespace, XMLS if (controlArea.hasProperty("pTolerance")) { pTolerance = Double.parseDouble(controlArea.getProperty("pTolerance")); } else { - // FIXME(Luma) check if QoCDC says something about this tolerance - pTolerance = 0.1 * netInterchange; + pTolerance = Math.abs(0.01 * netInterchange); } writer.writeStartElement(cimNamespace, "ControlArea.pTolerance"); writer.writeCharacters(CgmesExportUtil.format(pTolerance)); From ee15e39a83dced58af5d6448c69ab5de3710b1d1 Mon Sep 17 00:00:00 2001 From: Luma Date: Fri, 25 Oct 2024 13:46:50 +0200 Subject: [PATCH 09/17] refactor writing of tie flows in equipment export Signed-off-by: Luma --- .../conversion/export/EquipmentExport.java | 48 +++++++++++-------- .../test/export/EquipmentExportTest.java | 2 +- 2 files changed, 28 insertions(+), 22 deletions(-) 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 d46de87df3c..678b08ef534 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 @@ -1380,27 +1380,33 @@ private static void writeControlArea(Area controlArea, String energyAreaId, Stri 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()) { - areaBoundary.getTerminal().ifPresent(terminal -> { - 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()); - } - }); - areaBoundary.getBoundary().ifPresent(boundary -> { - String terminalId = getTieFlowBoundaryTerminal(boundary, context, network); - if (terminalId != null) { - String tieFlowId = context.getNamingStrategy().getCgmesId(ref(terminalId), TIE_FLOW); - TieFlowEq.write(tieFlowId, controlAreaCgmesId, terminalId, cimNamespace, writer, context); - } - }); + TieFlow.from(areaBoundary, context, network).ifPresent(tieFlow -> + TieFlowEq.write(tieFlow.id(), controlAreaCgmesId, tieFlow.terminalId(), cimNamespace, writer, context) + ); + } + } + + private record TieFlow(String id, String terminalId) { + static Optional from(AreaBoundary areaBoundary, CgmesExportContext context, Network network) { + return areaBoundary.getTerminal().map(terminal -> from(terminal, context)) + .orElse(areaBoundary.getBoundary().flatMap(boundary -> from(boundary, context, network))); + } + + 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, Network network) { + String terminalId = getTieFlowBoundaryTerminal(boundary, context, network); + if (terminalId != null) { + return Optional.of(new TieFlow( + context.getNamingStrategy().getCgmesId(ref(terminalId), TIE_FLOW), + terminalId)); + } else { + return Optional.empty(); + } } } 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 fc05f0eef2f..a25b5231203 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 @@ -1691,7 +1691,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"); From 0af40d189cbf8aa2901fc6f51b3a15a95b453540 Mon Sep 17 00:00:00 2001 From: Luma Date: Mon, 4 Nov 2024 13:17:29 +0100 Subject: [PATCH 10/17] determine if a boundary should be ac or dc based on the reference data Signed-off-by: Luma --- .../conversion/export/CgmesExportContext.java | 53 +++++++++++++------ .../export/ReferenceDataProvider.java | 13 +++++ .../src/main/resources/CIM16.sparql | 3 +- 3 files changed, 53 insertions(+), 16 deletions(-) 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 559bf9ae499..2ed20914a18 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 @@ -535,23 +535,46 @@ private void addIidmMappingsControlArea(Network network) { long numControlAreas = network.getAreaStream().filter(a -> a.getAreaType().equals("ControlAreaTypeKind.Interchange")).count(); long numSubnetworks = network.getSubnetworks().size(); if (numControlAreas == 0 && numSubnetworks == 0) { - String controlAreaId = namingStrategy.getCgmesId(refTyped(network), CONTROL_AREA); - Area area = network.newArea() - .setAreaType("ControlAreaTypeKind.Interchange") - .setId(controlAreaId) - .setName("Network") + createDefaultControlArea(network); + } + } + + private void createDefaultControlArea(Network network) { + String controlAreaId = namingStrategy.getCgmesId(refTyped(network), CONTROL_AREA); + Area area = network.newArea() + .setAreaType("ControlAreaTypeKind.Interchange") + .setId(controlAreaId) + .setName("Network") + .add(); + 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(); + for (DanglingLine danglingLine : CgmesExportUtil.getBoundaryDanglingLines(network)) { + // Our exchange should be referred the boundary + area.newAreaBoundary() + .setAc(isAcBoundary(danglingLine, boundaryDcNodes)) + .setBoundary(danglingLine.getBoundary()) .add(); - 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; - for (DanglingLine danglingLine : CgmesExportUtil.getBoundaryDanglingLines(network)) { - // Our exchange should be referred the boundary - area.newAreaBoundary().setAc(true).setBoundary(danglingLine.getBoundary()).add(); - currentInterchange += danglingLine.getBoundary().getP(); - } - area.setInterchangeTarget(currentInterchange); + currentInterchange += danglingLine.getBoundary().getP(); } + area.setInterchangeTarget(currentInterchange); + } + + private Set getBoundaryDcNodes() { + return referenceDataProvider.getBoundaryNodes().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; } public int getCimVersion() { 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-model/src/main/resources/CIM16.sparql b/cgmes/cgmes-model/src/main/resources/CIM16.sparql index 2ac8ae113eb..12e41bc132b 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 } } } From f51309fd909750ff2db438df578c07f89ede29e8 Mon Sep 17 00:00:00 2001 From: Luma Date: Thu, 14 Nov 2024 14:08:40 +0100 Subject: [PATCH 11/17] move control area conversion to specific class Signed-off-by: Luma --- .../powsybl/cgmes/conversion/Conversion.java | 50 ++--------------- .../conversion/RegulatingTerminalMapper.java | 4 +- .../elements/ControlAreaConversion.java | 48 +++++++++++++++++ .../elements/TieFlowConversion.java | 54 +++++++++++++++++++ .../conversion/export/CgmesExportContext.java | 17 ++++-- ...icroGridBaseCaseBE-invalid-voltage-bus.txt | 1 + .../microGridBaseCaseBE-target-deadband.txt | 1 + .../functional-logs/microGridBaseCaseBE.txt | 1 + .../functional-logs/miniGridNodeBreaker.txt | 1 + .../com/powsybl/cgmes/model/CgmesNames.java | 1 + 10 files changed, 126 insertions(+), 52 deletions(-) create mode 100644 cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/ControlAreaConversion.java create mode 100644 cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/TieFlowConversion.java 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 9fa5af3ad2d..60cf6a94fe1 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,10 +231,8 @@ public Network convert(ReportNode reportNode) { } if (config.importControlAreas()) { - context.pushReportNode(CgmesReports.convertingElementTypeReport(reportNode, CgmesNames.CONTROL_AREA)); - cgmes.controlAreas().forEach(ca -> createControlArea(context, ca)); - cgmes.tieFlows().forEach(tf -> addTieFlow(context, tf)); - context.popReportNode(); + convert(cgmes.controlAreas(), CgmesNames.CONTROL_AREA, context); + convert(cgmes.tieFlows(), CgmesNames.TIE_FLOW, context); } context.pushReportNode(CgmesReports.convertingElementTypeReport(reportNode, CgmesNames.REGULATING_CONTROL)); @@ -398,48 +396,6 @@ private static void completeVoltagesAndAngles(Network network) { network.getTieLines().forEach(tieLine -> AbstractConductingEquipmentConversion.calculateVoltageAndAngleInBoundaryBus(tieLine.getDanglingLine1(), tieLine.getDanglingLine2())); } - private static void createControlArea(Context context, PropertyBag ca) { - String controlAreaId = ca.getId(CgmesNames.CONTROL_AREA); - String type = ca.getLocal("controlAreaType"); - Area area = context.network().newArea() - .setAreaType(type) // Copy the type defined by CGMES - .setId(controlAreaId) - .setName(ca.getLocal("name")) - .setInterchangeTarget(ca.asDouble("netInterchange", Double.NaN)) - .add(); - String pTolerance = "0"; - if (ca.containsKey(CgmesNames.P_TOLERANCE)) { - pTolerance = ca.get(CgmesNames.P_TOLERANCE); - } - area.setProperty(CgmesNames.P_TOLERANCE, pTolerance); - if (ca.containsKey(CgmesNames.ENERGY_IDENT_CODE_EIC)) { - area.addAlias(ca.get(CgmesNames.ENERGY_IDENT_CODE_EIC), CgmesNames.ENERGY_IDENT_CODE_EIC); - } - } - - private static void addTieFlow(Context context, PropertyBag tf) { - String controlAreaId = tf.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", tf.getId("TieFlow"))); - return; - } - String terminalId = tf.getId("terminal"); - Boundary boundary = context.terminalMapping().findBoundary(terminalId, context.cgmes()); - if (boundary != null) { - area.newAreaBoundary() - .setAc(true) - .setBoundary(boundary) - .add(); - return; - } - RegulatingTerminalMapper.mapForTieFlow(terminalId, context) - .ifPresent(t -> area.newAreaBoundary() - .setAc(true) - .setTerminal(t) - .add()); - } - private void convert(PropertyBags elements, String elementType, Context context) { context.pushReportNode(CgmesReports.convertingElementTypeReport(context.getReportNode(), elementType)); for (PropertyBag element : elements) { @@ -464,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..db9518fe5ed --- /dev/null +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/ControlAreaConversion.java @@ -0,0 +1,48 @@ +/** + 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(); + String pTolerance = "0"; + if (p.containsKey(CgmesNames.P_TOLERANCE)) { + 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..1d07cf7e999 --- /dev/null +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/TieFlowConversion.java @@ -0,0 +1,54 @@ +/** + 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.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"); + Boundary boundary = context.terminalMapping().findBoundary(terminalId, context.cgmes()); + if (boundary != null) { + area.newAreaBoundary() + .setAc(true) + .setBoundary(boundary) + .add(); + return; + } + RegulatingTerminalMapper.mapForTieFlow(terminalId, context) + .ifPresent(t -> area.newAreaBoundary() + .setAc(true) + .setTerminal(t) + .add()); + } +} 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 2ed20914a18..4a136d92542 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 @@ -19,6 +19,7 @@ import com.powsybl.commons.report.ReportNode; import com.powsybl.iidm.network.*; import com.powsybl.iidm.network.Identifiable; +import com.powsybl.triplestore.api.PropertyBags; import org.apache.commons.lang3.tuple.Pair; import java.net.URLEncoder; @@ -563,10 +564,18 @@ private void createDefaultControlArea(Network network) { } private Set getBoundaryDcNodes() { - return referenceDataProvider.getBoundaryNodes().stream() - .filter(node -> node.containsKey("topologicalNodeDescription") && node.get("topologicalNodeDescription").startsWith("HVDC")) - .map(node -> node.getId(CgmesNames.TOPOLOGICAL_NODE)) - .collect(Collectors.toSet()); + if (referenceDataProvider == null) { + return Collections.emptySet(); + } + PropertyBags boundaryNodes = referenceDataProvider.getBoundaryNodes(); + if (boundaryNodes == null) { + return Collections.emptySet(); + } else { + 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) { 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-model/src/main/java/com/powsybl/cgmes/model/CgmesNames.java b/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/CgmesNames.java index 1542de6234e..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"; From 53cb10d9d56f1d8280898969e07866eaa3cffed8 Mon Sep 17 00:00:00 2001 From: Luma Date: Thu, 14 Nov 2024 14:12:26 +0100 Subject: [PATCH 12/17] int for size of list Signed-off-by: Luma --- .../com/powsybl/cgmes/conversion/export/CgmesExportContext.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4a136d92542..81dadda4ea9 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 @@ -534,7 +534,7 @@ private void addIidmMappingsControlArea(Network network) { // If no control area exists, create one for the whole network, containing the dangling lines as boundaries, // but only if the network does not contain subnetworks long numControlAreas = network.getAreaStream().filter(a -> a.getAreaType().equals("ControlAreaTypeKind.Interchange")).count(); - long numSubnetworks = network.getSubnetworks().size(); + int numSubnetworks = network.getSubnetworks().size(); if (numControlAreas == 0 && numSubnetworks == 0) { createDefaultControlArea(network); } From 81b63e3eb07edbcc795ba2ac7ba7a5075944bec5 Mon Sep 17 00:00:00 2001 From: Luma Date: Thu, 14 Nov 2024 17:41:23 +0100 Subject: [PATCH 13/17] import tie flow sets the ac/dc type Signed-off-by: Luma --- .../elements/TieFlowConversion.java | 13 +++- .../test/TieFlowConversionTest.java | 30 +++++++- .../src/test/resources/HvdcTieFlow_EQ.xml | 70 +++++++++++++++++++ .../src/test/resources/HvdcTieFlow_EQBD.xml | 25 +++++++ .../src/test/resources/HvdcTieFlow_TPBD.xml | 23 ++++++ 5 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 cgmes/cgmes-conversion/src/test/resources/HvdcTieFlow_EQ.xml create mode 100644 cgmes/cgmes-conversion/src/test/resources/HvdcTieFlow_EQBD.xml create mode 100644 cgmes/cgmes-conversion/src/test/resources/HvdcTieFlow_TPBD.xml 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 index 1d07cf7e999..985b8d8c04d 100644 --- 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 @@ -10,6 +10,7 @@ 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; @@ -37,18 +38,26 @@ public void convert() { return; } String terminalId = p.getId("terminal"); + boolean isAc = isConsideredAcTieFlow(terminalId); Boundary boundary = context.terminalMapping().findBoundary(terminalId, context.cgmes()); if (boundary != null) { area.newAreaBoundary() - .setAc(true) + .setAc(isAc) .setBoundary(boundary) .add(); return; } RegulatingTerminalMapper.mapForTieFlow(terminalId, context) .ifPresent(t -> area.newAreaBoundary() - .setAc(true) + .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/test/java/com/powsybl/cgmes/conversion/test/TieFlowConversionTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/TieFlowConversionTest.java index a2d25e58cb3..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,9 +8,9 @@ package com.powsybl.cgmes.conversion.test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - +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; @@ -23,6 +23,10 @@ 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 } @@ -81,6 +85,26 @@ void microGridBaseCaseBEWithTieFlowMappedToSwitch() { 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) { config.setConvertSvInjections(true); return ConversionUtil.networkModel(testGridModel, config); 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 From c081ba27da1512184aacf3e2c08f871e51dceb6e Mon Sep 17 00:00:00 2001 From: Luma Date: Fri, 13 Dec 2024 19:42:40 +0100 Subject: [PATCH 14/17] remove legacy extension, adapt unit tests Signed-off-by: Luma --- .../conversion/export/EquipmentExport.java | 40 ++--- ...gmesConformity1ModifiedConversionTest.java | 3 +- .../test/export/EquipmentExportTest.java | 34 ++-- .../cgmes/extensions/CgmesControlArea.java | 48 ------ .../extensions/CgmesControlAreaAdder.java | 30 ---- .../extensions/CgmesControlAreaAdderImpl.java | 67 -------- .../extensions/CgmesControlAreaImpl.java | 94 ----------- .../cgmes/extensions/CgmesControlAreas.java | 41 ----- .../extensions/CgmesControlAreasAdder.java | 22 --- .../CgmesControlAreasAdderImpl.java | 27 ---- .../CgmesControlAreasAdderImplProvider.java | 40 ----- .../extensions/CgmesControlAreasImpl.java | 54 ------- .../extensions/CgmesControlAreasSerDe.java | 147 ------------------ .../extensions/CgmesControlAreaTest.java | 66 -------- .../CgmesControlAreasSerDeTest.java | 55 ------- 15 files changed, 25 insertions(+), 743 deletions(-) delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlArea.java delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdder.java delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaAdderImpl.java delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreaImpl.java delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreas.java delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdder.java delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdderImpl.java delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasAdderImplProvider.java delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasImpl.java delete mode 100644 cgmes/cgmes-extensions/src/main/java/com/powsybl/cgmes/extensions/CgmesControlAreasSerDe.java delete mode 100644 cgmes/cgmes-extensions/src/test/java/com/powsybl/cgmes/extensions/CgmesControlAreaTest.java delete mode 100644 cgmes/cgmes-extensions/src/test/java/com/powsybl/cgmes/extensions/CgmesControlAreasSerDeTest.java 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 c6076243b1e..952738b301a 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 @@ -1385,29 +1385,29 @@ 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 { for (Area area : network.getAreas()) { if (area.getAreaType().equals("ControlAreaTypeKind.Interchange")) { - writeControlArea(area, energyAreaId, cimNamespace, euNamespace, writer, context, network); + writeControlArea(area, energyAreaId, cimNamespace, euNamespace, writer, context); } } } private static void writeControlArea(Area controlArea, String energyAreaId, String cimNamespace, String euNamespace, - XMLStreamWriter writer, CgmesExportContext context, Network network) throws XMLStreamException { + 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(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, network).ifPresent(tieFlow -> + TieFlow.from(areaBoundary, context).ifPresent(tieFlow -> TieFlowEq.write(tieFlow.id(), controlAreaCgmesId, tieFlow.terminalId(), cimNamespace, writer, context) ); } } private record TieFlow(String id, String terminalId) { - static Optional from(AreaBoundary areaBoundary, CgmesExportContext context, Network network) { + static Optional from(AreaBoundary areaBoundary, CgmesExportContext context) { return areaBoundary.getTerminal().map(terminal -> from(terminal, context)) - .orElse(areaBoundary.getBoundary().flatMap(boundary -> from(boundary, context, network))); + .orElse(areaBoundary.getBoundary().flatMap(boundary -> from(boundary, context))); } static Optional from(Terminal terminal, CgmesExportContext context) { @@ -1416,8 +1416,8 @@ static Optional from(Terminal terminal, CgmesExportContext context) { CgmesExportUtil.getTerminalId(terminal, context))); } - static Optional from(Boundary boundary, CgmesExportContext context, Network network) { - String terminalId = getTieFlowBoundaryTerminal(boundary, context, network); + static Optional from(Boundary boundary, CgmesExportContext context) { + String terminalId = getTieFlowBoundaryTerminal(boundary, context); if (terminalId != null) { return Optional.of(new TieFlow( context.getNamingStrategy().getCgmesId(ref(terminalId), TIE_FLOW), @@ -1428,34 +1428,14 @@ static Optional from(Boundary boundary, CgmesExportContext context, Net } } - 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/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 4a2e0ee2eb3..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,7 +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.CgmesControlAreas; import com.powsybl.cgmes.extensions.CgmesMetadataModels; import com.powsybl.cgmes.model.*; import com.powsybl.commons.PowsyblException; @@ -862,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/EquipmentExportTest.java b/cgmes/cgmes-conversion/src/test/java/com/powsybl/cgmes/conversion/test/export/EquipmentExportTest.java index 5c0aa6e11c8..68bba576810 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 @@ -160,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()); + area.addAlias("energyIdentCodeEic", CgmesNames.ENERGY_IDENT_CODE_EIC); - // 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); + // The reimported network control area should contain one tie flow + Network actual = exportImportBusBranch(network, dataSource); Area actualControlArea = actual.getArea("controlAreaId"); - boolean tieFlowsAtTieLinesAreSupported = false; - if (tieFlowsAtTieLinesAreSupported) { - assertEquals(1, actualControlArea.getAreaBoundaryStream().count()); - assertEquals("7f43f508-2496-4b64-9146-0a40406cbe49", actualControlArea.getAreaBoundaries().iterator().next().getBoundary().get().getDanglingLine().getId()); - } else { - assertNull(actualControlArea); - } + assertEquals(1, actualControlArea.getAreaBoundaryStream().count()); + assertEquals("7f43f508-2496-4b64-9146-0a40406cbe49", actualControlArea.getAreaBoundaries().iterator().next().getBoundary().get().getDanglingLine().getId()); } @Test @@ -593,7 +586,7 @@ void microGridCgmesExportPreservingOriginalClassesOfLoads() throws IOException, // 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 (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()); @@ -671,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()); @@ -1664,6 +1657,7 @@ private Path exportToCgmesEQ(Network network) throws IOException, XMLStreamExcep private Path exportToCgmesEQ(Network network, boolean transformersWithHighestVoltageAtEnd1) throws IOException, XMLStreamException { // Export CGMES EQ file + tmpDir = Path.of("/Users/zamarrenolm/Downloads"); Path exportedEq = tmpDir.resolve("exportedEq.xml"); try (OutputStream os = new BufferedOutputStream(Files.newOutputStream(exportedEq))) { XMLStreamWriter writer = XmlUtil.initializeWriter(true, " ", os); 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"); - } -} From cc60a5387f412f0bdfca9c5b0394a6ceb545e2a5 Mon Sep 17 00:00:00 2001 From: Luma Date: Fri, 13 Dec 2024 19:54:49 +0100 Subject: [PATCH 15/17] remove local directory Signed-off-by: Luma --- .../cgmes/conversion/test/export/EquipmentExportTest.java | 1 - 1 file changed, 1 deletion(-) 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 68bba576810..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 @@ -1657,7 +1657,6 @@ private Path exportToCgmesEQ(Network network) throws IOException, XMLStreamExcep private Path exportToCgmesEQ(Network network, boolean transformersWithHighestVoltageAtEnd1) throws IOException, XMLStreamException { // Export CGMES EQ file - tmpDir = Path.of("/Users/zamarrenolm/Downloads"); Path exportedEq = tmpDir.resolve("exportedEq.xml"); try (OutputStream os = new BufferedOutputStream(Files.newOutputStream(exportedEq))) { XMLStreamWriter writer = XmlUtil.initializeWriter(true, " ", os); From 4f9d471dd54479312d8cc1d05995e1b24412190f Mon Sep 17 00:00:00 2001 From: Luma Date: Mon, 16 Dec 2024 16:59:06 +0100 Subject: [PATCH 16/17] explicit creation of default control area of type interchange Signed-off-by: Luma --- .../powsybl/cgmes/conversion/CgmesExport.java | 77 +++++++++++++++++-- .../conversion/export/CgmesExportContext.java | 62 +-------------- .../conversion/export/EquipmentExport.java | 7 ++ .../test/export/CgmesExportTest.java | 29 +++++++ 4 files changed, 109 insertions(+), 66 deletions(-) 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/export/CgmesExportContext.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/CgmesExportContext.java index 99721967cb5..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 @@ -19,7 +19,6 @@ import com.powsybl.commons.report.ReportNode; import com.powsybl.iidm.network.*; import com.powsybl.iidm.network.Identifiable; -import com.powsybl.triplestore.api.PropertyBags; import org.apache.commons.lang3.tuple.Pair; import java.net.URLEncoder; @@ -155,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)) { @@ -181,7 +184,6 @@ public void addIidmMappings(Network network) { addIidmMappingsStaticVarCompensators(network); addIidmMappingsEndsAndTapChangers(network); addIidmMappingsEquivalentInjection(network); - addIidmMappingsControlArea(network); } private void addIidmMappingsSubstations(Network network) { @@ -532,62 +534,6 @@ private void addIidmMappingsEquivalentInjection(Network network) { } } - private void addIidmMappingsControlArea(Network network) { - // If no control area exists, create one for the whole network, containing the dangling lines as boundaries, - // but only if the network does not contain subnetworks - long numControlAreas = network.getAreaStream().filter(a -> a.getAreaType().equals("ControlAreaTypeKind.Interchange")).count(); - int numSubnetworks = network.getSubnetworks().size(); - if (numControlAreas == 0 && numSubnetworks == 0) { - createDefaultControlArea(network); - } - } - - private void createDefaultControlArea(Network network) { - String controlAreaId = namingStrategy.getCgmesId(refTyped(network), CONTROL_AREA); - Area area = network.newArea() - .setAreaType("ControlAreaTypeKind.Interchange") - .setId(controlAreaId) - .setName("Network") - .add(); - 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(); - 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 Set getBoundaryDcNodes() { - if (referenceDataProvider == null) { - return Collections.emptySet(); - } - PropertyBags boundaryNodes = referenceDataProvider.getBoundaryNodes(); - if (boundaryNodes == null) { - return Collections.emptySet(); - } else { - 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; - } - 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 952738b301a..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,6 +1383,13 @@ 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 { + // 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); 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..023261f03a2 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,34 @@ 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 + 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()); + assertEquals(1, networkWithCA.getAreas().iterator().next().getAreaBoundaryStream().count()); + } + } + private static final double EPSILON = 1e-10; } From d264397c9a370d04db5bf1e5f344ad8e97750ef8 Mon Sep 17 00:00:00 2001 From: Luma Date: Mon, 16 Dec 2024 17:46:30 +0100 Subject: [PATCH 17/17] control area net interchange tolerance is optional, no default value is used Signed-off-by: Luma --- .../elements/ControlAreaConversion.java | 5 ++--- .../export/SteadyStateHypothesisExport.java | 6 ++---- .../test/export/CgmesExportTest.java | 20 ++++++++++++++++++- 3 files changed, 23 insertions(+), 8 deletions(-) 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 index db9518fe5ed..f61c4efc30c 100644 --- 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 @@ -36,11 +36,10 @@ public void convert() { .setName(p.getLocal("name")) .setInterchangeTarget(p.asDouble("netInterchange", Double.NaN)) .add(); - String pTolerance = "0"; if (p.containsKey(CgmesNames.P_TOLERANCE)) { - pTolerance = p.get(CgmesNames.P_TOLERANCE); + String pTolerance = p.get(CgmesNames.P_TOLERANCE); + area.setProperty(CgmesNames.P_TOLERANCE, pTolerance); } - 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/export/SteadyStateHypothesisExport.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/export/SteadyStateHypothesisExport.java index baa20aa21c2..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 @@ -866,11 +866,9 @@ private static void writeControlArea(Area controlArea, String cimNamespace, XMLS double pTolerance; if (controlArea.hasProperty("pTolerance")) { pTolerance = Double.parseDouble(controlArea.getProperty("pTolerance")); - } else { - pTolerance = Math.abs(0.01 * netInterchange); + writer.writeStartElement(cimNamespace, "ControlArea.pTolerance"); + writer.writeCharacters(CgmesExportUtil.format(pTolerance)); } - writer.writeStartElement(cimNamespace, "ControlArea.pTolerance"); - writer.writeCharacters(CgmesExportUtil.format(pTolerance)); writer.writeEndElement(); writer.writeEndElement(); } 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 023261f03a2..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 @@ -692,12 +692,30 @@ void networkWithoutControlAreaInterchange() throws IOException { 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()); - assertEquals(1, networkWithCA.getAreas().iterator().next().getAreaBoundaryStream().count()); + 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)); } }