diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 6e256957c..d53531c66 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -21,7 +21,7 @@ jobs: uses: actions/checkout@v1 with: repository: powsybl/powsybl-core - ref: refs/heads/main + ref: refs/tags/v6.1.0 - name: Checkout sources uses: actions/checkout@v1 diff --git a/commons/src/main/java/com/powsybl/dynawo/commons/AbstractCsvParser.java b/commons/src/main/java/com/powsybl/dynawo/commons/AbstractCsvParser.java new file mode 100644 index 000000000..2ccfed9eb --- /dev/null +++ b/commons/src/main/java/com/powsybl/dynawo/commons/AbstractCsvParser.java @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2023, 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.dynawo.commons; + +import com.powsybl.commons.PowsyblException; +import com.univocity.parsers.common.ParsingContext; +import com.univocity.parsers.common.ResultIterator; +import com.univocity.parsers.csv.CsvParser; +import com.univocity.parsers.csv.CsvParserSettings; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; + +/** + * @author Laurent Issertial {@literal } + */ +public abstract class AbstractCsvParser { + + protected static final char DEFAULT_SEPARATOR = '|'; + + private final char separator; + + protected AbstractCsvParser(char separator) { + this.separator = separator; + } + + public List parse(Path file) { + if (!Files.exists(file)) { + return Collections.emptyList(); + } + + try (BufferedReader reader = Files.newBufferedReader(file, StandardCharsets.UTF_8)) { + return parse(reader); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private List parse(BufferedReader reader) { + Objects.requireNonNull(reader); + CsvParserSettings settings = new CsvParserSettings(); + settings.getFormat().setDelimiter(separator); + settings.getFormat().setQuoteEscape('"'); + settings.getFormat().setLineSeparator(System.lineSeparator()); + settings.setMaxColumns(getNbColumns()); + CsvParser csvParser = new CsvParser(settings); + ResultIterator iterator = csvParser.iterate(reader).iterator(); + return read(iterator); + } + + protected List read(ResultIterator iterator) { + List logs = new ArrayList<>(); + int iLine = 0; + while (iterator.hasNext()) { + iLine++; + String[] tokens = iterator.next(); + if (!hasCorrectNbColumns(tokens.length)) { + throw new PowsyblException("Columns of line " + iLine + " are inconsistent"); + } + createEntry(tokens).ifPresent(logs::add); + } + return logs; + } + + protected abstract Optional createEntry(String[] tokens); + + protected abstract boolean hasCorrectNbColumns(int tokensSize); + + protected abstract int getNbColumns(); +} diff --git a/commons/src/main/java/com/powsybl/dynawo/commons/CommonReports.java b/commons/src/main/java/com/powsybl/dynawo/commons/CommonReports.java new file mode 100644 index 000000000..a5ede19af --- /dev/null +++ b/commons/src/main/java/com/powsybl/dynawo/commons/CommonReports.java @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2023, 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.dynawo.commons; + +import com.powsybl.commons.reporter.Report; +import com.powsybl.commons.reporter.Reporter; +import com.powsybl.commons.reporter.TypedValue; +import com.powsybl.dynawo.commons.dynawologs.LogEntry; +import com.powsybl.dynawo.commons.timeline.TimelineEntry; + +/** + * @author Laurent Issertial {@literal } + */ +public final class CommonReports { + + private static final String TIME_MS = "timeMsTypedValue"; + private static final String ID = "idTypedValue"; + + private CommonReports() { + } + + public static Reporter createDynawoLogReporter(Reporter reporter) { + return reporter.createSubReporter("dynawoLog", + "Dynawo Log"); + } + + public static void reportTimelineEvent(Reporter reporter, TimelineEntry timelineEntry) { + reporter.report(Report.builder() + .withKey("DynawoTimelineEvent") + .withDefaultMessage("[t=${time}] ${message} on equipment '${identifiableId}'") + .withTypedValue("time", timelineEntry.time(), TIME_MS) + .withTypedValue("identifiableId", timelineEntry.modelName(), ID) + .withValue("message", timelineEntry.message()) + .withSeverity(TypedValue.TRACE_SEVERITY) + .build()); + } + + public static void reportLogEvent(Reporter reporter, LogEntry logEntry) { + reporter.report(Report.builder() + .withKey("DynawoTimelineEvent") + .withDefaultMessage("${message}") + .withValue("message", logEntry.message()) + .withSeverity(logEntry.severity()) + .build()); + } +} diff --git a/commons/src/main/java/com/powsybl/dynawo/commons/DynawoConstants.java b/commons/src/main/java/com/powsybl/dynawo/commons/DynawoConstants.java index 9e1eebdd9..83d077995 100644 --- a/commons/src/main/java/com/powsybl/dynawo/commons/DynawoConstants.java +++ b/commons/src/main/java/com/powsybl/dynawo/commons/DynawoConstants.java @@ -26,6 +26,8 @@ private DynawoConstants() { public static final String DYNAWO_CMD_NAME = "dynawo"; + public static final String DYNAWO_TIMELINE_FOLDER = "timeLine"; + public static final DynawoVersion VERSION_MIN = new DynawoVersion(1, 5, 0); public static final List IIDM_EXTENSIONS = List.of( diff --git a/commons/src/main/java/com/powsybl/dynawo/commons/dynawologs/CsvLogParser.java b/commons/src/main/java/com/powsybl/dynawo/commons/dynawologs/CsvLogParser.java new file mode 100644 index 000000000..43a429139 --- /dev/null +++ b/commons/src/main/java/com/powsybl/dynawo/commons/dynawologs/CsvLogParser.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2023, 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.dynawo.commons.dynawologs; + +import com.powsybl.dynawo.commons.AbstractCsvParser; + +import java.util.Optional; + +/** + * @author Laurent Issertial {@literal } + */ +public final class CsvLogParser extends AbstractCsvParser { + + private static final int NB_COLUMNS = 4; + + public CsvLogParser() { + this(DEFAULT_SEPARATOR); + } + + public CsvLogParser(char separator) { + super(separator); + } + + @Override + protected Optional createEntry(String[] tokens) { + return tokens.length == NB_COLUMNS ? LogUtils.createLog(tokens[1], tokens[2] + " " + tokens[3]) + : LogUtils.createLog(tokens[1], tokens[2]); + } + + @Override + protected boolean hasCorrectNbColumns(int tokensSize) { + return tokensSize == NB_COLUMNS - 1 || tokensSize == NB_COLUMNS; + } + + @Override + protected int getNbColumns() { + return NB_COLUMNS; + } +} diff --git a/commons/src/main/java/com/powsybl/dynawo/commons/dynawologs/LogEntry.java b/commons/src/main/java/com/powsybl/dynawo/commons/dynawologs/LogEntry.java new file mode 100644 index 000000000..928221c4f --- /dev/null +++ b/commons/src/main/java/com/powsybl/dynawo/commons/dynawologs/LogEntry.java @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2023, 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.dynawo.commons.dynawologs; + +import com.powsybl.commons.reporter.TypedValue; + +/** + * @author Laurent Issertial {@literal } + */ +public record LogEntry(TypedValue severity, String message) { + +} diff --git a/commons/src/main/java/com/powsybl/dynawo/commons/dynawologs/LogUtils.java b/commons/src/main/java/com/powsybl/dynawo/commons/dynawologs/LogUtils.java new file mode 100644 index 000000000..760c431de --- /dev/null +++ b/commons/src/main/java/com/powsybl/dynawo/commons/dynawologs/LogUtils.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2023, 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.dynawo.commons.dynawologs; + +import com.powsybl.commons.reporter.TypedValue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Optional; + +/** + * @author Laurent Issertial {@literal } + */ +public final class LogUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(LogUtils.class); + private static final String EMPTY_START = "======"; + private static final String EMPTY_BREAKER = "------"; + + private LogUtils() { + } + + public static Optional createLog(String severity, String message) { + if (severity == null) { + LOGGER.warn("Inconsistent log entry (modelName: '{}', message: '{}')", severity, message); + } else { + if (emptyMessage(message)) { + LOGGER.debug("Empty message, the entry will be skipped : {}", message); + } else { + return convertDynawoLog(severity).map(severityTypedValue -> new LogEntry(severityTypedValue, message)); + } + } + return Optional.empty(); + } + + private static Optional convertDynawoLog(String severity) { + return switch (severity) { + case "DEBUG" -> Optional.of(TypedValue.DEBUG_SEVERITY); + case "INFO" -> Optional.of(TypedValue.INFO_SEVERITY); + case "WARN" -> Optional.of(TypedValue.WARN_SEVERITY); + case "ERROR" -> Optional.of(TypedValue.ERROR_SEVERITY); + default -> { + LOGGER.warn("Inconsistent severity entry '{}'", severity); + yield Optional.empty(); + } + }; + } + + private static boolean emptyMessage(String message) { + return message == null || message.startsWith(EMPTY_BREAKER) || message.startsWith(EMPTY_START); + } +} diff --git a/commons/src/main/java/com/powsybl/dynawo/commons/timeline/CsvTimeLineParser.java b/commons/src/main/java/com/powsybl/dynawo/commons/timeline/CsvTimeLineParser.java index 473fff818..70b3e4a52 100644 --- a/commons/src/main/java/com/powsybl/dynawo/commons/timeline/CsvTimeLineParser.java +++ b/commons/src/main/java/com/powsybl/dynawo/commons/timeline/CsvTimeLineParser.java @@ -7,80 +7,37 @@ */ package com.powsybl.dynawo.commons.timeline; -import com.powsybl.commons.PowsyblException; -import com.univocity.parsers.common.ParsingContext; -import com.univocity.parsers.common.ResultIterator; -import com.univocity.parsers.csv.CsvParser; -import com.univocity.parsers.csv.CsvParserSettings; +import com.powsybl.dynawo.commons.AbstractCsvParser; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; +import java.util.Optional; /** * @author Laurent Issertial {@literal } */ -public final class CsvTimeLineParser implements TimeLineParser { +public final class CsvTimeLineParser extends AbstractCsvParser implements TimeLineParser { private static final int NB_COLUMNS = 3; - private final char separator; public CsvTimeLineParser() { - this('|'); + this(DEFAULT_SEPARATOR); } public CsvTimeLineParser(char separator) { - this.separator = separator; + super(separator); } - public List parse(Path file) { - return parse(file, separator); + @Override + protected Optional createEntry(String[] tokens) { + return TimeLineUtil.createEvent(tokens[0], tokens[1], tokens[2]); } - public static List parse(Path file, char separator) { - if (!Files.exists(file)) { - return Collections.emptyList(); - } - - try (BufferedReader reader = Files.newBufferedReader(file, StandardCharsets.UTF_8)) { - return parse(reader, separator); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - static List parse(BufferedReader reader, char separator) { - Objects.requireNonNull(reader); - CsvParserSettings settings = new CsvParserSettings(); - settings.getFormat().setDelimiter(separator); - settings.getFormat().setQuoteEscape('"'); - settings.getFormat().setLineSeparator(System.lineSeparator()); - settings.setMaxColumns(NB_COLUMNS); - CsvParser csvParser = new CsvParser(settings); - ResultIterator iterator = csvParser.iterate(reader).iterator(); - return read(iterator); + @Override + protected boolean hasCorrectNbColumns(int tokensSize) { + return NB_COLUMNS == tokensSize; } - static List read(ResultIterator iterator) { - List timeline = new ArrayList<>(); - int iLine = 0; - while (iterator.hasNext()) { - iLine++; - String[] tokens = iterator.next(); - if (tokens.length != NB_COLUMNS) { - throw new PowsyblException("Columns of line " + iLine + " are inconsistent"); - } - TimeLineUtil.createEvent(tokens[0], tokens[1], tokens[2]) - .ifPresent(timeline::add); - } - return timeline; + @Override + protected int getNbColumns() { + return NB_COLUMNS; } - } diff --git a/commons/src/test/java/com/powsybl/dynawo/commons/dynawologs/CsvLogParserTest.java b/commons/src/test/java/com/powsybl/dynawo/commons/dynawologs/CsvLogParserTest.java new file mode 100644 index 000000000..f9fc16b28 --- /dev/null +++ b/commons/src/test/java/com/powsybl/dynawo/commons/dynawologs/CsvLogParserTest.java @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2023, 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.dynawo.commons.dynawologs; + +import com.powsybl.commons.reporter.TypedValue; +import org.junit.jupiter.api.Test; + +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.util.List; +import java.util.Objects; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author Laurent Issertial {@literal } + */ +class CsvLogParserTest { + + @Test + void testLog() throws URISyntaxException { + + Path path = Path.of(Objects.requireNonNull(getClass().getResource("/dynawo.log")).toURI()); + List logs = new CsvLogParser().parse(path); + + assertEquals(6, logs.size()); + assertEquals("DYNAWO VERSION : 1.4.1", logs.get(0).message()); + assertEquals(TypedValue.INFO_SEVERITY, logs.get(0).severity()); + assertEquals("time iter num order (k) time step (h)", logs.get(1).message()); + assertEquals(TypedValue.INFO_SEVERITY, logs.get(1).severity()); + assertEquals("0.000 0 0 0.010", logs.get(2).message()); + assertEquals(TypedValue.INFO_SEVERITY, logs.get(2).severity()); + assertEquals("call of SolverReInit i.e. a new symbolic and numerical factorization will be performed", logs.get(3).message()); + assertEquals(TypedValue.DEBUG_SEVERITY, logs.get(3).severity()); + assertEquals("five consecutive steps have been taken that satisfy a scaled step length test", logs.get(4).message()); + assertEquals(TypedValue.WARN_SEVERITY, logs.get(4).severity()); + assertEquals("KINSOL fails to solve the problem ( DYNSolverKINAlgRestoration.cpp:394 )", logs.get(5).message()); + assertEquals(TypedValue.ERROR_SEVERITY, logs.get(5).severity()); + } +} diff --git a/commons/src/test/java/com/powsybl/dynawo/commons/timeline/CsvTimeLineParserTest.java b/commons/src/test/java/com/powsybl/dynawo/commons/timeline/CsvTimeLineParserTest.java index 91df30869..2b82a1d6a 100644 --- a/commons/src/test/java/com/powsybl/dynawo/commons/timeline/CsvTimeLineParserTest.java +++ b/commons/src/test/java/com/powsybl/dynawo/commons/timeline/CsvTimeLineParserTest.java @@ -50,8 +50,9 @@ void testTimeline(String fileName) throws URISyntaxException { @Test void testInconsistentFile() throws URISyntaxException { + CsvTimeLineParser parser = new CsvTimeLineParser('|'); Path path = Path.of(Objects.requireNonNull(getClass().getResource("/wrongTimeline.log")).toURI()); - Exception e = assertThrows(PowsyblException.class, () -> CsvTimeLineParser.parse(path, '|')); + Exception e = assertThrows(PowsyblException.class, () -> parser.parse(path)); assertEquals("Columns of line 2 are inconsistent", e.getMessage()); } } diff --git a/commons/src/test/resources/dynawo.log b/commons/src/test/resources/dynawo.log new file mode 100644 index 000000000..c6e2e7c0b --- /dev/null +++ b/commons/src/test/resources/dynawo.log @@ -0,0 +1,12 @@ +2023-11-09 11:36:53 | INFO | ============================================================ +2023-11-09 11:36:53 | INFO | DYNAWO VERSION : 1.4.1 +2023-11-09 11:36:53 | INFO | ============================================================ +2023-11-09 11:36:53 | INFO | +2023-11-13 11:36:53 | INFO | time | iter num order (k) time step (h) +2023-11-13 11:36:53 | INFO | ----------------------------------------------------------------------- +2023-11-13 11:36:53 | INFO | 0.000 | 0 0 0.010 +2023-11-09 11:36:58 | TRACE | Algebraic mode change for model CONST.TG6 at t = 0 +2023-11-09 11:36:58 | | Algebraic mode change for model CONST.TG7 at t = 0 +2023-11-09 11:36:58 | DEBUG | call of SolverReInit i.e. a new symbolic and numerical factorization will be performed +2023-11-09 11:36:59 | WARN | five consecutive steps have been taken that satisfy a scaled step length test +2023-11-09 11:36:59 | ERROR | KINSOL fails to solve the problem ( DYNSolverKINAlgRestoration.cpp:394 ) diff --git a/dynaflow/src/main/java/com/powsybl/dynaflow/DynaFlowConstants.java b/dynaflow/src/main/java/com/powsybl/dynaflow/DynaFlowConstants.java index c20c23d41..79f7287a6 100644 --- a/dynaflow/src/main/java/com/powsybl/dynaflow/DynaFlowConstants.java +++ b/dynaflow/src/main/java/com/powsybl/dynaflow/DynaFlowConstants.java @@ -21,7 +21,6 @@ public final class DynaFlowConstants { public static final String OUTPUT_IIDM_FILENAME = "outputIIDM.xml"; public static final String OUTPUT_RESULTS_FILENAME = "results.json"; static final String DYNAFLOW_OUTPUTS_FOLDER = "outputs"; - static final String DYNAWO_TIMELINE_FOLDER = "timeLine"; static final String DYNAFLOW_TIMELINE_FILE = "timeline.xml"; diff --git a/dynaflow/src/main/java/com/powsybl/dynaflow/DynaFlowProvider.java b/dynaflow/src/main/java/com/powsybl/dynaflow/DynaFlowProvider.java index 71298196e..3af269043 100644 --- a/dynaflow/src/main/java/com/powsybl/dynaflow/DynaFlowProvider.java +++ b/dynaflow/src/main/java/com/powsybl/dynaflow/DynaFlowProvider.java @@ -17,6 +17,7 @@ import com.powsybl.computation.*; import com.powsybl.dynaflow.json.DynaFlowConfigSerializer; import com.powsybl.dynaflow.json.JsonDynaFlowParametersSerializer; +import com.powsybl.dynawo.commons.CommonReports; import com.powsybl.dynawo.commons.DynawoUtil; import com.powsybl.dynawo.commons.NetworkResultsUpdater; import com.powsybl.dynawo.commons.PowsyblDynawoVersion; @@ -39,6 +40,7 @@ import static com.powsybl.dynaflow.DynaFlowConstants.*; import static com.powsybl.dynaflow.DynaFlowParameters.*; +import static com.powsybl.dynawo.commons.DynawoConstants.DYNAWO_TIMELINE_FOLDER; /** * @@ -239,7 +241,7 @@ private void reportTimeLine(Path workingDir) { .resolve(DYNAWO_TIMELINE_FOLDER) .resolve(DYNAFLOW_TIMELINE_FILE); List tl = new XmlTimeLineParser().parse(timelineFile); - tl.forEach(e -> Reports.reportTimelineEvent(dfReporter, e)); + tl.forEach(e -> CommonReports.reportTimelineEvent(dfReporter, e)); } } } diff --git a/dynaflow/src/main/java/com/powsybl/dynaflow/DynaFlowSecurityAnalysis.java b/dynaflow/src/main/java/com/powsybl/dynaflow/DynaFlowSecurityAnalysis.java index efb09524f..431b03403 100644 --- a/dynaflow/src/main/java/com/powsybl/dynaflow/DynaFlowSecurityAnalysis.java +++ b/dynaflow/src/main/java/com/powsybl/dynaflow/DynaFlowSecurityAnalysis.java @@ -17,6 +17,7 @@ import com.powsybl.contingency.json.ContingencyJsonModule; import com.powsybl.dynaflow.json.DynaFlowConfigSerializer; import com.powsybl.dynaflow.xml.ConstraintsReader; +import com.powsybl.dynawo.commons.CommonReports; import com.powsybl.dynawo.commons.DynawoUtil; import com.powsybl.dynawo.commons.timeline.TimelineEntry; import com.powsybl.dynawo.commons.timeline.XmlTimeLineParser; @@ -40,6 +41,7 @@ import static com.powsybl.dynaflow.DynaFlowConstants.CONFIG_FILENAME; import static com.powsybl.dynaflow.DynaFlowConstants.IIDM_FILENAME; +import static com.powsybl.dynawo.commons.DynawoConstants.DYNAWO_TIMELINE_FOLDER; /** * @author Luma Zamarreno {@literal } @@ -170,10 +172,10 @@ public SecurityAnalysisReport after(Path workingDir, ExecutionReport report) thr .toList(); // Report the timeline events from the timeline files written by dynawo - Path timelineDir = workingDir.resolve(DynaFlowConstants.DYNAWO_TIMELINE_FOLDER); + Path timelineDir = workingDir.resolve(DYNAWO_TIMELINE_FOLDER); contingencies.forEach(c -> { Reporter contingencyReporter = Reports.createDynaFlowTimelineReporter(reporter, c.getId()); - getTimeline(timelineDir, c).forEach(e -> Reports.reportTimelineEvent(contingencyReporter, e)); + getTimeline(timelineDir, c).forEach(e -> CommonReports.reportTimelineEvent(contingencyReporter, e)); }); return new SecurityAnalysisReport( diff --git a/dynaflow/src/main/java/com/powsybl/dynaflow/Reports.java b/dynaflow/src/main/java/com/powsybl/dynaflow/Reports.java index f4819f55d..c88b08fb3 100644 --- a/dynaflow/src/main/java/com/powsybl/dynaflow/Reports.java +++ b/dynaflow/src/main/java/com/powsybl/dynaflow/Reports.java @@ -7,17 +7,12 @@ */ package com.powsybl.dynaflow; -import com.powsybl.commons.reporter.Report; import com.powsybl.commons.reporter.Reporter; -import com.powsybl.commons.reporter.TypedValue; -import com.powsybl.dynawo.commons.timeline.TimelineEntry; /** * @author Florian Dupuy {@literal } */ public final class Reports { - private static final String TIME_MS = "timeMsTypedValue"; - private static final String ID = "idTypedValue"; private Reports() { } @@ -39,15 +34,4 @@ public static Reporter createDynaFlowTimelineReporter(Reporter reporter, String "Contingency '${contingencyId}'", "contingencyId", contingencyId); } - - public static void reportTimelineEvent(Reporter reporter, TimelineEntry timelineEntry) { - reporter.report(Report.builder() - .withKey("DynawoTimelineEvent") - .withDefaultMessage("[t=${time}] ${message} on equipment '${identifiableId}'") - .withTypedValue("time", timelineEntry.time(), TIME_MS) - .withTypedValue("identifiableId", timelineEntry.modelName(), ID) - .withValue("message", timelineEntry.message()) - .withSeverity(TypedValue.TRACE_SEVERITY) - .build()); - } } diff --git a/dynawaltz/src/main/java/com/powsybl/dynawaltz/DynaWaltzProvider.java b/dynawaltz/src/main/java/com/powsybl/dynawaltz/DynaWaltzProvider.java index 2699ed989..03263f655 100644 --- a/dynawaltz/src/main/java/com/powsybl/dynawaltz/DynaWaltzProvider.java +++ b/dynawaltz/src/main/java/com/powsybl/dynawaltz/DynaWaltzProvider.java @@ -16,13 +16,14 @@ import com.powsybl.dynawaltz.xml.DydXml; import com.powsybl.dynawaltz.xml.JobsXml; import com.powsybl.dynawaltz.xml.ParametersXml; -import com.powsybl.dynawo.commons.DynawoConstants; -import com.powsybl.dynawo.commons.DynawoUtil; -import com.powsybl.dynawo.commons.NetworkResultsUpdater; +import com.powsybl.dynawo.commons.*; import com.powsybl.dynawo.commons.PowsyblDynawoVersion; +import com.powsybl.dynawo.commons.dynawologs.CsvLogParser; import com.powsybl.dynawo.commons.loadmerge.LoadsMerger; +import com.powsybl.dynawo.commons.timeline.CsvTimeLineParser; import com.powsybl.iidm.network.Network; import com.powsybl.iidm.serde.NetworkSerDe; +import com.powsybl.timeseries.DoubleTimeSeries; import com.powsybl.timeseries.TimeSeries; import com.powsybl.timeseries.TimeSeries.TimeFormat; import com.powsybl.timeseries.TimeSeriesConstants; @@ -36,9 +37,12 @@ import java.nio.file.StandardCopyOption; import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; import static com.powsybl.dynawaltz.xml.DynaWaltzConstants.*; +import static com.powsybl.dynawo.commons.DynawoConstants.DYNAWO_TIMELINE_FOLDER; /** * @author Marcos de Miguel {@literal } @@ -51,8 +55,13 @@ public class DynaWaltzProvider implements DynamicSimulationProvider { private static final String OUTPUTS_FOLDER = "outputs"; private static final String FINAL_STATE_FOLDER = "finalState"; + private static final String LOGS_FOLDER = "logs"; private static final String OUTPUT_IIDM_FILENAME = "outputIIDM.xml"; private static final String OUTPUT_DUMP_FILENAME = "outputState.dmp"; + private static final String TIMELINE_FILENAME = "timeline.log"; + private static final String LOGS_FILENAME = "dynawaltz.log"; + private static final String ERROR_FILENAME = "dyn_fs_0.err"; + private static final String DYNAWO_ERROR_PATTERN = "DYN Error: "; private static final Logger LOGGER = LoggerFactory.getLogger(DynaWaltzProvider.class); @@ -138,19 +147,26 @@ private CompletableFuture run(Network network, DynamicM .map(BlackBoxModel.class::cast) .collect(Collectors.toList()); DynaWaltzContext context = new DynaWaltzContext(network, workingVariantId, blackBoxModels, blackBoxEventModels, curvesSupplier.get(network, dsReporter), parameters, dynaWaltzParameters, reporter); - return computationManager.execute(execEnv, new DynaWaltzHandler(context)); + return computationManager.execute(execEnv, new DynaWaltzHandler(context, reporter)); } private final class DynaWaltzHandler extends AbstractExecutionHandler { private final DynaWaltzContext context; private final Network dynawoInput; + private final Reporter reporter; - public DynaWaltzHandler(DynaWaltzContext context) { + private final List timeline = new ArrayList<>(); + private final Map curves = new HashMap<>(); + private DynamicSimulationResult.Status status = DynamicSimulationResult.Status.SUCCESS; + private String statusText = ""; + + public DynaWaltzHandler(DynaWaltzContext context, Reporter reporter) { this.context = context; this.dynawoInput = context.getDynaWaltzParameters().isMergeLoads() ? LoadsMerger.mergeLoads(context.getNetwork()) : context.getNetwork(); + this.reporter = reporter; } @Override @@ -170,38 +186,95 @@ public List before(Path workingDir) throws IOException { @Override public DynamicSimulationResult after(Path workingDir, ExecutionReport report) throws IOException { - super.after(workingDir, report); + + Path outputsFolder = workingDir.resolve(OUTPUTS_FOLDER); context.getNetwork().getVariantManager().setWorkingVariant(context.getWorkingVariantId()); DynaWaltzParameters parameters = context.getDynaWaltzParameters(); DumpFileParameters dumpFileParameters = parameters.getDumpFileParameters(); - boolean status = true; - if (parameters.isWriteFinalState()) { - Path outputNetworkFile = workingDir.resolve(OUTPUTS_FOLDER).resolve(FINAL_STATE_FOLDER).resolve(OUTPUT_IIDM_FILENAME); - if (Files.exists(outputNetworkFile)) { - NetworkResultsUpdater.update(context.getNetwork(), NetworkSerDe.read(outputNetworkFile), context.getDynaWaltzParameters().isMergeLoads()); + + setDynawoLog(outputsFolder); + // Error file + Path errorFile = workingDir.resolve(ERROR_FILENAME); + if (Files.exists(errorFile)) { + Matcher errorMatcher = Pattern.compile(DYNAWO_ERROR_PATTERN + "(.*)") + .matcher(Files.readString(errorFile)); + if (!errorMatcher.find()) { + if (parameters.isWriteFinalState()) { + updateNetwork(outputsFolder); + } + if (dumpFileParameters.exportDumpFile()) { + setDumpFile(outputsFolder, dumpFileParameters.dumpFileFolder(), workingDir.getFileName()); + } + setTimeline(outputsFolder); + if (context.withCurves()) { + setCurves(workingDir); + } } else { - status = false; + status = DynamicSimulationResult.Status.FAILURE; + statusText = errorMatcher.group().substring(DYNAWO_ERROR_PATTERN.length()); } + } else { + LOGGER.warn("Error file not found"); + status = DynamicSimulationResult.Status.FAILURE; + statusText = "Dynawo error log file not found"; } - if (dumpFileParameters.exportDumpFile()) { - Path outputDumpFile = workingDir.resolve(OUTPUTS_FOLDER).resolve(FINAL_STATE_FOLDER).resolve(OUTPUT_DUMP_FILENAME); - if (Files.exists(outputDumpFile)) { - Files.copy(outputDumpFile, dumpFileParameters.dumpFileFolder().resolve(workingDir.getFileName() + "_" + OUTPUT_DUMP_FILENAME), StandardCopyOption.REPLACE_EXISTING); - } else { - LOGGER.warn("Dump file {} not found, export will be skipped", OUTPUT_DUMP_FILENAME); - } + + return new DynamicSimulationResultImpl(status, statusText, curves, timeline); + } + + private void setDynawoLog(Path outputsFolder) { + Path logFile = outputsFolder.resolve(LOGS_FOLDER).resolve(LOGS_FILENAME); + if (Files.exists(logFile)) { + Reporter logReporter = CommonReports.createDynawoLogReporter(reporter); + new CsvLogParser().parse(logFile).forEach(e -> CommonReports.reportLogEvent(logReporter, e)); + } else { + LOGGER.warn("Dynawo logs file not found"); + } + } + + private void updateNetwork(Path outputsFolder) { + Path outputNetworkFile = outputsFolder.resolve(FINAL_STATE_FOLDER).resolve(OUTPUT_IIDM_FILENAME); + if (Files.exists(outputNetworkFile)) { + NetworkResultsUpdater.update(context.getNetwork(), NetworkSerDe.read(outputNetworkFile), context.getDynaWaltzParameters().isMergeLoads()); + } else { + LOGGER.warn("Output IIDM file not found"); + status = DynamicSimulationResult.Status.FAILURE; + statusText = "Dynawo Output IIDM file not found"; } + } + + private void setDumpFile(Path outputsFolder, Path dumpFileFolder, Path fileName) throws IOException { + Path outputDumpFile = outputsFolder.resolve(FINAL_STATE_FOLDER).resolve(OUTPUT_DUMP_FILENAME); + if (Files.exists(outputDumpFile)) { + Files.copy(outputDumpFile, dumpFileFolder.resolve(fileName + "_" + OUTPUT_DUMP_FILENAME), StandardCopyOption.REPLACE_EXISTING); + } else { + LOGGER.warn("Dump file {} not found, export will be skipped", OUTPUT_DUMP_FILENAME); + } + } + + private void setTimeline(Path outputsFolder) { + Path timelineFile = outputsFolder.resolve(DYNAWO_TIMELINE_FOLDER).resolve(TIMELINE_FILENAME); + if (Files.exists(timelineFile)) { + Reporter timelineReporter = DynawaltzReports.createDynaWaltzTimelineReporter(reporter); + new CsvTimeLineParser().parse(timelineFile).forEach(e -> { + CommonReports.reportTimelineEvent(timelineReporter, e); + timeline.add(new TimelineEvent(e.time(), e.modelName(), e.message())); + }); + } else { + LOGGER.warn("Timeline file not found"); + } + } + + private void setCurves(Path workingDir) { Path curvesPath = workingDir.resolve(CURVES_OUTPUT_PATH).toAbsolutePath().resolve(CURVES_FILENAME); - Map curves = new HashMap<>(); if (Files.exists(curvesPath)) { - Map> curvesPerVersion = TimeSeries.parseCsv(curvesPath, new TimeSeriesCsvConfig(TimeSeriesConstants.DEFAULT_SEPARATOR, false, TimeFormat.FRACTIONS_OF_SECOND)); - curvesPerVersion.values().forEach(l -> l.forEach(curve -> curves.put(curve.getMetadata().getName(), curve))); + TimeSeries.parseCsv(curvesPath, new TimeSeriesCsvConfig(TimeSeriesConstants.DEFAULT_SEPARATOR, false, TimeFormat.FRACTIONS_OF_SECOND)) + .values().forEach(l -> l.forEach(curve -> curves.put(curve.getMetadata().getName(), (DoubleTimeSeries) curve))); } else { - if (context.withCurves()) { - status = false; - } + LOGGER.warn("Curves folder not found"); + status = DynamicSimulationResult.Status.FAILURE; + statusText = "Dynawo curves folder not found"; } - return new DynamicSimulationResultImpl(status, null, curves, DynamicSimulationResult.emptyTimeLine()); } private void writeInputFiles(Path workingDir) throws IOException { diff --git a/dynawaltz/src/main/java/com/powsybl/dynawaltz/DynawaltzReports.java b/dynawaltz/src/main/java/com/powsybl/dynawaltz/DynawaltzReports.java index 06ee86e81..2d8b20867 100644 --- a/dynawaltz/src/main/java/com/powsybl/dynawaltz/DynawaltzReports.java +++ b/dynawaltz/src/main/java/com/powsybl/dynawaltz/DynawaltzReports.java @@ -30,6 +30,11 @@ public static Reporter createDynaWaltzContextReporter(Reporter reporter) { "Dynawaltz models processing"); } + public static Reporter createDynaWaltzTimelineReporter(Reporter reporter) { + return reporter.createSubReporter("dynawaltzTimeline", + "Dynawaltz Timeline"); + } + public static void reportDuplicateStaticId(Reporter reporter, String duplicateId, String modelName, String dynamicId) { reporter.report(Report.builder() .withKey("duplicateStaticId") diff --git a/dynawaltz/src/test/java/com/powsybl/dynawaltz/DynaWaltzProviderTest.java b/dynawaltz/src/test/java/com/powsybl/dynawaltz/DynaWaltzProviderTest.java index c6dbbe031..a2d7fd841 100644 --- a/dynawaltz/src/test/java/com/powsybl/dynawaltz/DynaWaltzProviderTest.java +++ b/dynawaltz/src/test/java/com/powsybl/dynawaltz/DynaWaltzProviderTest.java @@ -107,7 +107,7 @@ void testWithoutMergeLoads() throws Exception { assertEquals(DynaWaltzProvider.NAME, dynawoSimulation.getName()); DynamicSimulationResult result = dynawoSimulation.run(network, (n, r) -> Collections.emptyList(), EventModelsSupplier.empty(), CurvesSupplier.empty(), network.getVariantManager().getWorkingVariantId(), - computationManager, dynamicSimulationParameters); + computationManager, dynamicSimulationParameters, NO_OP); assertNotNull(result); } diff --git a/dynawo-integration-tests/src/test/java/com/powsybl/dynawo/it/DynaWaltzTest.java b/dynawo-integration-tests/src/test/java/com/powsybl/dynawo/it/DynaWaltzTest.java index 09fce25bf..e341a812f 100644 --- a/dynawo-integration-tests/src/test/java/com/powsybl/dynawo/it/DynaWaltzTest.java +++ b/dynawo-integration-tests/src/test/java/com/powsybl/dynawo/it/DynaWaltzTest.java @@ -8,7 +8,6 @@ import com.powsybl.commons.datasource.ResourceDataSource; import com.powsybl.commons.datasource.ResourceSet; -import com.powsybl.commons.reporter.Reporter; import com.powsybl.dynamicsimulation.*; import com.powsybl.dynamicsimulation.groovy.*; import com.powsybl.dynawaltz.DumpFileParameters; @@ -21,7 +20,6 @@ import com.powsybl.iidm.network.VariantManagerConstants; import com.powsybl.iidm.network.test.SvcTestCaseFactory; import com.powsybl.timeseries.DoubleTimeSeries; -import com.powsybl.timeseries.StringTimeSeries; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -31,6 +29,7 @@ import java.util.List; import java.util.stream.Stream; +import static com.powsybl.commons.reporter.Reporter.NO_OP; import static org.junit.jupiter.api.Assertions.*; /** @@ -50,7 +49,7 @@ void setUp() throws Exception { super.setUp(); provider = new DynaWaltzProvider(new DynaWaltzConfig(Path.of("/dynawo"), false)); parameters = new DynamicSimulationParameters() - .setStartTime(1) + .setStartTime(0) .setStopTime(100); dynaWaltzParameters = new DynaWaltzParameters(); parameters.addExtension(DynaWaltzParameters.class, dynaWaltzParameters); @@ -82,17 +81,18 @@ void testIeee14() { .setDefaultDumpFileParameters(); DynamicSimulationResult result = provider.run(network, dynamicModelsSupplier, eventModelsSupplier, curvesSupplier, - VariantManagerConstants.INITIAL_VARIANT_ID, computationManager, parameters, Reporter.NO_OP) + VariantManagerConstants.INITIAL_VARIANT_ID, computationManager, parameters, NO_OP) .join(); - assertTrue(result.isOk()); + assertEquals(DynamicSimulationResult.Status.SUCCESS, result.getStatus()); + assertTrue(result.getStatusText().isEmpty()); assertEquals(41, result.getCurves().size()); DoubleTimeSeries ts1 = (DoubleTimeSeries) result.getCurve("_GEN____1_SM_generator_UStatorPu"); assertEquals("_GEN____1_SM_generator_UStatorPu", ts1.getMetadata().getName()); assertEquals(587, ts1.toArray().length); - StringTimeSeries timeLine = result.getTimeLine(); - assertEquals(1, timeLine.toArray().length); - assertNull(timeLine.toArray()[0]); // FIXME + List timeLine = result.getTimeLine(); + assertEquals(23, timeLine.size()); + checkFirstTimeLineEvent(timeLine.get(0), 0, "_GEN____8_SM", "PMIN : activation"); } @Test @@ -126,9 +126,9 @@ void testIeee14WithDump() throws IOException { .setDumpFileParameters(dumpFileParameters); DynamicSimulationResult result = provider.run(network, dynamicModelsSupplier, eventModelsSupplier, curvesSupplier, - VariantManagerConstants.INITIAL_VARIANT_ID, computationManager, parameters, Reporter.NO_OP) + VariantManagerConstants.INITIAL_VARIANT_ID, computationManager, parameters, NO_OP) .join(); - assertTrue(result.isOk()); + assertEquals(DynamicSimulationResult.Status.SUCCESS, result.getStatus()); //Use exported dump as input parameters.setStartTime(30); @@ -141,11 +141,10 @@ void testIeee14WithDump() throws IOException { dynaWaltzParameters.setDumpFileParameters(DumpFileParameters.createImportDumpFileParameters(dumpDir, dumpFile)); result = provider.run(network, dynamicModelsSupplier, eventModelsSupplier, curvesSupplier, - VariantManagerConstants.INITIAL_VARIANT_ID, computationManager, parameters, Reporter.NO_OP) + VariantManagerConstants.INITIAL_VARIANT_ID, computationManager, parameters, NO_OP) .join(); - assertTrue(result.isOk()); - + assertEquals(DynamicSimulationResult.Status.SUCCESS, result.getStatus()); } @Test @@ -166,14 +165,15 @@ void testSvc() { .setDefaultDumpFileParameters(); DynamicSimulationResult result = provider.run(network, dynamicModelsSupplier, EventModelsSupplier.empty(), CurvesSupplier.empty(), - VariantManagerConstants.INITIAL_VARIANT_ID, computationManager, parameters, Reporter.NO_OP) + VariantManagerConstants.INITIAL_VARIANT_ID, computationManager, parameters, NO_OP) .join(); - assertTrue(result.isOk()); - assertEquals(0, result.getCurves().size()); - StringTimeSeries timeLine = result.getTimeLine(); - assertEquals(1, timeLine.toArray().length); - assertNull(timeLine.toArray()[0]); // FIXME + assertEquals(DynamicSimulationResult.Status.SUCCESS, result.getStatus()); + assertTrue(result.getStatusText().isEmpty()); + assertTrue(result.getCurves().isEmpty()); + List timeLine = result.getTimeLine(); + assertEquals(1, timeLine.size()); + checkFirstTimeLineEvent(timeLine.get(0), 0, "G1", "PMIN : activation"); } @Test @@ -194,14 +194,15 @@ void testHvdc() { .setDefaultDumpFileParameters(); DynamicSimulationResult result = provider.run(network, dynamicModelsSupplier, EventModelsSupplier.empty(), CurvesSupplier.empty(), - VariantManagerConstants.INITIAL_VARIANT_ID, computationManager, parameters, Reporter.NO_OP) + VariantManagerConstants.INITIAL_VARIANT_ID, computationManager, parameters, NO_OP) .join(); - assertTrue(result.isOk()); - assertEquals(0, result.getCurves().size()); - StringTimeSeries timeLine = result.getTimeLine(); - assertEquals(1, timeLine.toArray().length); - assertNull(timeLine.toArray()[0]); // FIXME + assertEquals(DynamicSimulationResult.Status.SUCCESS, result.getStatus()); + assertTrue(result.getStatusText().isEmpty()); + assertTrue(result.getCurves().isEmpty()); + List timeLine = result.getTimeLine(); + assertEquals(7, timeLine.size()); + checkFirstTimeLineEvent(timeLine.get(0), 30.0, "_BUS____5-BUS____6-1_PS", "Tap +1"); } @Test @@ -231,13 +232,48 @@ void testSmib() { .setDefaultDumpFileParameters(); DynamicSimulationResult result = provider.run(network, dynamicModelsSupplier, eventModelsSupplier, curvesSupplier, - VariantManagerConstants.INITIAL_VARIANT_ID, computationManager, parameters, Reporter.NO_OP) + VariantManagerConstants.INITIAL_VARIANT_ID, computationManager, parameters, NO_OP) .join(); - assertTrue(result.isOk()); + assertEquals(DynamicSimulationResult.Status.SUCCESS, result.getStatus()); + assertTrue(result.getStatusText().isEmpty()); assertEquals(35, result.getCurves().size()); - StringTimeSeries timeLine = result.getTimeLine(); - assertEquals(1, timeLine.toArray().length); - assertNull(timeLine.toArray()[0]); // FIXME + List timeLine = result.getTimeLine(); + assertTrue(timeLine.isEmpty()); + } + + @Test + void testSimulationError() { + Network network = Network.read(new ResourceDataSource("powsybl_dynawaltz", new ResourceSet("/error", "powsybl_dynawaltz.xiidm"))); + + GroovyDynamicModelsSupplier dynamicModelsSupplier = new GroovyDynamicModelsSupplier( + getResourceAsStream("/error/models.groovy"), + GroovyExtension.find(DynamicModelGroovyExtension.class, DynaWaltzProvider.NAME)); + + GroovyEventModelsSupplier eventModelsSupplier = new GroovyEventModelsSupplier( + getResourceAsStream("/error/eventModels.groovy"), + GroovyExtension.find(EventModelGroovyExtension.class, DynaWaltzProvider.NAME)); + + parameters.setStopTime(200); + dynaWaltzParameters.setModelsParameters(ParametersXml.load(getResourceAsStream("/error/models.par"))) + .setNetworkParameters(ParametersXml.load(getResourceAsStream("/error/network.par"), "NETWORK")) + .setSolverParameters(ParametersXml.load(getResourceAsStream("/error/solvers.par"), "3")) + .setSolverType(DynaWaltzParameters.SolverType.SIM) + .setDefaultDumpFileParameters(); + + DynamicSimulationResult result = provider.run(network, dynamicModelsSupplier, eventModelsSupplier, CurvesSupplier.empty(), + VariantManagerConstants.INITIAL_VARIANT_ID, computationManager, parameters, NO_OP) + .join(); + + assertEquals(DynamicSimulationResult.Status.FAILURE, result.getStatus()); + assertEquals("time step <= 0.1 s for more than 10 iterations ( DYNSolverCommonFixedTimeStep.cpp:419 )", result.getStatusText()); + assertTrue(result.getTimeLine().isEmpty()); + assertTrue(result.getCurves().isEmpty()); + } + + private void checkFirstTimeLineEvent(TimelineEvent event, double time, String modelName, String message) { + assertEquals(time, event.time()); + assertEquals(modelName, event.modelName()); + assertEquals(message, event.message()); } } diff --git a/dynawo-integration-tests/src/test/resources/error/eventModels.groovy b/dynawo-integration-tests/src/test/resources/error/eventModels.groovy new file mode 100644 index 000000000..97e19c954 --- /dev/null +++ b/dynawo-integration-tests/src/test/resources/error/eventModels.groovy @@ -0,0 +1,13 @@ +package error + +Disconnect { + staticId "L4032-4044" + startTime 1.1 +} +NodeFault { + staticId "4032_401" + startTime 1 + faultTime 0.1 + rPu 0.025 + xPu 0.025 +} diff --git a/dynawo-integration-tests/src/test/resources/error/models.groovy b/dynawo-integration-tests/src/test/resources/error/models.groovy new file mode 100644 index 000000000..27efab494 --- /dev/null +++ b/dynawo-integration-tests/src/test/resources/error/models.groovy @@ -0,0 +1,30 @@ +package error + +import com.powsybl.iidm.network.Generator +import com.powsybl.iidm.network.Load + +for (Generator equipment : network.generators) { + if (equipment.energySource.name() == "HYDRO") { + GeneratorSynchronousThreeWindingsGoverNordicVRNordic { + staticId equipment.id + parameterSetId "Nordic" + equipment.id + } + } else if (equipment.energySource.name() == "THERMAL") { + GeneratorSynchronousFourWindingsPmConstVRNordic { + staticId equipment.id + parameterSetId "Nordic" + equipment.id + } + } else if (equipment.energySource.name() == "OTHER") { + GeneratorSynchronousThreeWindingsPmConstVRNordic { + staticId equipment.id + parameterSetId "Nordic" + equipment.id + } + } +} + +for (Load equipment : network.loads) { + LoadAlphaBeta { + staticId equipment.id + parameterSetId "LAB" + } +} diff --git a/dynawo-integration-tests/src/test/resources/error/models.par b/dynawo-integration-tests/src/test/resources/error/models.par new file mode 100644 index 000000000..a786647fa --- /dev/null +++ b/dynawo-integration-tests/src/test/resources/error/models.par @@ -0,0 +1,1013 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dynawo-integration-tests/src/test/resources/error/network.par b/dynawo-integration-tests/src/test/resources/error/network.par new file mode 100644 index 000000000..f34881631 --- /dev/null +++ b/dynawo-integration-tests/src/test/resources/error/network.par @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dynawo-integration-tests/src/test/resources/error/powsybl_dynawaltz.xiidm b/dynawo-integration-tests/src/test/resources/error/powsybl_dynawaltz.xiidm new file mode 100644 index 000000000..4b2b7c1d1 --- /dev/null +++ b/dynawo-integration-tests/src/test/resources/error/powsybl_dynawaltz.xiidm @@ -0,0 +1,2195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dynawo-integration-tests/src/test/resources/error/solvers.par b/dynawo-integration-tests/src/test/resources/error/solvers.par new file mode 100644 index 000000000..71b76a308 --- /dev/null +++ b/dynawo-integration-tests/src/test/resources/error/solvers.par @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 97274e31c..eb374f8ef 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 17 - 6.1.0-SNAPSHOT + 6.1.0 4.0.14 ../distribution/target/site/jacoco-aggregate/jacoco.xml,