From fde10f2afc8893838843c734266859357dbf382b Mon Sep 17 00:00:00 2001 From: Lisrte Date: Tue, 2 Jul 2024 16:52:24 +0200 Subject: [PATCH] Add deserialization in DynawoModelsSupplier/DynawoEventModelsSupplier (#363) * Add deserialization in DynawoModelsSupplier and DynawoEventModelsSupplier through a load static method * Add integration test * Add unit test Signed-off-by: lisrte --- .../suppliers/SupplierJsonDeserializer.java | 50 +++++++++++++++ .../dynamicmodels/DynawoModelsSupplier.java | 19 +++++- .../events/DynawoEventModelsSupplier.java | 19 +++++- ...ava => DynawoEventModelsSupplierTest.java} | 29 +++++---- ...est.java => DynawoModelsSupplierTest.java} | 29 +++++---- .../SupplierJsonDeserializerTest.java | 43 +++++++++++++ .../com/powsybl/dynawo/it/DynaWaltzTest.java | 30 +++++++++ .../ieee14/disconnectline/dynamicModels.json | 62 +++++++++++++++++++ .../ieee14/disconnectline/eventModels.json | 24 +++++++ 9 files changed, 273 insertions(+), 32 deletions(-) create mode 100644 dynawaltz/src/main/java/com/powsybl/dynawaltz/suppliers/SupplierJsonDeserializer.java rename dynawaltz/src/test/java/com/powsybl/dynawaltz/suppliers/{DynawoEventModelsSuppliersTest.java => DynawoEventModelsSupplierTest.java} (88%) rename dynawaltz/src/test/java/com/powsybl/dynawaltz/suppliers/{DynawoModelsSuppliersTest.java => DynawoModelsSupplierTest.java} (91%) create mode 100644 dynawaltz/src/test/java/com/powsybl/dynawaltz/suppliers/SupplierJsonDeserializerTest.java create mode 100644 dynawo-integration-tests/src/test/resources/ieee14/disconnectline/dynamicModels.json create mode 100644 dynawo-integration-tests/src/test/resources/ieee14/disconnectline/eventModels.json diff --git a/dynawaltz/src/main/java/com/powsybl/dynawaltz/suppliers/SupplierJsonDeserializer.java b/dynawaltz/src/main/java/com/powsybl/dynawaltz/suppliers/SupplierJsonDeserializer.java new file mode 100644 index 000000000..efc2f481e --- /dev/null +++ b/dynawaltz/src/main/java/com/powsybl/dynawaltz/suppliers/SupplierJsonDeserializer.java @@ -0,0 +1,50 @@ +package com.powsybl.dynawaltz.suppliers; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.powsybl.commons.PowsyblException; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +/** + * @author Laurent Issertial {@literal } + */ +public class SupplierJsonDeserializer { + + private final StdDeserializer> deserializer; + + public SupplierJsonDeserializer(StdDeserializer> deserializer) { + this.deserializer = deserializer; + } + + public List deserialize(Path path) { + try { + Reader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8); + return setupObjectMapper().readValue(reader, new TypeReference<>() { + }); + } catch (IOException e) { + throw new PowsyblException("JSON input cannot be read", e); + } + } + + public List deserialize(InputStream is) { + try { + return setupObjectMapper().readValue(is, new TypeReference<>() { + }); + } catch (IOException e) { + throw new PowsyblException("JSON input cannot be read", e); + } + } + + private ObjectMapper setupObjectMapper() { + return new ObjectMapper().registerModule(new SimpleModule().addDeserializer(List.class, deserializer)); + } +} diff --git a/dynawaltz/src/main/java/com/powsybl/dynawaltz/suppliers/dynamicmodels/DynawoModelsSupplier.java b/dynawaltz/src/main/java/com/powsybl/dynawaltz/suppliers/dynamicmodels/DynawoModelsSupplier.java index 5398282c3..ceee9be81 100644 --- a/dynawaltz/src/main/java/com/powsybl/dynawaltz/suppliers/dynamicmodels/DynawoModelsSupplier.java +++ b/dynawaltz/src/main/java/com/powsybl/dynawaltz/suppliers/dynamicmodels/DynawoModelsSupplier.java @@ -11,17 +11,21 @@ import com.powsybl.commons.report.ReportNode; import com.powsybl.dynamicsimulation.DynamicModel; import com.powsybl.dynamicsimulation.DynamicModelsSupplier; +import com.powsybl.dynawaltz.DynaWaltzProvider; import com.powsybl.dynawaltz.builders.ModelBuilder; import com.powsybl.dynawaltz.builders.ModelConfigsHandler; import com.powsybl.dynawaltz.suppliers.Property; +import com.powsybl.dynawaltz.suppliers.SupplierJsonDeserializer; import com.powsybl.iidm.network.Network; +import java.io.InputStream; import java.lang.reflect.InvocationTargetException; +import java.nio.file.Path; import java.util.List; import java.util.Objects; /** - * Instantiates an {@link DynamicModelConfig} list from {@link DynamicModelConfig} + * Instantiates an {@link DynamicModelConfig} list from {@link DynamicModelConfig} or JSON input * @author Laurent Issertial {@literal } */ public class DynawoModelsSupplier implements DynamicModelsSupplier { @@ -30,10 +34,23 @@ public class DynawoModelsSupplier implements DynamicModelsSupplier { private final List dynamicModelConfigs; + public static DynawoModelsSupplier load(InputStream is) { + return new DynawoModelsSupplier(new SupplierJsonDeserializer<>(new DynamicModelConfigsJsonDeserializer()).deserialize(is)); + } + + public static DynawoModelsSupplier load(Path path) { + return new DynawoModelsSupplier(new SupplierJsonDeserializer<>(new DynamicModelConfigsJsonDeserializer()).deserialize(path)); + } + public DynawoModelsSupplier(List dynamicModelConfigs) { this.dynamicModelConfigs = dynamicModelConfigs; } + @Override + public String getName() { + return DynaWaltzProvider.NAME; + } + @Override public List get(Network network, ReportNode reportNode) { return dynamicModelConfigs.stream() diff --git a/dynawaltz/src/main/java/com/powsybl/dynawaltz/suppliers/events/DynawoEventModelsSupplier.java b/dynawaltz/src/main/java/com/powsybl/dynawaltz/suppliers/events/DynawoEventModelsSupplier.java index 8162bfabf..62d66555c 100644 --- a/dynawaltz/src/main/java/com/powsybl/dynawaltz/suppliers/events/DynawoEventModelsSupplier.java +++ b/dynawaltz/src/main/java/com/powsybl/dynawaltz/suppliers/events/DynawoEventModelsSupplier.java @@ -11,27 +11,44 @@ import com.powsybl.commons.report.ReportNode; import com.powsybl.dynamicsimulation.EventModel; import com.powsybl.dynamicsimulation.EventModelsSupplier; +import com.powsybl.dynawaltz.DynaWaltzProvider; import com.powsybl.dynawaltz.builders.ModelBuilder; import com.powsybl.dynawaltz.builders.ModelConfigsHandler; import com.powsybl.dynawaltz.suppliers.Property; +import com.powsybl.dynawaltz.suppliers.SupplierJsonDeserializer; import com.powsybl.iidm.network.Network; +import java.io.InputStream; import java.lang.reflect.InvocationTargetException; +import java.nio.file.Path; import java.util.List; import java.util.Objects; /** - * Instantiates an {@link EventModel} list from {@link EventModelConfig} + * Instantiates an {@link EventModel} list from {@link EventModelConfig} or JSON input * @author Laurent Issertial {@literal } */ public class DynawoEventModelsSupplier implements EventModelsSupplier { private final List eventModelConfigs; + public static DynawoEventModelsSupplier load(InputStream is) { + return new DynawoEventModelsSupplier(new SupplierJsonDeserializer<>(new EventModelConfigsJsonDeserializer()).deserialize(is)); + } + + public static DynawoEventModelsSupplier load(Path path) { + return new DynawoEventModelsSupplier(new SupplierJsonDeserializer<>(new EventModelConfigsJsonDeserializer()).deserialize(path)); + } + public DynawoEventModelsSupplier(List eventModelConfigs) { this.eventModelConfigs = eventModelConfigs; } + @Override + public String getName() { + return DynaWaltzProvider.NAME; + } + @Override public List get(Network network, ReportNode reportNode) { return eventModelConfigs.stream() diff --git a/dynawaltz/src/test/java/com/powsybl/dynawaltz/suppliers/DynawoEventModelsSuppliersTest.java b/dynawaltz/src/test/java/com/powsybl/dynawaltz/suppliers/DynawoEventModelsSupplierTest.java similarity index 88% rename from dynawaltz/src/test/java/com/powsybl/dynawaltz/suppliers/DynawoEventModelsSuppliersTest.java rename to dynawaltz/src/test/java/com/powsybl/dynawaltz/suppliers/DynawoEventModelsSupplierTest.java index 98c4838d7..e5b914866 100644 --- a/dynawaltz/src/test/java/com/powsybl/dynawaltz/suppliers/DynawoEventModelsSuppliersTest.java +++ b/dynawaltz/src/test/java/com/powsybl/dynawaltz/suppliers/DynawoEventModelsSupplierTest.java @@ -7,9 +7,6 @@ */ package com.powsybl.dynawaltz.suppliers; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; import com.powsybl.commons.PowsyblException; import com.powsybl.commons.report.ReportNode; import com.powsybl.dynamicsimulation.EventModel; @@ -23,8 +20,11 @@ import java.io.IOException; import java.io.InputStream; +import java.net.URISyntaxException; +import java.nio.file.Path; import java.util.Collections; import java.util.List; +import java.util.Objects; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; @@ -32,7 +32,7 @@ /** * @author Laurent Issertial {@literal } */ -class DynawoEventModelsSuppliersTest { +class DynawoEventModelsSupplierTest { @Test void testEventSupplier() { @@ -66,12 +66,19 @@ void testWrongNameBuilder() { assertTrue(events.isEmpty()); } + @Test + void testSupplierFromPath() throws URISyntaxException { + Network network = EurostagTutorialExample1Factory.create(); + Path path = Path.of(Objects.requireNonNull(getClass().getResource("/suppliers/mappingEvent.json")).toURI()); + List models = DynawoEventModelsSupplier.load(path).get(network); + assertEquals(1, models.size()); + } + @Test void testEventModelConfigDeserializer() throws IOException { - ObjectMapper objectMapper = setupObjectMapper(); + SupplierJsonDeserializer deserializer = new SupplierJsonDeserializer<>(new EventModelConfigsJsonDeserializer()); try (InputStream is = getClass().getResourceAsStream("/suppliers/mappingEvent.json")) { - List configs = objectMapper.readValue(is, new TypeReference<>() { - }); + List configs = deserializer.deserialize(is); assertEquals(1, configs.size()); assertThat(configs.get(0)).usingRecursiveComparison().isEqualTo(getActivePowerVariationConfig()); } @@ -133,12 +140,4 @@ private static EventModelConfig getActivePowerVariationConfig() { .type(PropertyType.DOUBLE) .build())); } - - private static ObjectMapper setupObjectMapper() { - ObjectMapper objectMapper = new ObjectMapper(); - SimpleModule module = new SimpleModule(); - module.addDeserializer(List.class, new EventModelConfigsJsonDeserializer()); - objectMapper.registerModule(module); - return objectMapper; - } } diff --git a/dynawaltz/src/test/java/com/powsybl/dynawaltz/suppliers/DynawoModelsSuppliersTest.java b/dynawaltz/src/test/java/com/powsybl/dynawaltz/suppliers/DynawoModelsSupplierTest.java similarity index 91% rename from dynawaltz/src/test/java/com/powsybl/dynawaltz/suppliers/DynawoModelsSuppliersTest.java rename to dynawaltz/src/test/java/com/powsybl/dynawaltz/suppliers/DynawoModelsSupplierTest.java index 22a02f7c4..adfe1d171 100644 --- a/dynawaltz/src/test/java/com/powsybl/dynawaltz/suppliers/DynawoModelsSuppliersTest.java +++ b/dynawaltz/src/test/java/com/powsybl/dynawaltz/suppliers/DynawoModelsSupplierTest.java @@ -7,9 +7,6 @@ */ package com.powsybl.dynawaltz.suppliers; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; import com.powsybl.commons.PowsyblException; import com.powsybl.commons.report.ReportNode; import com.powsybl.dynamicsimulation.DynamicModel; @@ -23,9 +20,12 @@ import java.io.IOException; import java.io.InputStream; +import java.net.URISyntaxException; +import java.nio.file.Path; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Objects; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; @@ -33,7 +33,7 @@ /** * @author Laurent Issertial {@literal } */ -class DynawoModelsSuppliersTest { +class DynawoModelsSupplierTest { @Test void testDynamicModelSupplier() { @@ -74,12 +74,19 @@ void testWrongNameBuilder() { assertTrue(models.isEmpty()); } + @Test + void testSupplierFromPath() throws URISyntaxException { + Network network = EurostagTutorialExample1Factory.createWithLFResults(); + Path path = Path.of(Objects.requireNonNull(getClass().getResource("/suppliers/mappingDynamicModel.json")).toURI()); + List models = DynawoModelsSupplier.load(path).get(network); + assertEquals(2, models.size()); + } + @Test void testModelConfigDeserializer() throws IOException { - ObjectMapper objectMapper = setupObjectMapper(); + SupplierJsonDeserializer deserializer = new SupplierJsonDeserializer<>(new DynamicModelConfigsJsonDeserializer()); try (InputStream is = getClass().getResourceAsStream("/suppliers/mappingDynamicModel.json")) { - List configs = objectMapper.readValue(is, new TypeReference<>() { - }); + List configs = deserializer.deserialize(is); assertEquals(2, configs.size()); assertThat(configs.get(0)).usingRecursiveComparison().isEqualTo(getLoadConfig()); assertThat(configs.get(1)).usingRecursiveComparison().isEqualTo(getTcbConfig()); @@ -177,12 +184,4 @@ private static DynamicModelConfig getSimpleTcbConfig() { .build() )); } - - private static ObjectMapper setupObjectMapper() { - ObjectMapper objectMapper = new ObjectMapper(); - SimpleModule module = new SimpleModule(); - module.addDeserializer(List.class, new DynamicModelConfigsJsonDeserializer()); - objectMapper.registerModule(module); - return objectMapper; - } } diff --git a/dynawaltz/src/test/java/com/powsybl/dynawaltz/suppliers/SupplierJsonDeserializerTest.java b/dynawaltz/src/test/java/com/powsybl/dynawaltz/suppliers/SupplierJsonDeserializerTest.java new file mode 100644 index 000000000..e64dbd19c --- /dev/null +++ b/dynawaltz/src/test/java/com/powsybl/dynawaltz/suppliers/SupplierJsonDeserializerTest.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2024, RTE (http://www.rte-france.com/) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.dynawaltz.suppliers; + +import com.powsybl.commons.PowsyblException; +import com.powsybl.dynawaltz.suppliers.events.EventModelConfig; +import com.powsybl.dynawaltz.suppliers.events.EventModelConfigsJsonDeserializer; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * @author Laurent Issertial {@literal } + */ +class SupplierJsonDeserializerTest { + + @Test + void testPathException() { + Path path = Path.of("wrongURI"); + SupplierJsonDeserializer deserializer = new SupplierJsonDeserializer<>(new EventModelConfigsJsonDeserializer()); + Exception e = assertThrows(PowsyblException.class, () -> deserializer.deserialize(path)); + assertEquals("JSON input cannot be read", e.getMessage()); + } + + @Test + void testInputStreamException() throws IOException { + try (InputStream is = InputStream.nullInputStream()) { + SupplierJsonDeserializer deserializer = new SupplierJsonDeserializer<>(new EventModelConfigsJsonDeserializer()); + Exception e = assertThrows(PowsyblException.class, () -> deserializer.deserialize(is)); + assertEquals("JSON input cannot be read", e.getMessage()); + } + } +} 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 c6fab454b..56fb17d8c 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 @@ -16,6 +16,8 @@ import com.powsybl.dynawaltz.DynaWaltzParameters; import com.powsybl.dynawaltz.DynaWaltzProvider; import com.powsybl.dynawaltz.parameters.ParametersSet; +import com.powsybl.dynawaltz.suppliers.dynamicmodels.DynawoModelsSupplier; +import com.powsybl.dynawaltz.suppliers.events.DynawoEventModelsSupplier; import com.powsybl.dynawaltz.xml.ParametersXml; import com.powsybl.iidm.network.Network; import com.powsybl.iidm.network.VariantManagerConstants; @@ -273,6 +275,34 @@ void testSimulationError() { assertTrue(result.getCurves().isEmpty()); } + @Test + void testIeee14DynawoSuppliers() { + Network network = Network.read(new ResourceDataSource("IEEE14", new ResourceSet("/ieee14", "IEEE14.iidm"))); + + DynamicModelsSupplier dynamicModelsSupplier = DynawoModelsSupplier.load(getResourceAsStream("/ieee14/disconnectline/dynamicModels.json")); + EventModelsSupplier eventModelsSupplier = DynawoEventModelsSupplier.load(getResourceAsStream("/ieee14/disconnectline/eventModels.json")); + + List modelsParameters = ParametersXml.load(getResourceAsStream("/ieee14/disconnectline/models.par")); + ParametersSet networkParameters = ParametersXml.load(getResourceAsStream("/ieee14/disconnectline/network.par"), "8"); + ParametersSet solverParameters = ParametersXml.load(getResourceAsStream("/ieee14/disconnectline/solvers.par"), "2"); + dynaWaltzParameters.setModelsParameters(modelsParameters) + .setNetworkParameters(networkParameters) + .setSolverParameters(solverParameters) + .setSolverType(DynaWaltzParameters.SolverType.IDA) + .setTimelineExportMode(DynaWaltzParameters.ExportMode.XML); + + DynamicSimulationResult result = provider.run(network, dynamicModelsSupplier, eventModelsSupplier, CurvesSupplier.empty(), + VariantManagerConstants.INITIAL_VARIANT_ID, computationManager, parameters, NO_OP) + .join(); + + assertEquals(DynamicSimulationResult.Status.SUCCESS, result.getStatus()); + assertTrue(result.getStatusText().isEmpty()); + assertEquals(0, result.getCurves().size()); + List timeLine = result.getTimeLine(); + assertEquals(11, timeLine.size()); + checkFirstTimeLineEvent(timeLine.get(0), 0, "_GEN____8_SM", "PMIN : activation"); + } + private void checkFirstTimeLineEvent(TimelineEvent event, double time, String modelName, String message) { assertEquals(time, event.time()); assertEquals(modelName, event.modelName()); diff --git a/dynawo-integration-tests/src/test/resources/ieee14/disconnectline/dynamicModels.json b/dynawo-integration-tests/src/test/resources/ieee14/disconnectline/dynamicModels.json new file mode 100644 index 000000000..3071a9bb9 --- /dev/null +++ b/dynawo-integration-tests/src/test/resources/ieee14/disconnectline/dynamicModels.json @@ -0,0 +1,62 @@ +{ + "models":[ + { + "model":"LoadAlphaBeta", + "group": "LAB", + "properties":[ + { + "name":"staticId", + "value":"_LOAD___5_EC", + "type":"STRING" + } + ] + }, + { + "model":"LoadAlphaBeta", + "group": "LAB", + "properties":[ + { + "name":"staticId", + "value":"_LOAD___6_EC", + "type":"STRING" + } + ] + }, + { + "model":"GeneratorSynchronousThreeWindingsProportionalRegulations", + "group": "GSTWPR", + "groupType": "PREFIX", + "properties":[ + { + "name":"staticId", + "value":"_GEN____6_SM", + "type":"STRING" + } + ] + }, + { + "model":"GeneratorSynchronousThreeWindingsProportionalRegulations", + "group": "GSTWPR", + "groupType": "PREFIX", + "properties":[ + { + "name":"staticId", + "value":"_GEN____8_SM", + "type":"STRING" + } + ] + }, + { + "model":"GeneratorSynchronousFourWindingsProportionalRegulations", + "group": "GSFWPR", + "groupType": "PREFIX", + "properties":[ + { + "name":"staticId", + "value":"_GEN____2_SM", + "type":"STRING" + } + ] + } + ] +} \ No newline at end of file diff --git a/dynawo-integration-tests/src/test/resources/ieee14/disconnectline/eventModels.json b/dynawo-integration-tests/src/test/resources/ieee14/disconnectline/eventModels.json new file mode 100644 index 000000000..2d9983ed2 --- /dev/null +++ b/dynawo-integration-tests/src/test/resources/ieee14/disconnectline/eventModels.json @@ -0,0 +1,24 @@ +{ + "events":[ + { + "model":"Disconnect", + "properties":[ + { + "name":"staticId", + "value":"_BUS____1-BUS____5-1_AC", + "type":"STRING" + }, + { + "name":"startTime", + "value":"1", + "type":"DOUBLE" + }, + { + "name":"disconnectOnly", + "value":"TWO", + "type":"TWO_SIDES" + } + ] + } + ] +} \ No newline at end of file