diff --git a/pom.xml b/pom.xml
index f1066524..7db2a7c8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -90,6 +90,8 @@
+
+
org.gridsuite
@@ -98,13 +100,16 @@
pom
import
+
+
+
com.powsybl
- powsybl-network-store-iidm-impl
+ powsybl-iidm-api
org.springframework.boot
@@ -132,15 +137,15 @@
com.powsybl
- powsybl-dynawaltz
+ powsybl-dynamic-simulation-dsl
com.powsybl
- powsybl-dynawaltz-dsl
+ powsybl-dynawaltz
com.powsybl
- powsybl-dynamic-simulation-dsl
+ powsybl-dynawaltz-dsl
com.powsybl
@@ -189,6 +194,12 @@
${h2database.version}
test
+
+ com.powsybl
+ powsybl-commons
+ test-jar
+ test
+
com.powsybl
powsybl-config-test
diff --git a/src/main/java/com/powsybl/dynamicsimulation/groovy/GroovyCurvesSupplier.java b/src/main/java/com/powsybl/dynamicsimulation/groovy/GroovyCurvesSupplier.java
new file mode 100644
index 00000000..fab65bd1
--- /dev/null
+++ b/src/main/java/com/powsybl/dynamicsimulation/groovy/GroovyCurvesSupplier.java
@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2020, 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/.
+ */
+
+package com.powsybl.dynamicsimulation.groovy;
+
+import com.powsybl.dsl.ExpressionDslLoader;
+import com.powsybl.dsl.GroovyScripts;
+import com.powsybl.dynamicsimulation.Curve;
+import com.powsybl.dynamicsimulation.CurvesSupplier;
+import com.powsybl.iidm.network.Network;
+import groovy.lang.Binding;
+import groovy.lang.GroovyCodeSource;
+import groovy.lang.GroovyShell;
+import org.codehaus.groovy.control.CompilerConfiguration;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * TODO: remove and use core one when switching to 5.1.0
+ * @author Mathieu Bague
+ */
+public class GroovyCurvesSupplier implements CurvesSupplier {
+
+ private final GroovyCodeSource codeSource;
+
+ private final List extensions;
+
+ public GroovyCurvesSupplier(InputStream is, List extensions) {
+ this.codeSource = GroovyScripts.load(is);
+ this.extensions = Objects.requireNonNull(extensions);
+ }
+
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public List get(Network network) {
+ List curves = new ArrayList<>();
+
+ Binding binding = new Binding();
+ binding.setVariable("network", network);
+
+ ExpressionDslLoader.prepareClosures(binding);
+ extensions.forEach(e -> e.load(binding, curves::add));
+
+ GroovyShell shell = new GroovyShell(binding, new CompilerConfiguration());
+ shell.evaluate(codeSource);
+
+ return curves;
+ }
+}
diff --git a/src/main/java/com/powsybl/dynamicsimulation/groovy/GroovyEventModelsSupplier.java b/src/main/java/com/powsybl/dynamicsimulation/groovy/GroovyEventModelsSupplier.java
new file mode 100644
index 00000000..216e54a4
--- /dev/null
+++ b/src/main/java/com/powsybl/dynamicsimulation/groovy/GroovyEventModelsSupplier.java
@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2020, 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/.
+ */
+
+package com.powsybl.dynamicsimulation.groovy;
+
+import com.powsybl.dsl.ExpressionDslLoader;
+import com.powsybl.dsl.GroovyScripts;
+import com.powsybl.dynamicsimulation.EventModel;
+import com.powsybl.dynamicsimulation.EventModelsSupplier;
+import com.powsybl.iidm.network.Network;
+import groovy.lang.Binding;
+import groovy.lang.GroovyCodeSource;
+import groovy.lang.GroovyShell;
+import org.codehaus.groovy.control.CompilerConfiguration;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * TODO: remove and use core one when switching to 5.1.0
+ * @author Marcos de Miguel
+ */
+public class GroovyEventModelsSupplier implements EventModelsSupplier {
+
+ private final GroovyCodeSource codeSource;
+
+ private final List extensions;
+
+ public GroovyEventModelsSupplier(InputStream is, List extensions) {
+ this.codeSource = GroovyScripts.load(is);
+ this.extensions = Objects.requireNonNull(extensions);
+ }
+
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public List get(Network network) {
+ List eventModels = new ArrayList<>();
+
+ Binding binding = new Binding();
+ binding.setVariable("network", network);
+
+ ExpressionDslLoader.prepareClosures(binding);
+ extensions.forEach(e -> e.load(binding, eventModels::add));
+
+ GroovyShell shell = new GroovyShell(binding, new CompilerConfiguration());
+ shell.evaluate(codeSource);
+
+ return eventModels;
+ }
+}
diff --git a/src/main/java/org/gridsuite/ds/server/DynamicSimulationApi.java b/src/main/java/org/gridsuite/ds/server/DynamicSimulationApi.java
index 28653119..0064fc37 100644
--- a/src/main/java/org/gridsuite/ds/server/DynamicSimulationApi.java
+++ b/src/main/java/org/gridsuite/ds/server/DynamicSimulationApi.java
@@ -10,10 +10,10 @@
* @author Abdelsalem Hedhili
*/
-final class DynamicSimulationApi {
+public final class DynamicSimulationApi {
private DynamicSimulationApi() {
}
- static final String API_VERSION = "v1";
+ public static final String API_VERSION = "v1";
}
diff --git a/src/main/java/org/gridsuite/ds/server/DynamicSimulationSwaggerConfig.java b/src/main/java/org/gridsuite/ds/server/config/SwaggerConfig.java
similarity index 82%
rename from src/main/java/org/gridsuite/ds/server/DynamicSimulationSwaggerConfig.java
rename to src/main/java/org/gridsuite/ds/server/config/SwaggerConfig.java
index 50100054..ad7c890f 100644
--- a/src/main/java/org/gridsuite/ds/server/DynamicSimulationSwaggerConfig.java
+++ b/src/main/java/org/gridsuite/ds/server/config/SwaggerConfig.java
@@ -1,13 +1,14 @@
-/**
- * Copyright (c) 2021, RTE (http://www.rte-france.com)
+/*
+ * Copyright (c) 2021-2022, 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/.
*/
-package org.gridsuite.ds.server;
+package org.gridsuite.ds.server.config;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
+import org.gridsuite.ds.server.DynamicSimulationApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -15,7 +16,7 @@
* @author Abdelsalem Hedhili
*/
@Configuration
-public class DynamicSimulationSwaggerConfig {
+public class SwaggerConfig {
@Bean
public OpenAPI createOpenApi() {
diff --git a/src/main/java/org/gridsuite/ds/server/DynamicSimulationController.java b/src/main/java/org/gridsuite/ds/server/controller/DynamicSimulationController.java
similarity index 60%
rename from src/main/java/org/gridsuite/ds/server/DynamicSimulationController.java
rename to src/main/java/org/gridsuite/ds/server/controller/DynamicSimulationController.java
index 43a4859e..620cc21b 100644
--- a/src/main/java/org/gridsuite/ds/server/DynamicSimulationController.java
+++ b/src/main/java/org/gridsuite/ds/server/controller/DynamicSimulationController.java
@@ -4,30 +4,31 @@
* 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/.
*/
-package org.gridsuite.ds.server;
+package org.gridsuite.ds.server.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
+import org.gridsuite.ds.server.dto.DynamicSimulationStatus;
import org.gridsuite.ds.server.service.DynamicSimulationService;
import org.springframework.boot.context.properties.bind.DefaultValue;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
-import org.springframework.http.codec.multipart.FilePart;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;
import java.util.UUID;
-import static org.springframework.http.MediaType.*;
+import static org.gridsuite.ds.server.DynamicSimulationApi.API_VERSION;
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
/**
* @author Abdelsalem Hedhili
*/
@RestController
-@RequestMapping(value = "/" + DynamicSimulationApi.API_VERSION)
+@RequestMapping(value = "/" + API_VERSION)
@Tag(name = "Dynamic simulation server")
public class DynamicSimulationController {
@@ -44,17 +45,28 @@ public ResponseEntity> run(@PathVariable("networkUuid") UUID networkU
@RequestParam(name = "variantId", required = false) String variantId,
@DefaultValue("0") @RequestParam("startTime") int startTime,
@RequestParam("stopTime") int stopTime,
- @RequestPart("dynamicModel") FilePart dynamicModel) {
- Mono resultUuid = dynamicSimulationService.runAndSaveResult(networkUuid, variantId, startTime, stopTime, dynamicModel);
+ @RequestParam("mappingName") String mappingName,
+ @RequestParam(name = "receiver", required = false) String receiver) {
+ Mono resultUuid = dynamicSimulationService.runAndSaveResult(receiver, networkUuid, variantId, startTime, stopTime, mappingName);
return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(resultUuid);
}
- @GetMapping(value = "/results/{resultUuid}", produces = "application/json")
+ @GetMapping(value = "/results/{resultUuid}/timeseries", produces = "application/json")
@Operation(summary = "Get a dynamic simulation result from the database")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The dynamic simulation result"),
@ApiResponse(responseCode = "404", description = "Dynamic simulation result has not been found")})
- public Mono> getResult(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid) {
- Mono result = dynamicSimulationService.getResult(resultUuid);
+ public Mono> getTimeSeriesResult(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid) {
+ Mono result = dynamicSimulationService.getTimeSeriesId(resultUuid);
+ return result.map(r -> ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(r))
+ .defaultIfEmpty(ResponseEntity.notFound().build());
+ }
+
+ @GetMapping(value = "/results/{resultUuid}/timeline", produces = "application/json")
+ @Operation(summary = "Get a dynamic simulation result from the database")
+ @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The dynamic simulation result"),
+ @ApiResponse(responseCode = "404", description = "Dynamic simulation result has not been found")})
+ public Mono> getTimeLineResult(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid) {
+ Mono result = dynamicSimulationService.getTimeLineId(resultUuid);
return result.map(r -> ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(r))
.defaultIfEmpty(ResponseEntity.notFound().build());
}
@@ -63,8 +75,8 @@ public Mono> getResult(@Parameter(description = "Result
@Operation(summary = "Get the dynamic simulation status from the database")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The dynamic simulation status"),
@ApiResponse(responseCode = "404", description = "Dynamic simulation status has not been found")})
- public Mono> getStatus(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid) {
- Mono result = dynamicSimulationService.getStatus(resultUuid);
+ public Mono> getStatus(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid) {
+ Mono result = dynamicSimulationService.getStatus(resultUuid);
return result.map(r -> ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(r))
.defaultIfEmpty(ResponseEntity.notFound().build());
}
@@ -85,4 +97,12 @@ public ResponseEntity> deleteResults() {
return ResponseEntity.ok().body(result);
}
+ @PutMapping(value = "/results/{resultUuid}/stop", produces = APPLICATION_JSON_VALUE)
+ @Operation(summary = "Stop a dynamic simulation computation")
+ @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The dynamic simulation has been stopped")})
+ public ResponseEntity> stop(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid,
+ @Parameter(description = "Result receiver") @RequestParam(name = "receiver", required = false) String receiver) {
+ Mono result = dynamicSimulationService.stop(receiver, resultUuid);
+ return ResponseEntity.ok().body(result);
+ }
}
diff --git a/src/main/java/org/gridsuite/ds/server/dto/DynamicSimulationStatus.java b/src/main/java/org/gridsuite/ds/server/dto/DynamicSimulationStatus.java
index cbe11762..fe48b08c 100644
--- a/src/main/java/org/gridsuite/ds/server/dto/DynamicSimulationStatus.java
+++ b/src/main/java/org/gridsuite/ds/server/dto/DynamicSimulationStatus.java
@@ -10,6 +10,8 @@
* @author Abdelsalem Hedhili
*/
public enum DynamicSimulationStatus {
+ NOT_DONE,
RUNNING,
- COMPLETED
+ CONVERGED,
+ DIVERGED
}
diff --git a/src/main/java/org/gridsuite/ds/server/dto/dynamicmapping/Script.java b/src/main/java/org/gridsuite/ds/server/dto/dynamicmapping/Script.java
new file mode 100644
index 00000000..22d37a26
--- /dev/null
+++ b/src/main/java/org/gridsuite/ds/server/dto/dynamicmapping/Script.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2022, 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/.
+ */
+package org.gridsuite.ds.server.dto.dynamicmapping;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * @author Thang PHAM
+ */
+@NoArgsConstructor
+@AllArgsConstructor
+@Getter
+@Setter
+public class Script {
+
+ private String name;
+
+ // name of the original mapping
+ private String parentName;
+
+ private String script;
+
+ private Date createdDate;
+
+ private String parametersFile;
+
+}
diff --git a/src/main/java/org/gridsuite/ds/server/dto/timeseries/TimeSeriesGroupInfos.java b/src/main/java/org/gridsuite/ds/server/dto/timeseries/TimeSeriesGroupInfos.java
new file mode 100644
index 00000000..cb0604c6
--- /dev/null
+++ b/src/main/java/org/gridsuite/ds/server/dto/timeseries/TimeSeriesGroupInfos.java
@@ -0,0 +1,26 @@
+/**
+ * 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/.
+ */
+package org.gridsuite.ds.server.dto.timeseries;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.UUID;
+
+/**
+ * @author Thang PHAM
+ */
+@NoArgsConstructor
+@AllArgsConstructor
+@Getter
+@Setter
+public class TimeSeriesGroupInfos {
+
+ private UUID id;
+}
diff --git a/src/main/java/org/gridsuite/ds/server/repository/AbstractManuallyAssignedIdentifierEntity.java b/src/main/java/org/gridsuite/ds/server/model/AbstractManuallyAssignedIdentifierEntity.java
similarity index 95%
rename from src/main/java/org/gridsuite/ds/server/repository/AbstractManuallyAssignedIdentifierEntity.java
rename to src/main/java/org/gridsuite/ds/server/model/AbstractManuallyAssignedIdentifierEntity.java
index 93b1eb90..1970f9ac 100644
--- a/src/main/java/org/gridsuite/ds/server/repository/AbstractManuallyAssignedIdentifierEntity.java
+++ b/src/main/java/org/gridsuite/ds/server/model/AbstractManuallyAssignedIdentifierEntity.java
@@ -4,7 +4,7 @@
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/.
*/
-package org.gridsuite.ds.server.repository;
+package org.gridsuite.ds.server.model;
import org.springframework.data.domain.Persistable;
diff --git a/src/main/java/org/gridsuite/ds/server/repository/ResultEntity.java b/src/main/java/org/gridsuite/ds/server/model/ResultEntity.java
similarity index 72%
rename from src/main/java/org/gridsuite/ds/server/repository/ResultEntity.java
rename to src/main/java/org/gridsuite/ds/server/model/ResultEntity.java
index fa002fab..15289243 100644
--- a/src/main/java/org/gridsuite/ds/server/repository/ResultEntity.java
+++ b/src/main/java/org/gridsuite/ds/server/model/ResultEntity.java
@@ -4,13 +4,13 @@
* 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/.
*/
-package org.gridsuite.ds.server.repository;
+package org.gridsuite.ds.server.model;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
-import javax.persistence.*;
+import javax.persistence.*;
import java.io.Serializable;
import java.util.UUID;
@@ -24,9 +24,10 @@
@Entity
public class ResultEntity extends AbstractManuallyAssignedIdentifierEntity implements Serializable {
- public ResultEntity(UUID id, Boolean result, String status) {
+ public ResultEntity(UUID id, UUID timeSeriesId, UUID timeLineId, String status) {
this.id = id;
- this.result = result;
+ this.timeSeriesId = timeSeriesId;
+ this.timeLineId = timeLineId;
this.status = status;
}
@@ -35,8 +36,11 @@ public ResultEntity(UUID id, Boolean result, String status) {
@GeneratedValue
private UUID id;
- @Column(name = "result")
- private Boolean result;
+ @Column(name = "timeSeriesUuid")
+ private UUID timeSeriesId;
+
+ @Column(name = "timeLineUuid")
+ private UUID timeLineId;
@Column(name = "status")
private String status;
diff --git a/src/main/java/org/gridsuite/ds/server/repository/ResultRepository.java b/src/main/java/org/gridsuite/ds/server/repository/ResultRepository.java
index 601f5e62..536330b8 100644
--- a/src/main/java/org/gridsuite/ds/server/repository/ResultRepository.java
+++ b/src/main/java/org/gridsuite/ds/server/repository/ResultRepository.java
@@ -6,6 +6,7 @@
*/
package org.gridsuite.ds.server.repository;
+import org.gridsuite.ds.server.model.ResultEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
diff --git a/src/main/java/org/gridsuite/ds/server/service/DynamicSimulationResultContext.java b/src/main/java/org/gridsuite/ds/server/service/DynamicSimulationResultContext.java
deleted file mode 100644
index dcdd3d86..00000000
--- a/src/main/java/org/gridsuite/ds/server/service/DynamicSimulationResultContext.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * Copyright (c) 2021, RTE (http://www.rte-france.com)
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-package org.gridsuite.ds.server.service;
-
-import com.powsybl.commons.PowsyblException;
-import org.springframework.messaging.Message;
-import org.springframework.messaging.MessageHeaders;
-import org.springframework.messaging.support.MessageBuilder;
-
-import java.util.*;
-
-/**
- * @author Abdelsalem Hedhili
- */
-public class DynamicSimulationResultContext {
-
- private final UUID resultUuid;
-
- private final DynamicSimulationRunContext runContext;
-
- public DynamicSimulationResultContext(UUID resultUuid, DynamicSimulationRunContext runContext) {
- this.resultUuid = Objects.requireNonNull(resultUuid);
- this.runContext = Objects.requireNonNull(runContext);
- }
-
- public UUID getResultUuid() {
- return resultUuid;
- }
-
- public DynamicSimulationRunContext getRunContext() {
- return runContext;
- }
-
- private static String getNonNullHeader(MessageHeaders headers, String name) {
- String header = (String) headers.get(name);
- if (header == null) {
- throw new PowsyblException("Header '" + name + "' not found");
- }
- return header;
- }
-
- public static DynamicSimulationResultContext fromMessage(Message message) {
- Objects.requireNonNull(message);
- MessageHeaders headers = message.getHeaders();
- UUID resultUuid = UUID.fromString(getNonNullHeader(headers, "resultUuid"));
- UUID networkUuid = UUID.fromString(getNonNullHeader(headers, "networkUuid"));
- String variantId = (String) headers.get("variantId");
- int startTime = Integer.parseInt(getNonNullHeader(headers, "startTime"));
- int stopTIme = Integer.parseInt(getNonNullHeader(headers, "stopTime"));
- byte[] dynamicModelContent = (byte[]) headers.get("dynamicModelContent");
- DynamicSimulationRunContext runContext = new DynamicSimulationRunContext(networkUuid, variantId, startTime, stopTIme, dynamicModelContent);
- return new DynamicSimulationResultContext(resultUuid, runContext);
- }
-
- public Message toMessage() {
- return MessageBuilder.withPayload("")
- .setHeader("resultUuid", resultUuid.toString())
- .setHeader("networkUuid", runContext.getNetworkUuid().toString())
- .setHeader("variantId", runContext.getVariantId())
- .setHeader("startTime", String.valueOf(runContext.getStartTime()))
- .setHeader("stopTime", String.valueOf(runContext.getStopTime()))
- .setHeader("dynamicModelContent", runContext.getDynamicModelContent())
- .build();
- }
-
-}
diff --git a/src/main/java/org/gridsuite/ds/server/service/DynamicSimulationRunContext.java b/src/main/java/org/gridsuite/ds/server/service/DynamicSimulationRunContext.java
deleted file mode 100644
index a602d519..00000000
--- a/src/main/java/org/gridsuite/ds/server/service/DynamicSimulationRunContext.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * Copyright (c) 2021, RTE (http://www.rte-france.com)
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-package org.gridsuite.ds.server.service;
-
-import java.util.Objects;
-import java.util.UUID;
-
-/**
- * @author Abdelsalem Hedhili
- */
-public class DynamicSimulationRunContext {
-
- private final UUID networkUuid;
-
- private final String variantId;
-
- private final int startTime;
-
- private final int stopTime;
-
- private final byte[] dynamicModelContent;
-
- public DynamicSimulationRunContext(UUID networkUuid, String variantId, int startTime, int stopTime, byte[] dynamicModelContent) {
- this.networkUuid = Objects.requireNonNull(networkUuid);
- this.variantId = variantId;
- this.startTime = startTime;
- this.stopTime = stopTime;
- this.dynamicModelContent = dynamicModelContent;
- }
-
- public UUID getNetworkUuid() {
- return networkUuid;
- }
-
- public String getVariantId() {
- return variantId;
- }
-
- public int getStartTime() {
- return startTime;
- }
-
- public int getStopTime() {
- return stopTime;
- }
-
- public byte[] getDynamicModelContent() {
- return dynamicModelContent;
- }
-}
-
diff --git a/src/main/java/org/gridsuite/ds/server/service/DynamicSimulationService.java b/src/main/java/org/gridsuite/ds/server/service/DynamicSimulationService.java
index 95499eb0..3296793b 100644
--- a/src/main/java/org/gridsuite/ds/server/service/DynamicSimulationService.java
+++ b/src/main/java/org/gridsuite/ds/server/service/DynamicSimulationService.java
@@ -6,20 +6,23 @@
*/
package org.gridsuite.ds.server.service;
+import com.powsybl.dynamicsimulation.DynamicSimulationParameters;
import org.gridsuite.ds.server.dto.DynamicSimulationStatus;
-import org.gridsuite.ds.server.repository.ResultEntity;
+import org.gridsuite.ds.server.model.ResultEntity;
import org.gridsuite.ds.server.repository.ResultRepository;
+import org.gridsuite.ds.server.service.client.dynamicmapping.DynamicMappingClient;
+import org.gridsuite.ds.server.service.contexts.DynamicSimulationCancelContext;
+import org.gridsuite.ds.server.service.contexts.DynamicSimulationResultContext;
+import org.gridsuite.ds.server.service.contexts.DynamicSimulationRunContext;
+import org.gridsuite.ds.server.service.notification.NotificationService;
+import org.gridsuite.ds.server.service.parameters.ParametersService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.cloud.stream.function.StreamBridge;
-import org.springframework.core.io.buffer.DefaultDataBufferFactory;
-import org.springframework.http.codec.multipart.FilePart;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Service;
-import org.springframework.util.StreamUtils;
import reactor.core.publisher.Mono;
+import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.UUID;
@@ -28,69 +31,82 @@
*/
@Service
public class DynamicSimulationService {
-
- private final ResultRepository resultRepository;
-
- @Autowired
- private StreamBridge publishRun;
-
private static final String CATEGORY_BROKER_OUTPUT = DynamicSimulationService.class.getName() + ".output-broker-messages";
-
private static final Logger LOGGER = LoggerFactory.getLogger(CATEGORY_BROKER_OUTPUT);
+ private final ResultRepository resultRepository;
+ private final NotificationService notificationService;
+ private final DynamicMappingClient dynamicMappingClient;
+ private final ParametersService parametersService;
- public DynamicSimulationService(ResultRepository resultRepository) {
+ public DynamicSimulationService(ResultRepository resultRepository, NotificationService notificationService, DynamicMappingClient dynamicMappingClient, ParametersService parametersService) {
this.resultRepository = Objects.requireNonNull(resultRepository);
+ this.notificationService = Objects.requireNonNull(notificationService);
+ this.dynamicMappingClient = Objects.requireNonNull(dynamicMappingClient);
+ this.parametersService = Objects.requireNonNull(parametersService);
}
- public Mono runAndSaveResult(UUID networkUuid, String variantId, int startTime, int stopTime, FilePart dynamicModel) {
-
- Mono fileBytes;
- fileBytes = dynamicModel.content().collectList().flatMap(all -> Mono.fromCallable(() ->
- StreamUtils.copyToByteArray(new DefaultDataBufferFactory().join(all).asInputStream())));
-
- return fileBytes.flatMap(bytes -> {
- DynamicSimulationRunContext runContext = new DynamicSimulationRunContext(networkUuid, variantId, startTime, stopTime, bytes);
- // update status to running status and store the dynamicModel file
- return insertStatus(DynamicSimulationStatus.RUNNING.name())
- .flatMap(resultEntity ->
- Mono.fromRunnable(() -> {
- Message message = new DynamicSimulationResultContext(resultEntity.getId(), runContext).toMessage();
- sendRunMessage(message);
- })
- .thenReturn(resultEntity.getId())
- );
- });
+ public Mono runAndSaveResult(String receiver, UUID networkUuid, String variantId, int startTime, int stopTime, String mappingName) {
+
+ return dynamicMappingClient.createFromMapping(mappingName) // get script and parameters file from dynamic mapping server
+ .flatMap(scriptObj -> {
+ // get all dynamic simulation parameters
+ String parametersFile = scriptObj.getParametersFile();
+ DynamicSimulationParameters parameters = parametersService.getDynamicSimulationParameters(parametersFile.getBytes(StandardCharsets.UTF_8));
+
+ // set start and stop times
+ parameters.setStartTime(startTime);
+ parameters.setStopTime(stopTime);
+
+ String script = scriptObj.getScript();
+ byte[] dynamicModel = script.getBytes(StandardCharsets.UTF_8);
+ byte[] eventModel = parametersService.getEventModel();
+ byte[] curveModel = parametersService.getCurveModel();
+
+ DynamicSimulationRunContext runContext = new DynamicSimulationRunContext(receiver, networkUuid, variantId, dynamicModel, eventModel, curveModel, parameters);
+
+ return insertStatus(DynamicSimulationStatus.RUNNING.name()) // update status to running status
+ .map(resultEntity -> {
+ Message message = new DynamicSimulationResultContext(resultEntity.getId(), runContext).toMessage();
+ notificationService.emitRunDynamicSimulationMessage(message);
+ return resultEntity.getId();
+ });
+ }
+ );
}
public Mono insertStatus(String status) {
- return Mono.fromCallable(() -> resultRepository.save(new ResultEntity(null, null, status)));
+ return Mono.fromCallable(() -> resultRepository.save(new ResultEntity(null, null, null, status)));
}
- public Mono getResult(UUID resultUuid) {
+ public Mono getTimeSeriesId(UUID resultUuid) {
Objects.requireNonNull(resultUuid);
- return Mono.fromCallable(() -> resultRepository.findById(resultUuid).map(ResultEntity::getResult)
- .orElse(null));
+ return Mono.fromCallable(() -> resultRepository.findById(resultUuid).map(ResultEntity::getTimeSeriesId)
+ .orElse(null));
}
- public Mono getStatus(UUID resultUuid) {
+ public Mono getTimeLineId(UUID resultUuid) {
Objects.requireNonNull(resultUuid);
- return Mono.fromCallable(() -> resultRepository.findById(resultUuid).map(ResultEntity::getStatus).orElse(null));
+ return Mono.fromCallable(() -> resultRepository.findById(resultUuid).map(ResultEntity::getTimeLineId)
+ .orElse(null));
+ }
+
+ public Mono getStatus(UUID resultUuid) {
+ Objects.requireNonNull(resultUuid);
+ return Mono.fromCallable(() -> resultRepository.findById(resultUuid).map(ResultEntity::getStatus).orElse(null)).map(DynamicSimulationStatus::valueOf);
}
public Mono deleteResult(UUID resultUuid) {
Objects.requireNonNull(resultUuid);
return Mono.fromRunnable(() -> resultRepository.deleteById(resultUuid))
- .doOnError(throwable -> LOGGER.error(throwable.toString(), throwable)).then();
+ .doOnError(throwable -> LOGGER.error(throwable.toString(), throwable)).then();
}
public Mono deleteResults() {
return Mono.fromRunnable(resultRepository::deleteAll)
- .doOnError(throwable -> LOGGER.error(throwable.toString(), throwable)).then();
+ .doOnError(throwable -> LOGGER.error(throwable.toString(), throwable)).then();
}
- private void sendRunMessage(Message message) {
- LOGGER.debug("Sending message : {}", message);
- publishRun.send("publishRun-out-0", message);
+ public Mono stop(String receiver, UUID resultUuid) {
+ return Mono.fromRunnable(() -> notificationService.emitCancelDynamicSimulationMessage(new DynamicSimulationCancelContext(receiver, resultUuid).toMessage()));
}
-
}
diff --git a/src/main/java/org/gridsuite/ds/server/service/DynamicSimulationWorkerService.java b/src/main/java/org/gridsuite/ds/server/service/DynamicSimulationWorkerService.java
index af0ab5dd..68c3a1cd 100644
--- a/src/main/java/org/gridsuite/ds/server/service/DynamicSimulationWorkerService.java
+++ b/src/main/java/org/gridsuite/ds/server/service/DynamicSimulationWorkerService.java
@@ -7,23 +7,25 @@
package org.gridsuite.ds.server.service;
import com.powsybl.commons.PowsyblException;
-import com.powsybl.dynamicsimulation.DynamicModelsSupplier;
-import com.powsybl.dynamicsimulation.DynamicSimulation;
-import com.powsybl.dynamicsimulation.DynamicSimulationParameters;
-import com.powsybl.dynamicsimulation.DynamicSimulationResult;
-import com.powsybl.dynamicsimulation.groovy.DynamicModelGroovyExtension;
-import com.powsybl.dynamicsimulation.groovy.GroovyDynamicModelsSupplier;
-import com.powsybl.dynamicsimulation.groovy.GroovyExtension;
+import com.powsybl.dynamicsimulation.*;
+import com.powsybl.dynamicsimulation.groovy.*;
import com.powsybl.dynawaltz.DynaWaltzProvider;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.VariantManagerConstants;
import com.powsybl.network.store.client.NetworkStoreService;
import com.powsybl.network.store.client.PreloadingStrategy;
-import org.gridsuite.ds.server.repository.ResultRepository;
+import com.powsybl.timeseries.StringTimeSeries;
+import com.powsybl.timeseries.TimeSeries;
+import com.powsybl.dynamicsimulation.groovy.GroovyCurvesSupplier;
+import com.powsybl.dynamicsimulation.groovy.GroovyEventModelsSupplier;
+import org.gridsuite.ds.server.dto.DynamicSimulationStatus;
+import org.gridsuite.ds.server.service.contexts.DynamicSimulationCancelContext;
+import org.gridsuite.ds.server.service.contexts.DynamicSimulationResultContext;
+import org.gridsuite.ds.server.service.contexts.DynamicSimulationRunContext;
+import org.gridsuite.ds.server.service.notification.NotificationService;
+import org.gridsuite.ds.server.service.client.timeseries.TimeSeriesClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.HttpStatus;
@@ -32,13 +34,10 @@
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import reactor.core.publisher.Mono;
+import reactor.core.scheduler.Schedulers;
import java.io.ByteArrayInputStream;
-import java.nio.file.FileSystem;
-import java.nio.file.FileSystems;
-import java.util.List;
-import java.util.Objects;
-import java.util.UUID;
+import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
@@ -56,48 +55,54 @@ public class DynamicSimulationWorkerService {
private static final Logger LOGGER_BROKER_INPUT = LoggerFactory.getLogger(CATEGORY_BROKER_INPUT);
- private static final String CATEGORY_BROKER_OUTPUT = DynamicSimulationService.class.getName() + ".output-broker-messages";
-
- private static final Logger OUTPUT_MESSAGE_LOGGER = LoggerFactory.getLogger(CATEGORY_BROKER_OUTPUT);
-
- private final ResultRepository resultRepository;
-
private final NetworkStoreService networkStoreService;
- private FileSystem fileSystem = FileSystems.getDefault();
+ private final NotificationService notificationService;
- @Autowired
- private StreamBridge publishResult;
+ private final TimeSeriesClient timeSeriesClient;
- private DynamicSimulationWorkerUpdateResult dynamicSimulationWorkerUpdateResult;
+ private final DynamicSimulationWorkerUpdateResult dynamicSimulationWorkerUpdateResult;
public DynamicSimulationWorkerService(NetworkStoreService networkStoreService,
- ResultRepository resultRepository,
+ NotificationService notificationService,
+ TimeSeriesClient timeSeriesClient,
DynamicSimulationWorkerUpdateResult dynamicSimulationWorkerUpdateResult) {
this.networkStoreService = networkStoreService;
- this.resultRepository = resultRepository;
+ this.notificationService = notificationService;
+ this.timeSeriesClient = timeSeriesClient;
this.dynamicSimulationWorkerUpdateResult = dynamicSimulationWorkerUpdateResult;
}
public Mono run(DynamicSimulationRunContext context) {
Objects.requireNonNull(context);
- LOGGER.info("Run dynamic simulation on network {}, startTime {}, stopTime {},", context.getNetworkUuid(), context.getStartTime(), context.getStopTime());
+ LOGGER.info("Run dynamic simulation on network {}, startTime {}, stopTime {},", context.getNetworkUuid(), context.getParameters().getStartTime(), context.getParameters().getStopTime());
Network network = getNetwork(context.getNetworkUuid());
- List extensions = GroovyExtension.find(DynamicModelGroovyExtension.class, DynaWaltzProvider.NAME);
- GroovyDynamicModelsSupplier dynamicModelsSupplier = new GroovyDynamicModelsSupplier(new ByteArrayInputStream(context.getDynamicModelContent()), extensions);
- DynamicSimulationParameters parameters = new DynamicSimulationParameters(context.getStartTime(), context.getStopTime());
+
+ List dynamicModelExtensions = GroovyExtension.find(DynamicModelGroovyExtension.class, DynaWaltzProvider.NAME);
+ DynamicModelsSupplier dynamicModelsSupplier = new GroovyDynamicModelsSupplier(new ByteArrayInputStream(context.getDynamicModelContent()), dynamicModelExtensions);
+
+ List eventModelExtensions = GroovyExtension.find(EventModelGroovyExtension.class, DynaWaltzProvider.NAME);
+ EventModelsSupplier eventModelsSupplier = new GroovyEventModelsSupplier(new ByteArrayInputStream(context.getEventModelContent()), eventModelExtensions);
+
+ List curveExtensions = GroovyExtension.find(CurveGroovyExtension.class, DynaWaltzProvider.NAME);
+ CurvesSupplier curvesSupplier = new GroovyCurvesSupplier(new ByteArrayInputStream(context.getCurveContent()), curveExtensions);
+
return Mono.fromCompletionStage(runAsync(network,
- context.getVariantId() != null ? context.getVariantId() : VariantManagerConstants.INITIAL_VARIANT_ID,
- dynamicModelsSupplier,
- parameters));
+ context.getVariantId() != null ? context.getVariantId() : VariantManagerConstants.INITIAL_VARIANT_ID,
+ dynamicModelsSupplier,
+ eventModelsSupplier,
+ curvesSupplier,
+ context.getParameters()));
}
public CompletableFuture runAsync(Network network,
String variantId,
DynamicModelsSupplier dynamicModelsSupplier,
+ EventModelsSupplier eventModelsSupplier,
+ CurvesSupplier curvesSupplier,
DynamicSimulationParameters dynamicSimulationParameters) {
- return DynamicSimulation.runAsync(network, dynamicModelsSupplier, n1 -> null, n1 -> null, variantId, dynamicSimulationParameters);
+ return DynamicSimulation.runAsync(network, dynamicModelsSupplier, eventModelsSupplier, curvesSupplier, variantId, dynamicSimulationParameters);
}
private Network getNetwork(UUID networkUuid) {
@@ -109,40 +114,59 @@ private Network getNetwork(UUID networkUuid) {
}
@Bean
- public Consumer> consumeRun() {
+ public Consumer> consumeRun() {
return message -> {
- LOGGER_BROKER_INPUT.debug("consume {}", message);
+ LOGGER_BROKER_INPUT.debug("consumeRun {}", message);
+ DynamicSimulationResultContext resultContext = DynamicSimulationResultContext.fromMessage(message);
try {
- DynamicSimulationResultContext resultContext = DynamicSimulationResultContext.fromMessage(message);
-
run(resultContext.getRunContext())
- .flatMap(result -> updateResult(resultContext.getResultUuid(), result.isOk()))
- .doOnSuccess(unused -> {
- Message sendMessage = MessageBuilder
- .withPayload("")
- .setHeader("resultUuid", resultContext.getResultUuid().toString())
- .build();
- sendResultMessage(sendMessage);
- LOGGER.info("Dynamic simulation complete (resultUuid='{}')", resultContext.getResultUuid());
- }).block();
+ .flatMap(result -> updateResult(resultContext.getResultUuid(), result))
+ .doOnSuccess(result -> {
+ Message sendMessage = MessageBuilder
+ .withPayload("")
+ .setHeader("resultUuid", resultContext.getResultUuid().toString())
+ .setHeader("receiver", resultContext.getRunContext().getReceiver())
+ .build();
+ notificationService.emitResultDynamicSimulationMessage(sendMessage);
+ LOGGER.info("Dynamic simulation complete (resultUuid='{}')", resultContext.getResultUuid());
+ })
+ .block();
} catch (Exception e) {
+ dynamicSimulationWorkerUpdateResult.doUpdateResult(resultContext.getResultUuid(), null, null, DynamicSimulationStatus.NOT_DONE);
LOGGER.error("error in consumeRun", e);
+ // S2142 Restore interrupted state...
+ if (e instanceof InterruptedException) {
+ Thread.currentThread().interrupt();
+ }
}
};
}
- public Mono updateResult(UUID resultUuid, Boolean result) {
+ public Mono updateResult(UUID resultUuid, DynamicSimulationResult result) {
Objects.requireNonNull(resultUuid);
- return Mono.fromRunnable(() -> dynamicSimulationWorkerUpdateResult.doUpdateResult(resultUuid, result));
- }
-
- public void setFileSystem(FileSystem fs) {
- this.fileSystem = fs;
+ List timeSeries = new ArrayList<>(result.getCurves().values());
+ StringTimeSeries timeLine = result.getTimeLine();
+ return Mono.zip(
+ timeSeriesClient.sendTimeSeries(timeSeries).subscribeOn(Schedulers.boundedElastic()),
+ timeSeriesClient.sendTimeSeries(Arrays.asList(timeLine)).subscribeOn(Schedulers.boundedElastic())
+ )
+ .map(uuidTuple -> {
+ UUID timeSeriesUuid = uuidTuple.getT1().getId();
+ UUID timeLineUuid = uuidTuple.getT2().getId();
+ DynamicSimulationStatus status = result.isOk() ? DynamicSimulationStatus.CONVERGED : DynamicSimulationStatus.DIVERGED;
+
+ dynamicSimulationWorkerUpdateResult.doUpdateResult(resultUuid, timeSeriesUuid, timeLineUuid, status);
+ return result;
+ });
}
- private void sendResultMessage(Message message) {
- OUTPUT_MESSAGE_LOGGER.debug("Sending message : {}", message);
- publishResult.send("publishResult-out-0", message);
+ @Bean
+ public Consumer> consumeCancel() {
+ return message -> {
+ LOGGER_BROKER_INPUT.debug("consumeCancel {}", message);
+ DynamicSimulationCancelContext cancelContext = DynamicSimulationCancelContext.fromMessage(message);
+ // TODO cancel implementation
+ };
}
}
diff --git a/src/main/java/org/gridsuite/ds/server/service/DynamicSimulationWorkerUpdateResult.java b/src/main/java/org/gridsuite/ds/server/service/DynamicSimulationWorkerUpdateResult.java
index e1079ca4..c34a106d 100644
--- a/src/main/java/org/gridsuite/ds/server/service/DynamicSimulationWorkerUpdateResult.java
+++ b/src/main/java/org/gridsuite/ds/server/service/DynamicSimulationWorkerUpdateResult.java
@@ -18,9 +18,10 @@ public DynamicSimulationWorkerUpdateResult(ResultRepository resultRepository) {
}
@Transactional
- public void doUpdateResult(UUID resultUuid, Boolean result) {
- var res = resultRepository.getOne(resultUuid);
- res.setResult(result);
- res.setStatus(DynamicSimulationStatus.COMPLETED.name());
+ public void doUpdateResult(UUID resultUuid, UUID timeSeriesUuid, UUID timeLineUuid, DynamicSimulationStatus status) {
+ var res = resultRepository.findById(resultUuid).orElseThrow();
+ res.setTimeSeriesId(timeSeriesUuid);
+ res.setTimeLineId(timeLineUuid);
+ res.setStatus(status.name());
}
}
diff --git a/src/main/java/org/gridsuite/ds/server/service/client/dynamicmapping/DynamicMappingClient.java b/src/main/java/org/gridsuite/ds/server/service/client/dynamicmapping/DynamicMappingClient.java
new file mode 100644
index 00000000..ee1cf5d2
--- /dev/null
+++ b/src/main/java/org/gridsuite/ds/server/service/client/dynamicmapping/DynamicMappingClient.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2022-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/.
+ */
+package org.gridsuite.ds.server.service.client.dynamicmapping;
+
+import org.gridsuite.ds.server.dto.dynamicmapping.Script;
+import reactor.core.publisher.Mono;
+
+/**
+ * @author Thang PHAM
+ */
+public interface DynamicMappingClient {
+ String API_VERSION = "";
+ String DELIMITER = "/";
+ String DYNAMIC_MAPPING_SCRIPT_BASE_END_POINT = "scripts";
+ String DYNAMIC_MAPPING_SCRIPT_CREATE_END_POINT = DYNAMIC_MAPPING_SCRIPT_BASE_END_POINT + DELIMITER + "from";
+
+ Mono