diff --git a/ieee-cdf/ieee-cdf-converter/src/main/java/com/powsybl/ieeecdf/converter/IeeeCdfImporter.java b/ieee-cdf/ieee-cdf-converter/src/main/java/com/powsybl/ieeecdf/converter/IeeeCdfImporter.java index 23a491a6497..7a60e6c3597 100644 --- a/ieee-cdf/ieee-cdf-converter/src/main/java/com/powsybl/ieeecdf/converter/IeeeCdfImporter.java +++ b/ieee-cdf/ieee-cdf-converter/src/main/java/com/powsybl/ieeecdf/converter/IeeeCdfImporter.java @@ -17,6 +17,9 @@ import com.powsybl.commons.parameters.ParameterDefaultValueConfig; import com.powsybl.commons.parameters.ParameterType; import com.powsybl.ieeecdf.model.*; +import com.powsybl.ieeecdf.model.elements.IeeeCdfBranch; +import com.powsybl.ieeecdf.model.elements.IeeeCdfBus; +import com.powsybl.ieeecdf.model.elements.IeeeCdfTitle; import com.powsybl.iidm.network.*; import com.powsybl.iidm.network.extensions.SlackTerminal; import com.powsybl.iidm.network.util.ContainersMapping; diff --git a/ieee-cdf/ieee-cdf-converter/src/main/java/com/powsybl/ieeecdf/converter/IeeeCdfNetworkFactory.java b/ieee-cdf/ieee-cdf-converter/src/main/java/com/powsybl/ieeecdf/converter/IeeeCdfNetworkFactory.java index 3664ba9aec6..c7c4bdfe5b3 100644 --- a/ieee-cdf/ieee-cdf-converter/src/main/java/com/powsybl/ieeecdf/converter/IeeeCdfNetworkFactory.java +++ b/ieee-cdf/ieee-cdf-converter/src/main/java/com/powsybl/ieeecdf/converter/IeeeCdfNetworkFactory.java @@ -10,10 +10,10 @@ import com.powsybl.commons.PowsyblException; import com.powsybl.commons.datasource.ResourceDataSource; import com.powsybl.commons.datasource.ResourceSet; -import com.powsybl.ieeecdf.model.IeeeCdfBranch; -import com.powsybl.ieeecdf.model.IeeeCdfBus; +import com.powsybl.ieeecdf.model.elements.IeeeCdfBranch; +import com.powsybl.ieeecdf.model.elements.IeeeCdfBus; import com.powsybl.ieeecdf.model.IeeeCdfModel; -import com.powsybl.ieeecdf.model.IeeeCdfTitle; +import com.powsybl.ieeecdf.model.elements.IeeeCdfTitle; import com.powsybl.iidm.network.Network; import com.powsybl.iidm.network.NetworkFactory; import com.univocity.parsers.csv.CsvParser; diff --git a/ieee-cdf/ieee-cdf-model/pom.xml b/ieee-cdf/ieee-cdf-model/pom.xml index 70ac931584e..0cf72465b69 100644 --- a/ieee-cdf/ieee-cdf-model/pom.xml +++ b/ieee-cdf/ieee-cdf-model/pom.xml @@ -42,10 +42,6 @@ com.fasterxml.jackson.core jackson-databind - - com.univocity - univocity-parsers - ${project.groupId} @@ -69,6 +65,11 @@ junit-jupiter test + + org.slf4j + slf4j-simple + test + diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfModel.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfModel.java index 0d9e2bf3d89..723e0fbfa31 100644 --- a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfModel.java +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfModel.java @@ -7,6 +7,13 @@ */ package com.powsybl.ieeecdf.model; +import com.powsybl.ieeecdf.model.elements.IeeeCdfBranch; +import com.powsybl.ieeecdf.model.elements.IeeeCdfBus; +import com.powsybl.ieeecdf.model.elements.IeeeCdfInterchangeData; +import com.powsybl.ieeecdf.model.elements.IeeeCdfLossZone; +import com.powsybl.ieeecdf.model.elements.IeeeCdfTieLine; +import com.powsybl.ieeecdf.model.elements.IeeeCdfTitle; + import java.util.ArrayList; import java.util.List; import java.util.Objects; diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfReader.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfReader.java index 90464a857bf..17da522971d 100644 --- a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfReader.java +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfReader.java @@ -7,100 +7,70 @@ */ package com.powsybl.ieeecdf.model; -import com.univocity.parsers.common.processor.BeanListProcessor; -import com.univocity.parsers.fixed.FixedWidthParser; -import com.univocity.parsers.fixed.FixedWidthParserSettings; +import com.google.re2j.Matcher; +import com.google.re2j.Pattern; +import com.powsybl.commons.PowsyblException; +import com.powsybl.ieeecdf.model.elements.IeeeCdfTitle; +import com.powsybl.ieeecdf.model.reader.IeeeCdfBranchReader; +import com.powsybl.ieeecdf.model.reader.IeeeCdfBusReader; +import com.powsybl.ieeecdf.model.reader.IeeeCdfInterchangeDataReader; +import com.powsybl.ieeecdf.model.reader.IeeeCdfLossZoneReader; +import com.powsybl.ieeecdf.model.reader.IeeeCdfTieLineReader; +import com.powsybl.ieeecdf.model.reader.IeeeCdfTitleReader; import java.io.BufferedReader; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; /** * @author Geoffroy Jamgotchian {@literal } */ public class IeeeCdfReader { - enum IeeeCdfSection { - BUS, - BRANCH, - LOSS_ZONES, - INTERCHANGE_DATA, - TIE_LINES - } + private static final Pattern PATTERN_BUS = Pattern.compile("BUS DATA FOLLOWS\\s+(\\d+)\\s+ITEMS"); + private static final Pattern PATTERN_BRANCH = Pattern.compile("BRANCH DATA FOLLOWS\\s+(\\d+)\\s+ITEMS"); + private static final Pattern PATTERN_LOSS_ZONE = Pattern.compile("LOSS ZONES FOLLOWS\\s+(\\d+)\\s+ITEMS"); + private static final Pattern PATTERN_INTERCHANGE = Pattern.compile("INTERCHANGE DATA FOLLOWS\\s+(\\d+)\\s+ITEMS"); + private static final Pattern PATTERN_TIE_LINE = Pattern.compile("TIE LINES FOLLOWS\\s+(\\d+)\\s+ITEMS"); public IeeeCdfModel read(BufferedReader reader) throws IOException { - String line = reader.readLine(); + String line; // Ensure malformed input does not trigger unexpected ArrayIndexOutOfBoundException - List parsedLines = parseLines(Collections.singletonList(line), IeeeCdfTitle.class); - if (parsedLines.isEmpty()) { + IeeeCdfTitle title = IeeeCdfTitleReader.parseTitle(reader); + if (title == null) { throw new IllegalArgumentException("Failed to parse the IeeeCdfModel"); } - IeeeCdfTitle title = parsedLines.get(0); IeeeCdfModel model = new IeeeCdfModel(title); - IeeeCdfSection section = null; - List lines = new ArrayList<>(); while ((line = reader.readLine()) != null) { if (line.startsWith("BUS DATA FOLLOWS")) { - section = IeeeCdfSection.BUS; + int expectedItemsNumber = getExpectedItemsNumber(line, PATTERN_BUS); + model.getBuses().addAll(IeeeCdfBusReader.parseBuses(reader, expectedItemsNumber)); } else if (line.startsWith("BRANCH DATA FOLLOWS")) { - section = IeeeCdfSection.BRANCH; + int expectedItemsNumber = getExpectedItemsNumber(line, PATTERN_BRANCH); + model.getBranches().addAll(IeeeCdfBranchReader.parseBranches(reader, expectedItemsNumber)); } else if (line.startsWith("LOSS ZONES FOLLOWS")) { - section = IeeeCdfSection.LOSS_ZONES; + int expectedItemsNumber = getExpectedItemsNumber(line, PATTERN_LOSS_ZONE); + model.getLossZones().addAll(IeeeCdfLossZoneReader.parseLossZones(reader, expectedItemsNumber)); } else if (line.startsWith("INTERCHANGE DATA FOLLOWS")) { - section = IeeeCdfSection.INTERCHANGE_DATA; + int expectedItemsNumber = getExpectedItemsNumber(line, PATTERN_INTERCHANGE); + model.getInterchangeData().addAll(IeeeCdfInterchangeDataReader.parseInterchangeData(reader, expectedItemsNumber)); } else if (line.startsWith("TIE LINES FOLLOWS ")) { - section = IeeeCdfSection.TIE_LINES; - } else if (line.startsWith("-9")) { - if (section != null) { - parseLines(lines, model, section); - lines.clear(); - section = null; - } - } else { - if (section != null) { - lines.add(line); - } + int expectedItemsNumber = getExpectedItemsNumber(line, PATTERN_TIE_LINE); + model.getTieLines().addAll(IeeeCdfTieLineReader.parseTieLine(reader, expectedItemsNumber)); } } return model; } - private static List parseLines(List lines, Class aClass) { - FixedWidthParserSettings settings = new FixedWidthParserSettings(); - BeanListProcessor processor = new BeanListProcessor<>(aClass); - settings.setProcessor(processor); - FixedWidthParser parser = new FixedWidthParser(settings); - for (String line : lines) { - parser.parseLine(line); - } - return processor.getBeans(); - } - - private void parseLines(List lines, IeeeCdfModel model, IeeeCdfSection section) { - switch (section) { - case BUS: - model.getBuses().addAll(parseLines(lines, IeeeCdfBus.class)); - break; - case BRANCH: - model.getBranches().addAll(parseLines(lines, IeeeCdfBranch.class)); - break; - case LOSS_ZONES: - model.getLossZones().addAll(parseLines(lines, IeeeCdfLossZone.class)); - break; - case INTERCHANGE_DATA: - model.getInterchangeData().addAll(parseLines(lines, IeeeCdfInterchangeData.class)); - break; - case TIE_LINES: - model.getTieLines().addAll(parseLines(lines, IeeeCdfTieLine.class)); - break; - default: - throw new IllegalStateException("Section unknown: " + section); + private static int getExpectedItemsNumber(String line, Pattern pattern) { + Matcher m = pattern.matcher(line); + if (m.matches()) { + return Integer.parseInt(m.group(1)); + } else { + throw new PowsyblException("Failed to parse the expected number of IEEE-CDF items in:" + line); } } } diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfWriter.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfWriter.java index 6896d6d889f..f98cc6db279 100644 --- a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfWriter.java +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfWriter.java @@ -7,15 +7,15 @@ */ package com.powsybl.ieeecdf.model; -import com.univocity.parsers.common.processor.BeanWriterProcessor; -import com.univocity.parsers.fixed.FixedWidthWriter; -import com.univocity.parsers.fixed.FixedWidthWriterSettings; +import com.powsybl.ieeecdf.model.writer.IeeeCdfBranchWriter; +import com.powsybl.ieeecdf.model.writer.IeeeCdfBusWriter; +import com.powsybl.ieeecdf.model.writer.IeeeCdfInterchangeDataWriter; +import com.powsybl.ieeecdf.model.writer.IeeeCdfLossZoneWriter; +import com.powsybl.ieeecdf.model.writer.IeeeCdfTieLineWriter; +import com.powsybl.ieeecdf.model.writer.IeeeCdfTitleWriter; import java.io.BufferedWriter; import java.io.IOException; -import java.io.Writer; -import java.util.Collections; -import java.util.List; import java.util.Objects; /** @@ -29,47 +29,14 @@ public IeeeCdfWriter(IeeeCdfModel model) { this.model = Objects.requireNonNull(model); } - private static void writeRecords(Writer writer, List beans, Class aClass) { - FixedWidthWriterSettings settings = new FixedWidthWriterSettings(); - settings.setWriteLineSeparatorAfterRecord(true); - BeanWriterProcessor processor = new BeanWriterProcessor<>(aClass); - settings.setRowWriterProcessor(processor); - new FixedWidthWriter(writer, settings).processRecords(beans); - } - public void write(BufferedWriter writer) throws IOException { - writeRecords(writer, Collections.singletonList(model.getTitle()), IeeeCdfTitle.class); - - writer.write(String.format("BUS DATA FOLLOWS %d ITEMS", model.getBuses().size())); - writer.newLine(); - writeRecords(writer, model.getBuses(), IeeeCdfBus.class); - writer.write("-999"); - writer.newLine(); - - writer.write(String.format("BRANCH DATA FOLLOWS %d ITEMS", model.getBranches().size())); - writer.newLine(); - writeRecords(writer, model.getBranches(), IeeeCdfBranch.class); - writer.write("-999"); - writer.newLine(); - - writer.write(String.format("LOSS ZONES FOLLOWS %d ITEMS", model.getLossZones().size())); - writer.newLine(); - writeRecords(writer, model.getLossZones(), IeeeCdfLossZone.class); - writer.write("-99"); - writer.newLine(); - - writer.write(String.format("INTERCHANGE DATA FOLLOWS %d ITEMS", model.getInterchangeData().size())); - writer.newLine(); - writeRecords(writer, model.getInterchangeData(), IeeeCdfInterchangeData.class); - writer.write("-9"); - writer.newLine(); - - writer.write(String.format("TIE LINES FOLLOWS %d ITEMS", model.getTieLines().size())); - writer.newLine(); - writeRecords(writer, model.getTieLines(), IeeeCdfTieLine.class); - writer.write("-999"); - writer.newLine(); + IeeeCdfTitleWriter.writeTitle(writer, model.getTitle()); + IeeeCdfBusWriter.writeBuses(writer, model.getBuses()); + IeeeCdfBranchWriter.writeBranches(writer, model.getBranches()); + IeeeCdfLossZoneWriter.writeLossZone(writer, model.getLossZones()); + IeeeCdfInterchangeDataWriter.writeInterchangeData(writer, model.getInterchangeData()); + IeeeCdfTieLineWriter.writeTieLines(writer, model.getTieLines()); writer.write("END OF DATA"); writer.newLine(); diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/SeasonConversion.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/SeasonConversion.java deleted file mode 100644 index 5b1f060622e..00000000000 --- a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/SeasonConversion.java +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2019, 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.ieeecdf.model; - -import com.univocity.parsers.conversions.ObjectConversion; - -/** - * @author Geoffroy Jamgotchian {@literal } - */ -public class SeasonConversion extends ObjectConversion { - - @Override - protected IeeeCdfTitle.Season fromString(String str) { - char season = str.charAt(0); - switch (season) { - case 'S': - return IeeeCdfTitle.Season.SUMMER; - case 'W': - return IeeeCdfTitle.Season.WINTER; - default: - throw new IllegalStateException("Unknown season: " + season); - } - } - - @Override - public String revert(IeeeCdfTitle.Season season) { - switch (season) { - case SUMMER: - return "S"; - case WINTER: - return "W"; - default: - throw new IllegalStateException("Unknown season: " + season); - } - } -} diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/BranchSideConversion.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/conversion/BranchSideConversion.java similarity index 55% rename from ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/BranchSideConversion.java rename to ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/conversion/BranchSideConversion.java index add06b7e732..69dff7b57c3 100644 --- a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/BranchSideConversion.java +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/conversion/BranchSideConversion.java @@ -1,26 +1,28 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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.ieeecdf.model; +package com.powsybl.ieeecdf.model.conversion; -import com.univocity.parsers.conversions.ObjectConversion; +import com.powsybl.ieeecdf.model.elements.IeeeCdfBranch; /** * @author Geoffroy Jamgotchian {@literal } */ -public class BranchSideConversion extends ObjectConversion { +public final class BranchSideConversion { + + private BranchSideConversion() { + // Utility class + } - @Override - protected IeeeCdfBranch.Side fromString(String str) { + public static IeeeCdfBranch.Side fromString(String str) { return IeeeCdfBranch.Side.values()[Integer.parseInt(str.trim())]; } - @Override - public String revert(IeeeCdfBranch.Side side) { + public static String revert(IeeeCdfBranch.Side side) { return side == null ? "" : Integer.toString(side.ordinal()); } } diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/BranchTypeConversion.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/conversion/BranchTypeConversion.java similarity index 58% rename from ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/BranchTypeConversion.java rename to ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/conversion/BranchTypeConversion.java index 6b12a21a2f4..831e1c8c8c5 100644 --- a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/BranchTypeConversion.java +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/conversion/BranchTypeConversion.java @@ -1,27 +1,29 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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.ieeecdf.model; +package com.powsybl.ieeecdf.model.conversion; -import com.univocity.parsers.conversions.ObjectConversion; +import com.powsybl.ieeecdf.model.elements.IeeeCdfBranch; /** * @author Geoffroy Jamgotchian {@literal } */ -public class BranchTypeConversion extends ObjectConversion { +public final class BranchTypeConversion { + + private BranchTypeConversion() { + // Utility class + } - @Override - protected IeeeCdfBranch.Type fromString(String str) { + public static IeeeCdfBranch.Type fromString(String str) { String trimmedStr = str.trim(); return trimmedStr.isEmpty() ? null : IeeeCdfBranch.Type.values()[Integer.parseInt(trimmedStr)]; } - @Override - public String revert(IeeeCdfBranch.Type type) { + public static String revert(IeeeCdfBranch.Type type) { return type == null ? "" : Integer.toString(type.ordinal()); } } diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/BusTypeConversion.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/conversion/BusTypeConversion.java similarity index 55% rename from ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/BusTypeConversion.java rename to ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/conversion/BusTypeConversion.java index 47b4695735e..41a5c7c7766 100644 --- a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/BusTypeConversion.java +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/conversion/BusTypeConversion.java @@ -1,26 +1,28 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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.ieeecdf.model; +package com.powsybl.ieeecdf.model.conversion; -import com.univocity.parsers.conversions.ObjectConversion; +import com.powsybl.ieeecdf.model.elements.IeeeCdfBus; /** * @author Geoffroy Jamgotchian {@literal } */ -public class BusTypeConversion extends ObjectConversion { +public final class BusTypeConversion { + + private BusTypeConversion() { + // Utility class + } - @Override - protected IeeeCdfBus.Type fromString(String str) { + public static IeeeCdfBus.Type fromString(String str) { return IeeeCdfBus.Type.values()[Integer.parseInt(str.trim())]; } - @Override - public String revert(IeeeCdfBus.Type type) { + public static String revert(IeeeCdfBus.Type type) { return Integer.toString(type.ordinal()); } } diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/LocalDateConversion.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/conversion/LocalDateConversion.java similarity index 58% rename from ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/LocalDateConversion.java rename to ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/conversion/LocalDateConversion.java index b64b3e0188e..1aeeaca3d49 100644 --- a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/LocalDateConversion.java +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/conversion/LocalDateConversion.java @@ -1,13 +1,11 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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.ieeecdf.model; - -import com.univocity.parsers.conversions.ObjectConversion; +package com.powsybl.ieeecdf.model.conversion; import java.time.LocalDate; import java.time.format.DateTimeFormatter; @@ -17,30 +15,27 @@ /** * @author Geoffroy Jamgotchian {@literal } */ -public class LocalDateConversion extends ObjectConversion { +public final class LocalDateConversion { + + private LocalDateConversion() { + // Utility class + } private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder() - .appendPattern("M/d/") - .optionalStart() - .appendPattern("uuuu") - .optionalEnd() - .optionalStart() - .appendValueReduced(ChronoField.YEAR, 2, 2, 1970) - .optionalEnd() - .toFormatter(); + .appendPattern("M/d/") + .appendValueReduced(ChronoField.YEAR, 2, 2, 1970) + .toFormatter(); private static final String INVALID_DATE = "0 /0 /0 "; - @Override - protected LocalDate fromString(String str) { + public static LocalDate fromString(String str) { if (!str.equals(INVALID_DATE)) { return LocalDate.parse(str, FORMATTER); } return null; } - @Override - public String revert(LocalDate date) { + public static String revert(LocalDate date) { return date != null ? FORMATTER.format(date) : INVALID_DATE; } } diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/conversion/SeasonConversion.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/conversion/SeasonConversion.java new file mode 100644 index 00000000000..c4ea40581f1 --- /dev/null +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/conversion/SeasonConversion.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019-2025, 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.ieeecdf.model.conversion; + +import com.powsybl.ieeecdf.model.elements.IeeeCdfTitle; + +/** + * @author Geoffroy Jamgotchian {@literal } + */ +public final class SeasonConversion { + + private SeasonConversion() { + // Utility class + } + + public static IeeeCdfTitle.Season fromString(String str) { + char season = str.charAt(0); + return switch (season) { + case 'S' -> IeeeCdfTitle.Season.SUMMER; + case 'W' -> IeeeCdfTitle.Season.WINTER; + default -> throw new IllegalStateException("Unknown season: " + season); + }; + } + + public static String revert(IeeeCdfTitle.Season season) { + return switch (season) { + case SUMMER -> "S"; + case WINTER -> "W"; + default -> throw new IllegalStateException("Unknown season: " + season); + }; + } +} diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/AbstractIeeeElement.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/AbstractIeeeElement.java new file mode 100644 index 00000000000..0a973e10493 --- /dev/null +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/AbstractIeeeElement.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025, 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.ieeecdf.model.elements; + +/** + * @author Nicolas Rol {@literal } + */ +public abstract class AbstractIeeeElement { + protected AbstractIeeeElement() { + // Constructor + } +} diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfBranch.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/IeeeCdfBranch.java similarity index 81% rename from ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfBranch.java rename to ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/IeeeCdfBranch.java index 6e2c3a98c90..5a7a6aa1ea6 100644 --- a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfBranch.java +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/IeeeCdfBranch.java @@ -1,16 +1,11 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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.ieeecdf.model; - -import com.univocity.parsers.annotations.Convert; -import com.univocity.parsers.annotations.FixedWidth; -import com.univocity.parsers.annotations.Parsed; -import com.univocity.parsers.fixed.FieldAlignment; +package com.powsybl.ieeecdf.model.elements; /** *

@@ -55,7 +50,7 @@ * * @author Geoffroy Jamgotchian {@literal } */ -public class IeeeCdfBranch { +public class IeeeCdfBranch extends AbstractIeeeElement { /** * 0 - Transmission line @@ -81,157 +76,111 @@ public enum Side { /** * Tap bus number (I) * */ - @FixedWidth(from = 0, to = 4, alignment = FieldAlignment.RIGHT) - @Parsed private int tapBusNumber; /** * Z bus number (I) * */ - @FixedWidth(from = 5, to = 9, alignment = FieldAlignment.RIGHT) - @Parsed private int zBusNumber; /** * Load flow area (I) */ - @FixedWidth(from = 10, to = 12, alignment = FieldAlignment.RIGHT) - @Parsed private int area; /** * Loss zone (I) */ - @FixedWidth(from = 13, to = 15, alignment = FieldAlignment.RIGHT) - @Parsed private int lossZone; /** * Circuit (I) * (Use 1 for single lines) */ - @FixedWidth(from = 16, to = 17, alignment = FieldAlignment.RIGHT) - @Parsed private int circuit; /** * Type (I) * */ - @FixedWidth(from = 18, to = 19) - @Parsed - @Convert(conversionClass = BranchTypeConversion.class) private Type type; /** * Branch resistance R, per unit (F) * */ - @FixedWidth(from = 19, to = 29, alignment = FieldAlignment.RIGHT) - @Parsed private double resistance; /** * Branch reactance X, per unit (F) * No zero impedance lines */ - @FixedWidth(from = 29, to = 40, alignment = FieldAlignment.RIGHT) - @Parsed private double reactance; /** * Line charging B, per unit (F) * (total line charging, +B) */ - @FixedWidth(from = 40, to = 50, alignment = FieldAlignment.RIGHT) - @Parsed private double chargingSusceptance; /** * Line MVA rating No 1 (I) Left justify! */ - @FixedWidth(from = 50, to = 55, alignment = FieldAlignment.RIGHT) - @Parsed private int rating1; /** * Line MVA rating No 2 (I) Left justify! */ - @FixedWidth(from = 56, to = 61, alignment = FieldAlignment.RIGHT) - @Parsed private int rating2; /** * Line MVA rating No 3 (I) Left justify! */ - @FixedWidth(from = 62, to = 67, alignment = FieldAlignment.RIGHT) - @Parsed private int rating3; /** * Control bus number */ - @FixedWidth(from = 68, to = 72, alignment = FieldAlignment.RIGHT) - @Parsed private int controlBusNumber; /** * Side (I) */ - @FixedWidth(from = 73, to = 74, alignment = FieldAlignment.RIGHT) - @Parsed - @Convert(conversionClass = BranchSideConversion.class) private Side side; /** * Transformer final turns ratio (F) */ - @FixedWidth(from = 76, to = 82) - @Parsed private double finalTurnsRatio; /** * Transformer (phase shifter) final angle (F) */ - @FixedWidth(from = 83, to = 90) - @Parsed private double finalAngle; /** * Minimum tap or phase shift (F) */ - @FixedWidth(from = 90, to = 97) - @Parsed private double minTapOrPhaseShift; /** * Maximum tap or phase shift (F) */ - @FixedWidth(from = 97, to = 104) - @Parsed private double maxTapOrPhaseShift; /** * Step size (F) */ - @FixedWidth(from = 105, to = 112) - @Parsed private double stepSize; /** * Minimum voltage, MVAR or MW limit (F) */ - @FixedWidth(from = 112, to = 118) - @Parsed private double minVoltageActiveOrReactivePowerLimit; /** * Maximum voltage, MVAR or MW limit (F) */ - @FixedWidth(from = 119, to = 126) - @Parsed private double maxVoltageActiveOrReactivePowerLimit; /** * This parameter does not exist in the specification but is present in 300 buses case. */ - @FixedWidth(from = 126, to = 133) - @Parsed private int unused; public int getTapBusNumber() { @@ -401,4 +350,12 @@ public double getMaxVoltageActiveOrReactivePowerLimit() { public void setMaxVoltageActiveOrReactivePowerLimit(double maxVoltageActiveOrReactivePowerLimit) { this.maxVoltageActiveOrReactivePowerLimit = maxVoltageActiveOrReactivePowerLimit; } + + public int getUnused() { + return unused; + } + + public void setUnused(int unused) { + this.unused = unused; + } } diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfBus.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/IeeeCdfBus.java similarity index 82% rename from ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfBus.java rename to ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/IeeeCdfBus.java index 4e5ae60825f..44cf83bbe52 100644 --- a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfBus.java +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/IeeeCdfBus.java @@ -1,16 +1,11 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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.ieeecdf.model; - -import com.univocity.parsers.annotations.Convert; -import com.univocity.parsers.annotations.FixedWidth; -import com.univocity.parsers.annotations.Parsed; -import com.univocity.parsers.fixed.FieldAlignment; +package com.powsybl.ieeecdf.model.elements; /** *

@@ -44,7 +39,7 @@ * * @author Geoffroy Jamgotchian {@literal } */ -public class IeeeCdfBus { +public class IeeeCdfBus extends AbstractIeeeElement { /** * 0 - Unregulated (load, PQ) @@ -62,133 +57,97 @@ public enum Type { /** * Bus number */ - @FixedWidth(from = 0, to = 4, alignment = FieldAlignment.RIGHT) - @Parsed private int number; /** * Name */ - @FixedWidth(from = 5, to = 17) - @Parsed private String name; /** * Load flow area number */ - @FixedWidth(from = 18, to = 20, alignment = FieldAlignment.RIGHT) - @Parsed private int areaNumber; /** * Loss zone number */ - @FixedWidth(from = 20, to = 23, alignment = FieldAlignment.RIGHT) - @Parsed private int lossZoneNumber; /** * Type */ - @FixedWidth(from = 24, to = 26, alignment = FieldAlignment.RIGHT) - @Parsed - @Convert(conversionClass = BusTypeConversion.class) private Type type; /** * Final voltage, p.u. */ - @FixedWidth(from = 27, to = 33) - @Parsed private double finalVoltage; /** * Final angle, degrees */ - @FixedWidth(from = 33, to = 40) - @Parsed private double finalAngle; /** * Load MW */ - @FixedWidth(from = 40, to = 49) - @Parsed private double activeLoad; /** * Load MVAR */ - @FixedWidth(from = 49, to = 59) - @Parsed private double reactiveLoad; /** * Generation MW */ - @FixedWidth(from = 59, to = 67) - @Parsed private double activeGeneration; /** * Generation MVAR */ - @FixedWidth(from = 67, to = 75) - @Parsed private double reactiveGeneration; /** * Base KV */ - @FixedWidth(from = 76, to = 83) - @Parsed private double baseVoltage; /** * Desired volts (pu) (F) (This is desired remote voltage if this bus is controlling another bus. */ - @FixedWidth(from = 84, to = 90) - @Parsed private double desiredVoltage; /** * Maximum MVAR or voltage limit */ - @FixedWidth(from = 90, to = 98) - @Parsed private double maxReactivePowerOrVoltageLimit; /** * Minimum MVAR or voltage limit */ - @FixedWidth(from = 98, to = 106) - @Parsed private double minReactivePowerOrVoltageLimit; /** * Shunt conductance G (per unit) */ - @FixedWidth(from = 106, to = 114) - @Parsed private double shuntConductance; /** * Shunt susceptance B (per unit) */ - @FixedWidth(from = 114, to = 122) - @Parsed private double shuntSusceptance; /** * Remote controlled bus number */ - @FixedWidth(from = 123, to = 127) - @Parsed private int remoteControlledBusNumber; - @FixedWidth(from = 127, to = 133) - @Parsed - private int unused; + /** + * Additional columns + */ + private Integer unused = null; public int getNumber() { return number; @@ -333,4 +292,12 @@ public int getRemoteControlledBusNumber() { public void setRemoteControlledBusNumber(int remoteControlledBusNumber) { this.remoteControlledBusNumber = remoteControlledBusNumber; } + + public Integer getUnused() { + return unused; + } + + public void setUnused(int unused) { + this.unused = unused; + } } diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfInterchangeData.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/IeeeCdfInterchangeData.java similarity index 83% rename from ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfInterchangeData.java rename to ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/IeeeCdfInterchangeData.java index abd8e4e5bb1..cc19554a94d 100644 --- a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfInterchangeData.java +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/IeeeCdfInterchangeData.java @@ -1,14 +1,11 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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.ieeecdf.model; - -import com.univocity.parsers.annotations.FixedWidth; -import com.univocity.parsers.annotations.Parsed; +package com.powsybl.ieeecdf.model.elements; /** *

@@ -27,55 +24,41 @@ * * @author Geoffroy Jamgotchian {@literal } */ -public class IeeeCdfInterchangeData { +public class IeeeCdfInterchangeData extends AbstractIeeeElement { /** * Area number */ - @FixedWidth(from = 0, to = 2) - @Parsed private int areaNumber; /** * Interchange slack bus number */ - @FixedWidth(from = 3, to = 7) - @Parsed private int interchangeSlackBusNumber; /** * Alternate swing bus name */ - @FixedWidth(from = 8, to = 20) - @Parsed private String alternateSwingBusName; /** * Area interchange export, MW */ - @FixedWidth(from = 20, to = 28) - @Parsed private double areaInterchangeExport; /** * Area interchange tolerance, MW */ - @FixedWidth(from = 29, to = 35) - @Parsed private double areaInterchangeTolerance; /** * Area code (abbreviated name) */ - @FixedWidth(from = 37, to = 43) - @Parsed private String areaCode; /** * Area name */ - @FixedWidth(from = 45, to = 75) - @Parsed private String areaName; public int getAreaNumber() { diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfLossZone.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/IeeeCdfLossZone.java similarity index 75% rename from ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfLossZone.java rename to ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/IeeeCdfLossZone.java index 3c7e433e788..ec95b9d0a60 100644 --- a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfLossZone.java +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/IeeeCdfLossZone.java @@ -1,14 +1,11 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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.ieeecdf.model; - -import com.univocity.parsers.annotations.FixedWidth; -import com.univocity.parsers.annotations.Parsed; +package com.powsybl.ieeecdf.model.elements; /** *

@@ -22,20 +19,16 @@ * * @author Geoffroy Jamgotchian {@literal } */ -public class IeeeCdfLossZone { +public class IeeeCdfLossZone extends AbstractIeeeElement { /** * Loss zone number */ - @FixedWidth(from = 0, to = 3) - @Parsed private int number; /** * Loss zone name */ - @FixedWidth(from = 4, to = 16) - @Parsed private String name; public int getNumber() { diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfTieLine.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/IeeeCdfTieLine.java similarity index 81% rename from ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfTieLine.java rename to ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/IeeeCdfTieLine.java index 22f6ff70789..1904681d6e3 100644 --- a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfTieLine.java +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/IeeeCdfTieLine.java @@ -1,14 +1,11 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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.ieeecdf.model; - -import com.univocity.parsers.annotations.FixedWidth; -import com.univocity.parsers.annotations.Parsed; +package com.powsybl.ieeecdf.model.elements; /** *

@@ -25,41 +22,31 @@ * * @author Geoffroy Jamgotchian {@literal } */ -public class IeeeCdfTieLine { +public class IeeeCdfTieLine extends AbstractIeeeElement { /** * Metered bus number */ - @FixedWidth(from = 0, to = 4) - @Parsed private int meteredBusNumber; /** * Metered area number */ - @FixedWidth(from = 6, to = 8) - @Parsed private int meteredAreaNumber; /** * Non-metered bus number */ - @FixedWidth(from = 10, to = 14) - @Parsed private int nonMeteredBusNumber; /** * Non-metered area number */ - @FixedWidth(from = 16, to = 18) - @Parsed private int nonMeteredAreaNumber; /** * Circuit number */ - @FixedWidth(from = 20, to = 21) - @Parsed private int circuitNumber; public int getMeteredBusNumber() { diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfTitle.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/IeeeCdfTitle.java similarity index 76% rename from ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfTitle.java rename to ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/IeeeCdfTitle.java index 6c17e62cec1..d256555d5d2 100644 --- a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/IeeeCdfTitle.java +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/elements/IeeeCdfTitle.java @@ -1,15 +1,11 @@ -/** - * Copyright (c) 2019, RTE (http://www.rte-france.com) +/* + * Copyright (c) 2019-2025, 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.ieeecdf.model; - -import com.univocity.parsers.annotations.Convert; -import com.univocity.parsers.annotations.FixedWidth; -import com.univocity.parsers.annotations.Parsed; +package com.powsybl.ieeecdf.model.elements; import java.time.LocalDate; @@ -29,7 +25,7 @@ * * @author Geoffroy Jamgotchian {@literal } */ -public class IeeeCdfTitle { +public class IeeeCdfTitle extends AbstractIeeeElement { public enum Season { SUMMER, @@ -39,45 +35,31 @@ public enum Season { /** * Date */ - @FixedWidth(from = 1, to = 10) - @Parsed - @Convert(conversionClass = LocalDateConversion.class) private LocalDate date; /** * Originator's name */ - @FixedWidth(from = 10, to = 30) - @Parsed private String originatorName; /** * MVA Base */ - @FixedWidth(from = 31, to = 37) - @Parsed private double mvaBase; /** * Year */ - @FixedWidth(from = 38, to = 42) - @Parsed private int year; /** * Season */ - @FixedWidth(from = 43, to = 44) - @Parsed - @Convert(conversionClass = SeasonConversion.class) private Season season; /** * Case identification */ - @FixedWidth(from = 45, to = 73) - @Parsed private String caseIdentification; public LocalDate getDate() { diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/AbstractIeeeCdfReader.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/AbstractIeeeCdfReader.java new file mode 100644 index 00000000000..2b9b23b5b42 --- /dev/null +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/AbstractIeeeCdfReader.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2025, 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.ieeecdf.model.reader; + +import com.powsybl.ieeecdf.model.elements.AbstractIeeeElement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.DoubleConsumer; +import java.util.function.Function; +import java.util.function.IntConsumer; + +/** + * @author Nicolas Rol {@literal } + */ +public abstract class AbstractIeeeCdfReader { + + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractIeeeCdfReader.class); + + protected AbstractIeeeCdfReader() { + } + + protected static List readLines(BufferedReader reader, int footerValue, + Function constructor, + int expectedItemsNumber) throws IOException { + List ieeeElements = new ArrayList<>(); + String currentLine; + while ((currentLine = reader.readLine()) != null) { + if (currentLine.startsWith(String.valueOf(footerValue))) { + break; // fin de section + } + ieeeElements.add(constructor.apply(currentLine)); + } + if (ieeeElements.size() != expectedItemsNumber) { + LOGGER.warn("Wrong number of elements parsed in the IEEE-CDF file: {} (expected {})", ieeeElements.size(), expectedItemsNumber); + } + return ieeeElements; + } + + protected static void readInteger(String line, int start, int end, IntConsumer consumer) { + if (start < line.length() + 1) { + String value = line.substring(start - 1, Math.min(end, line.length())).trim(); + if (!value.isEmpty()) { + consumer.accept(Integer.parseInt(value)); + } + } + } + + protected static void readInteger(String line, int index, IntConsumer consumer) { + readInteger(line, index, index, consumer); + } + + protected static void readDouble(String line, int start, int end, DoubleConsumer consumer) { + if (start < line.length() + 1) { + String value = line.substring(start - 1, Math.min(end, line.length())).trim(); + if (!value.isEmpty()) { + consumer.accept(Double.parseDouble(value)); + } + } + } + + protected static void readString(String line, int start, int end, Consumer consumer) { + if (start < line.length() + 1) { + String value = line.substring(start - 1, Math.min(end, line.length())).trim(); + if (!value.isEmpty()) { + consumer.accept(value.trim()); + } + } + } + + protected static void readString(String line, int index, Consumer consumer) { + readString(line, index, index, consumer); + } +} diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/IeeeCdfBranchReader.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/IeeeCdfBranchReader.java new file mode 100644 index 00000000000..2a7a20309fe --- /dev/null +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/IeeeCdfBranchReader.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025, 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.ieeecdf.model.reader; + +import com.powsybl.ieeecdf.model.elements.IeeeCdfBranch; +import com.powsybl.ieeecdf.model.conversion.BranchSideConversion; +import com.powsybl.ieeecdf.model.conversion.BranchTypeConversion; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.List; + +/** + * @author Nicolas Rol {@literal } + */ +public final class IeeeCdfBranchReader extends AbstractIeeeCdfReader { + + private IeeeCdfBranchReader() { + // private constructor to prevent instantiation + super(); + } + + public static List parseBranches(BufferedReader reader, int expectedItemsNumber) throws IOException { + return readLines(reader, -999, IeeeCdfBranchReader::parseBranch, expectedItemsNumber); + } + + private static IeeeCdfBranch parseBranch(String line) { + IeeeCdfBranch branch = new IeeeCdfBranch(); + readInteger(line, 1, 4, branch::setTapBusNumber); + readInteger(line, 6, 9, branch::setzBusNumber); + readInteger(line, 11, 12, branch::setArea); + readInteger(line, 14, 15, branch::setLossZone); + readInteger(line, 17, branch::setCircuit); + readString(line, 19, type -> branch.setType(BranchTypeConversion.fromString(type))); + readDouble(line, 20, 29, branch::setResistance); + readDouble(line, 30, 39, branch::setReactance); + readDouble(line, 41, 49, branch::setChargingSusceptance); + readInteger(line, 51, 55, branch::setRating1); + readInteger(line, 57, 61, branch::setRating2); + readInteger(line, 63, 67, branch::setRating3); + readInteger(line, 69, 72, branch::setControlBusNumber); + readString(line, 74, side -> branch.setSide(BranchSideConversion.fromString(side))); + readDouble(line, 77, 82, branch::setFinalTurnsRatio); + readDouble(line, 84, 90, branch::setFinalAngle); + readDouble(line, 91, 97, branch::setMinTapOrPhaseShift); + readDouble(line, 98, 104, branch::setMaxTapOrPhaseShift); + readDouble(line, 105, 111, branch::setStepSize); + try { + readDouble(line, 113, 119, branch::setMinVoltageActiveOrReactivePowerLimit); + } catch (NumberFormatException e) { + // In some cases, this column is one character shorter than usual + readDouble(line, 113, 118, branch::setMinVoltageActiveOrReactivePowerLimit); + } + readDouble(line, 120, 126, branch::setMaxVoltageActiveOrReactivePowerLimit); + readInteger(line, 127, 133, branch::setUnused); + return branch; + } +} diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/IeeeCdfBusReader.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/IeeeCdfBusReader.java new file mode 100644 index 00000000000..3e2fbd1a9e0 --- /dev/null +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/IeeeCdfBusReader.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025, 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.ieeecdf.model.reader; + +import com.powsybl.ieeecdf.model.elements.IeeeCdfBus; +import com.powsybl.ieeecdf.model.conversion.BusTypeConversion; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.List; + +/** + * @author Nicolas Rol {@literal } + */ +public final class IeeeCdfBusReader extends AbstractIeeeCdfReader { + + private IeeeCdfBusReader() { + // private constructor to prevent instantiation + super(); + } + + public static List parseBuses(BufferedReader reader, int expectedItemsNumber) throws IOException { + return readLines(reader, -999, IeeeCdfBusReader::parseBus, expectedItemsNumber); + } + + private static IeeeCdfBus parseBus(String line) { + IeeeCdfBus bus = new IeeeCdfBus(); + readInteger(line, 1, 4, bus::setNumber); + readString(line, 6, 17, bus::setName); + readInteger(line, 19, 20, bus::setAreaNumber); + readInteger(line, 21, 23, bus::setLossZoneNumber); + readString(line, 25, 26, type -> bus.setType(BusTypeConversion.fromString(type))); + readDouble(line, 28, 33, bus::setFinalVoltage); + readDouble(line, 34, 40, bus::setFinalAngle); + readDouble(line, 41, 49, bus::setActiveLoad); + readDouble(line, 50, 58, bus::setReactiveLoad); + readDouble(line, 59, 67, bus::setActiveGeneration); + readDouble(line, 68, 75, bus::setReactiveGeneration); + readDouble(line, 77, 83, bus::setBaseVoltage); + readDouble(line, 85, 90, bus::setDesiredVoltage); + readDouble(line, 91, 98, bus::setMaxReactivePowerOrVoltageLimit); + readDouble(line, 99, 106, bus::setMinReactivePowerOrVoltageLimit); + readDouble(line, 107, 114, bus::setShuntConductance); + readDouble(line, 115, 122, bus::setShuntSusceptance); + readInteger(line, 124, 127, bus::setRemoteControlledBusNumber); + readInteger(line, 128, 132, bus::setUnused); + return bus; + } +} diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/IeeeCdfInterchangeDataReader.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/IeeeCdfInterchangeDataReader.java new file mode 100644 index 00000000000..1f961f40d17 --- /dev/null +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/IeeeCdfInterchangeDataReader.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025, 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.ieeecdf.model.reader; + +import com.powsybl.ieeecdf.model.elements.IeeeCdfInterchangeData; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.List; + +/** + * @author Nicolas Rol {@literal } + */ +public final class IeeeCdfInterchangeDataReader extends AbstractIeeeCdfReader { + + private IeeeCdfInterchangeDataReader() { + // private constructor to prevent instantiation + super(); + } + + public static List parseInterchangeData(BufferedReader reader, int expectedItemsNumber) throws IOException { + return readLines(reader, -9, IeeeCdfInterchangeDataReader::parseInterchangeData, expectedItemsNumber); + } + + private static IeeeCdfInterchangeData parseInterchangeData(String line) { + IeeeCdfInterchangeData interchangeData = new IeeeCdfInterchangeData(); + readInteger(line, 1, 2, interchangeData::setAreaNumber); + readInteger(line, 4, 7, interchangeData::setInterchangeSlackBusNumber); + readString(line, 9, 20, interchangeData::setAlternateSwingBusName); + readDouble(line, 21, 28, interchangeData::setAreaInterchangeExport); + readDouble(line, 29, 35, interchangeData::setAreaInterchangeTolerance); + readString(line, 38, 43, interchangeData::setAreaCode); + readString(line, 46, 75, interchangeData::setAreaName); + return interchangeData; + } +} diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/IeeeCdfLossZoneReader.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/IeeeCdfLossZoneReader.java new file mode 100644 index 00000000000..1e3a27a2223 --- /dev/null +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/IeeeCdfLossZoneReader.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025, 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.ieeecdf.model.reader; + +import com.powsybl.ieeecdf.model.elements.IeeeCdfLossZone; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.List; + +/** + * @author Nicolas Rol {@literal } + */ +public final class IeeeCdfLossZoneReader extends AbstractIeeeCdfReader { + + private IeeeCdfLossZoneReader() { + // private constructor to prevent instantiation + super(); + } + + public static List parseLossZones(BufferedReader reader, int expectedItemsNumber) throws IOException { + return readLines(reader, -99, IeeeCdfLossZoneReader::parseLossZone, expectedItemsNumber); + } + + private static IeeeCdfLossZone parseLossZone(String line) { + IeeeCdfLossZone lossZone = new IeeeCdfLossZone(); + readInteger(line, 1, 3, lossZone::setNumber); + readString(line, 5, 16, lossZone::setName); + return lossZone; + } + +} diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/IeeeCdfTieLineReader.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/IeeeCdfTieLineReader.java new file mode 100644 index 00000000000..89c0dec65b2 --- /dev/null +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/IeeeCdfTieLineReader.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025, 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.ieeecdf.model.reader; + +import com.powsybl.ieeecdf.model.elements.IeeeCdfTieLine; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.List; + +/** + * @author Nicolas Rol {@literal } + */ +public final class IeeeCdfTieLineReader extends AbstractIeeeCdfReader { + + private IeeeCdfTieLineReader() { + // private constructor to prevent instantiation + super(); + } + + public static List parseTieLine(BufferedReader reader, int expectedItemsNumber) throws IOException { + return readLines(reader, -999, IeeeCdfTieLineReader::parseTieLine, expectedItemsNumber); + } + + private static IeeeCdfTieLine parseTieLine(String line) { + IeeeCdfTieLine tieLine = new IeeeCdfTieLine(); + readInteger(line, 1, 4, tieLine::setMeteredBusNumber); + readInteger(line, 7, 8, tieLine::setMeteredAreaNumber); + readInteger(line, 11, 14, tieLine::setNonMeteredBusNumber); + readInteger(line, 17, 18, tieLine::setNonMeteredAreaNumber); + readInteger(line, 21, tieLine::setCircuitNumber); + return tieLine; + } +} diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/IeeeCdfTitleReader.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/IeeeCdfTitleReader.java new file mode 100644 index 00000000000..52bb85e57a4 --- /dev/null +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/reader/IeeeCdfTitleReader.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025, 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.ieeecdf.model.reader; + +import com.powsybl.ieeecdf.model.conversion.LocalDateConversion; +import com.powsybl.ieeecdf.model.conversion.SeasonConversion; +import com.powsybl.ieeecdf.model.elements.IeeeCdfTitle; + +import java.io.BufferedReader; +import java.io.IOException; + +/** + * @author Nicolas Rol {@literal } + */ +public final class IeeeCdfTitleReader extends AbstractIeeeCdfReader { + + private IeeeCdfTitleReader() { + // private constructor to prevent instantiation + super(); + } + + public static IeeeCdfTitle parseTitle(BufferedReader reader) throws IOException { + String titleLine = reader.readLine(); + return titleLine == null ? null : parseTitle(titleLine); + } + + private static IeeeCdfTitle parseTitle(String line) { + IeeeCdfTitle title = new IeeeCdfTitle(); + readString(line, 2, 9, date -> title.setDate(LocalDateConversion.fromString(date))); + readString(line, 11, 30, title::setOriginatorName); + readDouble(line, 32, 37, title::setMvaBase); + readInteger(line, 39, 42, title::setYear); + readString(line, 44, season -> title.setSeason(SeasonConversion.fromString(season))); + readString(line, 46, 73, title::setCaseIdentification); + return title; + } +} diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/AbstractIeeeCdfWriter.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/AbstractIeeeCdfWriter.java new file mode 100644 index 00000000000..d45df6cf721 --- /dev/null +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/AbstractIeeeCdfWriter.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2025, 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.ieeecdf.model.writer; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.text.DecimalFormat; +import java.util.List; + +/** + * @author Nicolas Rol {@literal } + */ +public abstract class AbstractIeeeCdfWriter { + + protected static final String FILLER = " "; + protected static final String FILLER2 = FILLER + FILLER; + private static final DecimalFormat DF = new DecimalFormat(); + + protected AbstractIeeeCdfWriter() { + // private constructor to prevent instantiation + DF.setGroupingUsed(false); + } + + protected static void writeFooter(BufferedWriter writer, int footerValue) throws IOException { + writer.write(String.valueOf(footerValue)); + writer.newLine(); + } + + protected static void writeHeader(BufferedWriter writer, String header, List elements) throws IOException { + writer.write(String.format(header, elements.size())); + writer.newLine(); + } + + protected static String toString(int value, int index) { + return toString(value, index, index, true); + } + + protected static String toString(int value, int start, int end, boolean alignedToTheLeft) { + return pad(Integer.toString(value), end - start + 1, alignedToTheLeft); + } + + protected static String toString(double value, int start, int end, boolean alignedToTheLeft) { + return pad(Double.toString(value), end - start + 1, alignedToTheLeft); + } + + protected static String toString(String value, int index) { + return toString(value, index, index, true); + } + + protected static String toString(String value, int start, int end, boolean alignedToTheLeft) { + return pad(value, end - start + 1, alignedToTheLeft); + } + + private static String pad(String s, int width, boolean leftAlign) { + int len = s.length(); + if (len == width) { + return s; // exact fit + } + if (len > width) { + return s.substring(0, width); // truncate + } + + int pad = width - len; + StringBuilder sb = new StringBuilder(width); + + if (leftAlign) { + sb.append(s); + sb.append(" ".repeat(pad)); + } else { + sb.append(" ".repeat(pad)); + sb.append(s); + } + return sb.toString(); + } +} diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/IeeeCdfBranchWriter.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/IeeeCdfBranchWriter.java new file mode 100644 index 00000000000..a86668ac58b --- /dev/null +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/IeeeCdfBranchWriter.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2025, 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.ieeecdf.model.writer; + +import com.powsybl.ieeecdf.model.conversion.BranchSideConversion; +import com.powsybl.ieeecdf.model.conversion.BranchTypeConversion; +import com.powsybl.ieeecdf.model.elements.IeeeCdfBranch; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.List; + +/** + * @author Nicolas Rol {@literal } + */ +public final class IeeeCdfBranchWriter extends AbstractIeeeCdfWriter { + + private IeeeCdfBranchWriter() { + // private constructor to prevent instantiation + } + + public static void writeBranches(BufferedWriter writer, List branchList) throws IOException { + writeHeader(writer, "BRANCH DATA FOLLOWS %d ITEMS", branchList); + for (IeeeCdfBranch bean : branchList) { + writer.write(convertBranchToLine(bean)); + writer.newLine(); + } + writeFooter(writer, -999); + } + + private static String convertBranchToLine(IeeeCdfBranch branch) { + return toString(branch.getTapBusNumber(), 1, 4, false) + + FILLER + + toString(branch.getzBusNumber(), 6, 9, true) + + FILLER + + toString(branch.getArea(), 11, 12, true) + + FILLER + + toString(branch.getLossZone(), 14, 15, true) + + FILLER + + toString(branch.getCircuit(), 17) + + FILLER + + toString(BranchTypeConversion.revert(branch.getType()), 19) + + toString(branch.getResistance(), 20, 29, true) + + toString(branch.getReactance(), 30, 39, true) + + FILLER + + toString(branch.getChargingSusceptance(), 41, 49, true) + + FILLER + + toString(branch.getRating1(), 51, 55, true) + + FILLER + + toString(branch.getRating2(), 57, 61, true) + + FILLER + + toString(branch.getRating3(), 63, 67, true) + + FILLER + + toString(branch.getControlBusNumber(), 69, 72, true) + + FILLER + + toString(BranchSideConversion.revert(branch.getSide()), 74) + + FILLER2 + + toString(branch.getFinalTurnsRatio(), 77, 82, true) + + FILLER + + toString(branch.getFinalAngle(), 84, 90, true) + + toString(branch.getMinTapOrPhaseShift(), 91, 97, true) + + toString(branch.getMaxTapOrPhaseShift(), 98, 104, true) + + toString(branch.getStepSize(), 105, 111, true) + + FILLER + + toString(branch.getMinVoltageActiveOrReactivePowerLimit(), 113, 119, true) + + toString(branch.getMaxVoltageActiveOrReactivePowerLimit(), 120, 126, true) + + toString(branch.getUnused(), 127, 133, true); + } +} diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/IeeeCdfBusWriter.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/IeeeCdfBusWriter.java new file mode 100644 index 00000000000..f1e25ddaa73 --- /dev/null +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/IeeeCdfBusWriter.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025, 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.ieeecdf.model.writer; + +import com.powsybl.ieeecdf.model.conversion.BusTypeConversion; +import com.powsybl.ieeecdf.model.elements.IeeeCdfBus; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.List; + +/** + * @author Nicolas Rol {@literal } + */ +public final class IeeeCdfBusWriter extends AbstractIeeeCdfWriter { + + private IeeeCdfBusWriter() { + // private constructor to prevent instantiation + } + + public static void writeBuses(BufferedWriter writer, List busList) throws IOException { + writeHeader(writer, "BUS DATA FOLLOWS %d ITEMS", busList); + for (IeeeCdfBus bean : busList) { + writer.write(convertBusToLins(bean)); + writer.newLine(); + } + writeFooter(writer, -999); + } + + private static String convertBusToLins(IeeeCdfBus bus) { + return toString(bus.getNumber(), 1, 4, false) + + FILLER + + toString(bus.getName(), 6, 17, true) + + FILLER + + toString(bus.getAreaNumber(), 19, 20, true) + + toString(bus.getLossZoneNumber(), 21, 23, true) + + FILLER + + toString(BusTypeConversion.revert(bus.getType()), 25, 26, true) + + FILLER + + toString(bus.getFinalVoltage(), 28, 33, true) + + toString(bus.getFinalAngle(), 34, 40, true) + + toString(bus.getActiveLoad(), 41, 49, true) + + toString(bus.getReactiveLoad(), 50, 58, true) + + toString(bus.getActiveGeneration(), 59, 67, true) + + toString(bus.getReactiveGeneration(), 68, 75, true) + + FILLER + + toString(bus.getBaseVoltage(), 77, 83, true) + + FILLER + + toString(bus.getDesiredVoltage(), 85, 90, true) + + toString(bus.getMaxReactivePowerOrVoltageLimit(), 91, 98, true) + + toString(bus.getMinReactivePowerOrVoltageLimit(), 99, 106, true) + + toString(bus.getShuntConductance(), 107, 114, true) + + toString(bus.getShuntSusceptance(), 115, 122, true) + + FILLER + + toString(bus.getRemoteControlledBusNumber(), 124, 127, true) + + (bus.getUnused() != null ? toString(bus.getUnused(), 128, 132, true) : ""); + } +} diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/IeeeCdfInterchangeDataWriter.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/IeeeCdfInterchangeDataWriter.java new file mode 100644 index 00000000000..511b08b190a --- /dev/null +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/IeeeCdfInterchangeDataWriter.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025, 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.ieeecdf.model.writer; + +import com.powsybl.ieeecdf.model.elements.IeeeCdfInterchangeData; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.List; + +/** + * @author Nicolas Rol {@literal } + */ +public final class IeeeCdfInterchangeDataWriter extends AbstractIeeeCdfWriter { + + private IeeeCdfInterchangeDataWriter() { + // private constructor to prevent instantiation + } + + public static void writeInterchangeData(BufferedWriter writer, List interchangeDataList) throws IOException { + writeHeader(writer, "INTERCHANGE DATA FOLLOWS %d ITEMS", interchangeDataList); + for (IeeeCdfInterchangeData bean : interchangeDataList) { + writer.write(convertInterchangeDataToLine(bean)); + writer.newLine(); + } + writeFooter(writer, -9); + } + + private static String convertInterchangeDataToLine(IeeeCdfInterchangeData interchangeData) { + return toString(interchangeData.getAreaNumber(), 1, 2, false) + + FILLER + + toString(interchangeData.getInterchangeSlackBusNumber(), 4, 7, true) + + FILLER + + toString(interchangeData.getAlternateSwingBusName(), 9, 20, true) + + toString(interchangeData.getAreaInterchangeExport(), 21, 28, true) + + toString(interchangeData.getAreaInterchangeTolerance(), 29, 35, true) + + FILLER2 + + toString(interchangeData.getAreaCode(), 38, 43, true) + + FILLER2 + + toString(interchangeData.getAreaName(), 46, 75, true); + } +} diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/IeeeCdfLossZoneWriter.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/IeeeCdfLossZoneWriter.java new file mode 100644 index 00000000000..955342bdde9 --- /dev/null +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/IeeeCdfLossZoneWriter.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025, 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.ieeecdf.model.writer; + +import com.powsybl.ieeecdf.model.elements.IeeeCdfLossZone; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.List; + +/** + * @author Nicolas Rol {@literal } + */ +public final class IeeeCdfLossZoneWriter extends AbstractIeeeCdfWriter { + + private IeeeCdfLossZoneWriter() { + // private constructor to prevent instantiation + } + + public static void writeLossZone(BufferedWriter writer, List lossZoneList) throws IOException { + writeHeader(writer, "LOSS ZONES FOLLOWS %d ITEMS", lossZoneList); + for (IeeeCdfLossZone bean : lossZoneList) { + writer.write(convertLossZoneToLine(bean)); + writer.newLine(); + } + writeFooter(writer, -99); + } + + private static String convertLossZoneToLine(IeeeCdfLossZone lossZone) { + return toString(lossZone.getNumber(), 1, 3, false) + + FILLER + + toString(lossZone.getName(), 5, 16, true); + } +} diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/IeeeCdfTieLineWriter.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/IeeeCdfTieLineWriter.java new file mode 100644 index 00000000000..5a924eefdd5 --- /dev/null +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/IeeeCdfTieLineWriter.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025, 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.ieeecdf.model.writer; + +import com.powsybl.ieeecdf.model.elements.IeeeCdfTieLine; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.List; + +/** + * @author Nicolas Rol {@literal } + */ +public final class IeeeCdfTieLineWriter extends AbstractIeeeCdfWriter { + + private IeeeCdfTieLineWriter() { + // private constructor to prevent instantiation + } + + public static void writeTieLines(BufferedWriter writer, List tieLineList) throws IOException { + writeHeader(writer, "TIE LINES FOLLOWS %d ITEMS", tieLineList); + for (IeeeCdfTieLine bean : tieLineList) { + writer.write(convertTieLineToLine(bean)); + writer.newLine(); + } + writeFooter(writer, -999); + } + + private static String convertTieLineToLine(IeeeCdfTieLine tieLine) { + return toString(tieLine.getMeteredBusNumber(), 1, 4, false) + + FILLER2 + + toString(tieLine.getMeteredAreaNumber(), 7, 8, true) + + FILLER2 + + toString(tieLine.getNonMeteredBusNumber(), 11, 14, true) + + FILLER2 + + toString(tieLine.getNonMeteredAreaNumber(), 17, 18, true) + + FILLER2 + + toString(tieLine.getCircuitNumber(), 21); + + } +} diff --git a/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/IeeeCdfTitleWriter.java b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/IeeeCdfTitleWriter.java new file mode 100644 index 00000000000..6219bb89ac1 --- /dev/null +++ b/ieee-cdf/ieee-cdf-model/src/main/java/com/powsybl/ieeecdf/model/writer/IeeeCdfTitleWriter.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025, 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.ieeecdf.model.writer; + +import com.powsybl.ieeecdf.model.conversion.LocalDateConversion; +import com.powsybl.ieeecdf.model.conversion.SeasonConversion; +import com.powsybl.ieeecdf.model.elements.IeeeCdfTitle; + +import java.io.BufferedWriter; +import java.io.IOException; + +/** + * @author Nicolas Rol {@literal } + */ +public final class IeeeCdfTitleWriter extends AbstractIeeeCdfWriter { + + private IeeeCdfTitleWriter() { + // private constructor to prevent instantiation + } + + public static void writeTitle(BufferedWriter writer, IeeeCdfTitle title) throws IOException { + writer.write(convertToLine(title)); + writer.newLine(); + } + + private static String convertToLine(IeeeCdfTitle title) { + return FILLER + + toString(LocalDateConversion.revert(title.getDate()), 2, 9, true) + + FILLER + + toString(title.getOriginatorName(), 11, 30, true) + + FILLER + + toString(title.getMvaBase(), 32, 37, true) + + FILLER + + toString(title.getYear(), 39, 42, true) + + FILLER + + toString(SeasonConversion.revert(title.getSeason()), 44) + + FILLER + + toString(title.getCaseIdentification(), 46, 73, true); + } +} diff --git a/ieee-cdf/ieee-cdf-model/src/test/java/com/powsybl/ieeecdf/model/IeeeCdfReaderWriterTest.java b/ieee-cdf/ieee-cdf-model/src/test/java/com/powsybl/ieeecdf/model/IeeeCdfReaderWriterTest.java index 9f3fda8eb7a..29f9208f9a0 100644 --- a/ieee-cdf/ieee-cdf-model/src/test/java/com/powsybl/ieeecdf/model/IeeeCdfReaderWriterTest.java +++ b/ieee-cdf/ieee-cdf-model/src/test/java/com/powsybl/ieeecdf/model/IeeeCdfReaderWriterTest.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; +import com.powsybl.ieeecdf.model.elements.IeeeCdfTieLine; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -24,6 +25,7 @@ import java.nio.file.FileSystem; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Objects; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -50,7 +52,7 @@ void tearDown() throws Exception { private void testIeeeFile(String fileName) throws IOException { IeeeCdfModel model; // read - try (BufferedReader reader = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/" + fileName)))) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(getClass().getResourceAsStream("/" + fileName))))) { model = new IeeeCdfReader().read(reader); } @@ -108,10 +110,10 @@ void testIeee9zeroimpedance() throws IOException { @Test void testTieLine() throws IOException { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/tieline.txt")))) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(getClass().getResourceAsStream("/tieline.txt"))))) { IeeeCdfModel model = new IeeeCdfReader().read(reader); assertEquals(1, model.getTieLines().size()); - IeeeCdfTieLine tieLine = model.getTieLines().get(0); + IeeeCdfTieLine tieLine = model.getTieLines().getFirst(); assertEquals(1, tieLine.getMeteredBusNumber()); assertEquals(2, tieLine.getMeteredAreaNumber()); assertEquals(3, tieLine.getNonMeteredBusNumber()); diff --git a/ieee-cdf/ieee-cdf-model/src/test/resources/tieline.txt b/ieee-cdf/ieee-cdf-model/src/test/resources/tieline.txt index b9c781ea9e1..faf5a22404e 100644 --- a/ieee-cdf/ieee-cdf-model/src/test/resources/tieline.txt +++ b/ieee-cdf/ieee-cdf-model/src/test/resources/tieline.txt @@ -1,5 +1,5 @@ 11/14/19 TIELINE TEST 100.0 2019 W POWSYBL TEST CASE -TIE LINES FOLLOWS 0 ITEMS +TIE LINES FOLLOWS 1 ITEMS 1 2 3 4 5 -999 END OF DATA