From 9c18cc516664ac1266464d7b8438b506a297768c Mon Sep 17 00:00:00 2001 From: rcourtier <129156292+rcourtier@users.noreply.github.com> Date: Fri, 10 Jan 2025 15:15:09 +0100 Subject: [PATCH] Use PowerTransformerEnd.endNumber to sort transformer windings (#3234) * Use PowerTransformerEnd.endNumber instead of Terminal.sequenceNumber to sort transformer windings * Add an UNKNOWN value to the WindingType enum * Simplify sorting of transformerends Signed-off-by: Romain Courtier --- .../AbstractTransformerConversion.java | 5 +- .../cgmes/model/AbstractCgmesModel.java | 12 +-- .../com/powsybl/cgmes/model/WindingType.java | 48 +++++++----- .../powsybl/cgmes/model/WindingTypeTest.java | 75 +++++++++++++++++++ 4 files changed, 108 insertions(+), 32 deletions(-) create mode 100644 cgmes/cgmes-model/src/test/java/com/powsybl/cgmes/model/WindingTypeTest.java diff --git a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/transformers/AbstractTransformerConversion.java b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/transformers/AbstractTransformerConversion.java index a13b5cd1f6a..2f6a272dba5 100644 --- a/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/transformers/AbstractTransformerConversion.java +++ b/cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/conversion/elements/transformers/AbstractTransformerConversion.java @@ -16,6 +16,7 @@ import com.powsybl.cgmes.extensions.CgmesTapChangers; import com.powsybl.cgmes.extensions.CgmesTapChangersAdder; import com.powsybl.cgmes.model.CgmesNames; +import com.powsybl.cgmes.model.WindingType; import com.powsybl.iidm.network.*; import com.powsybl.triplestore.api.PropertyBag; import com.powsybl.triplestore.api.PropertyBags; @@ -111,10 +112,8 @@ protected CgmesRegulatingControlPhase setContextRegulatingDataPhase(TapChanger t @Override protected void addAliasesAndProperties(Identifiable identifiable) { super.addAliasesAndProperties(identifiable); - int end = 1; for (PropertyBag p : ps) { - identifiable.addAlias(p.getId("TransformerEnd"), Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + CgmesNames.TRANSFORMER_END + end); - end++; + identifiable.addAlias(p.getId("TransformerEnd"), Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + CgmesNames.TRANSFORMER_END + WindingType.endNumber(p)); } List ptcs = context.cgmes().phaseTapChangerListForPowerTransformer(identifiable.getId()); if (ptcs != null) { diff --git a/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/AbstractCgmesModel.java b/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/AbstractCgmesModel.java index 6006049b616..bc0063c1ddf 100644 --- a/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/AbstractCgmesModel.java +++ b/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/AbstractCgmesModel.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.io.InputStream; import java.util.*; -import java.util.stream.Collectors; /** * @author Luma ZamarreƱo {@literal } @@ -202,16 +201,7 @@ private Map computeGroupedTransformerEnds() { powerTransformerRatioTapChanger.get(id)[end.asInt(endNumber, 1) - 1] = end.getId("RatioTapChanger"); } }); - gends.entrySet() - .forEach(tends -> { - PropertyBags tends1 = new PropertyBags( - tends.getValue().stream() - .sorted(Comparator - .comparing(WindingType::fromTransformerEnd) - .thenComparing(end -> end.asInt(endNumber, -1))) - .collect(Collectors.toList())); - tends.setValue(tends1); - }); + gends.values().forEach(tends -> tends.sort(Comparator.comparing(WindingType::endNumber))); return gends; } diff --git a/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/WindingType.java b/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/WindingType.java index 049302e5969..669d0ef8b73 100644 --- a/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/WindingType.java +++ b/cgmes/cgmes-model/src/main/java/com/powsybl/cgmes/model/WindingType.java @@ -15,27 +15,39 @@ */ public enum WindingType { - PRIMARY, SECONDARY, TERTIARY; - - public static WindingType fromTransformerEnd(PropertyBag end) { - // For CIM14 (CIM ENTSOE Profile1) primary is determined by windingType - // For CIM16 (CGMES) primary is defined by the corresponding terminal sequence number: - // "The Terminal.sequenceNumber distinguishes the terminals much as previously done by - // TransformerWinding.windingType:WindingType" + UNKNOWN, PRIMARY, SECONDARY, TERTIARY; + /** + * Retrieve the WindingType for the given transformer winding/end. + * @param end A PropertyBag with the transformer winding/end properties. + * @return The WindingType (PRIMARY/SECONDARY/TERTIARY) corresponding to the given transformer winding/end. + */ + public static WindingType windingType(PropertyBag end) { if (end.containsKey("windingType")) { - String wtype = end.getLocal("windingType"); - if (wtype.endsWith("WindingType.primary")) { - return WindingType.PRIMARY; - } else if (wtype.endsWith("WindingType.secondary")) { - return WindingType.SECONDARY; - } else if (wtype.endsWith("WindingType.tertiary")) { - return WindingType.TERTIARY; + // For CIM14 (CIM ENTSOE Profile1) primary is determined by TransformerWinding.windingType + return switch (end.getLocal("windingType")) { + case "WindingType.primary" -> WindingType.PRIMARY; + case "WindingType.secondary" -> WindingType.SECONDARY; + case "WindingType.tertiary" -> WindingType.TERTIARY; + default -> WindingType.UNKNOWN; + }; + } else if (end.containsKey("endNumber")) { + // For CIM16 (CGMES 2.4.15) primary is defined by TransformerEnd.endNumber + try { + return WindingType.values()[end.asInt("endNumber")]; + } catch (Exception e) { + return WindingType.UNKNOWN; } - } else if (end.containsKey("terminalSequenceNumber")) { - // Terminal.sequenceNumber := 1, 2 ,3 ... - return WindingType.values()[end.asInt("terminalSequenceNumber") - 1]; } - return WindingType.PRIMARY; + return WindingType.UNKNOWN; + } + + /** + * Retrieve the endNumber for the given transformer winding/end. + * @param end A PropertyBag with the transformer winding/end properties. + * @return The endNumber value (1/2/3) corresponding to the given transformer winding/end. + */ + public static int endNumber(PropertyBag end) { + return windingType(end).ordinal(); } } diff --git a/cgmes/cgmes-model/src/test/java/com/powsybl/cgmes/model/WindingTypeTest.java b/cgmes/cgmes-model/src/test/java/com/powsybl/cgmes/model/WindingTypeTest.java new file mode 100644 index 00000000000..c888d4a4bca --- /dev/null +++ b/cgmes/cgmes-model/src/test/java/com/powsybl/cgmes/model/WindingTypeTest.java @@ -0,0 +1,75 @@ +/** + * 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.model; + +import com.powsybl.triplestore.api.PropertyBag; +import org.junit.jupiter.api.Test; + +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author Romain Courtier {@literal } + */ +class WindingTypeTest { + + PropertyBag end1; + PropertyBag end2; + PropertyBag end3; + PropertyBag end4; + + static final String WINDING_TYPE = "windingType"; + static final String END_NUMBER = "endNumber"; + + @Test + void cim14WindingTypeTest() { + end1 = new PropertyBag(Collections.singletonList(WINDING_TYPE), true); + end1.put(WINDING_TYPE, "http://iec.ch/TC57/2009/CIM-schema-cim14#WindingType.primary"); + assertEquals(WindingType.PRIMARY, WindingType.windingType(end1)); + assertEquals(1, WindingType.endNumber(end1)); + + end2 = new PropertyBag(Collections.singletonList(WINDING_TYPE), true); + end2.put(WINDING_TYPE, "http://iec.ch/TC57/2009/CIM-schema-cim14#WindingType.secondary"); + assertEquals(WindingType.SECONDARY, WindingType.windingType(end2)); + assertEquals(2, WindingType.endNumber(end2)); + + end3 = new PropertyBag(Collections.singletonList(WINDING_TYPE), true); + end3.put(WINDING_TYPE, "http://iec.ch/TC57/2009/CIM-schema-cim14#WindingType.tertiary"); + assertEquals(WindingType.TERTIARY, WindingType.windingType(end3)); + assertEquals(3, WindingType.endNumber(end3)); + + end4 = new PropertyBag(Collections.singletonList(WINDING_TYPE), true); + end4.put(WINDING_TYPE, "Unknown"); + assertEquals(WindingType.UNKNOWN, WindingType.windingType(end4)); + assertEquals(0, WindingType.endNumber(end4)); + } + + @Test + void cim16WindingTypeTest() { + end1 = new PropertyBag(Collections.singletonList(END_NUMBER), true); + end1.put(END_NUMBER, "1"); + assertEquals(WindingType.PRIMARY, WindingType.windingType(end1)); + assertEquals(1, WindingType.endNumber(end1)); + + end2 = new PropertyBag(Collections.singletonList(END_NUMBER), true); + end2.put(END_NUMBER, "2"); + assertEquals(WindingType.SECONDARY, WindingType.windingType(end2)); + assertEquals(2, WindingType.endNumber(end2)); + + end3 = new PropertyBag(Collections.singletonList(END_NUMBER), true); + end3.put(END_NUMBER, "3"); + assertEquals(WindingType.TERTIARY, WindingType.windingType(end3)); + assertEquals(3, WindingType.endNumber(end3)); + + end4 = new PropertyBag(Collections.singletonList(END_NUMBER), true); + end4.put(END_NUMBER, "Unknown"); + assertEquals(WindingType.UNKNOWN, WindingType.windingType(end4)); + assertEquals(0, WindingType.endNumber(end4)); + } +}