Skip to content

Commit

Permalink
Model version (#382)
Browse files Browse the repository at this point in the history
* Add Dynawo VersionInterval to all dynamic model
* Check the version against current version in DynawoSimulationContext
* Add to all builder a new version of getSupportedModelInfos filtered by version
* Check the event models version against current version in DynawoSimulationContext
* Add Library properties documentation
* Update models.json
* Add "model not instantiable" builder test
* Add missing model versions

Signed-off-by: lisrte <[email protected]>
  • Loading branch information
Lisrte authored Oct 8, 2024
1 parent 57c4cde commit aa604dd
Show file tree
Hide file tree
Showing 101 changed files with 851 additions and 246 deletions.
18 changes: 10 additions & 8 deletions commons/src/main/java/com/powsybl/dynawo/commons/DynawoUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,31 +44,33 @@ public static void writeIidm(Network network, Path file) {
network.write("XIIDM", params, file);
}

public static void requireDynaMinVersion(ExecutionEnvironment env, ComputationManager computationManager, Command versionCmd,
String dynaName, boolean fromErr) {
if (!checkDynawoVersion(env, computationManager, versionCmd, fromErr)) {
public static DynawoVersion requireDynaMinVersion(ExecutionEnvironment env, ComputationManager computationManager,
Command versionCmd, String dynaName, boolean fromErr) {
DynawoVersion version = getDynawoVersion(env, computationManager, versionCmd, fromErr);
if (DynawoConstants.VERSION_MIN.compareTo(version) > 0) {
throw new PowsyblException(dynaName + " version not supported. Must be >= " + DynawoConstants.VERSION_MIN);
}
return version;
}

public static boolean checkDynawoVersion(ExecutionEnvironment env, ComputationManager computationManager, Command versionCmd, boolean fromErr) {
return computationManager.execute(env, new AbstractExecutionHandler<Boolean>() {
private static DynawoVersion getDynawoVersion(ExecutionEnvironment env, ComputationManager computationManager,
Command versionCmd, boolean fromErr) {
return computationManager.execute(env, new AbstractExecutionHandler<DynawoVersion>() {
@Override
public List<CommandExecution> before(Path path) {
return Collections.singletonList(new CommandExecution(versionCmd, 1));
}

@Override
public Boolean after(Path workingDir, ExecutionReport report) throws IOException {
public DynawoVersion after(Path workingDir, ExecutionReport report) throws IOException {
super.after(workingDir, report);
Optional<InputStream> std = fromErr ? report.getStdErr(versionCmd, 0) : report.getStdOut(versionCmd, 0);
if (std.isEmpty()) {
throw new PowsyblException("No output for DynaFlow version command");
}
try (Reader reader = new InputStreamReader(std.get())) {
String stdErrContent = CharStreams.toString(reader);
DynawoVersion version = DynawoVersion.createFromString(versionSanitizer(stdErrContent));
return DynawoConstants.VERSION_MIN.compareTo(version) < 1;
return DynawoVersion.createFromString(versionSanitizer(stdErrContent));
}
}
}).join();
Expand Down
4 changes: 4 additions & 0 deletions docs/dynamic_simulation/dynamic-models-dsl.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ The list is statically loaded via [ModelConfigLoader](https://javadoc.io/doc/com
* `alias`: name used in powsybl-dynawo instead of lib
* `properties`: dynamic model properties (synchronized, dangling, etc.)
* `internalModelPrefix`: used for dyd file creation
* `doc`: library documentation
* `minVersion`: Dynawo minimum version required
* `maxVersion`: Dynawo maximum version required
* `endCause`: explains the cause of the model ending at `maxVersion`

## Dynamic model Builder List
Ultimately, all groovy scripts call dedicated builders that can be used directly by developers.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import com.google.common.jimfs.Configuration;
import com.google.common.jimfs.Jimfs;
import com.powsybl.commons.PowsyblException;
import com.powsybl.computation.Command;
import com.powsybl.computation.ComputationManager;
import com.powsybl.computation.ExecutionEnvironment;
Expand All @@ -16,6 +17,7 @@
import com.powsybl.computation.local.LocalComputationConfig;
import com.powsybl.computation.local.LocalComputationManager;
import com.powsybl.dynawo.commons.DynawoUtil;
import com.powsybl.dynawo.commons.DynawoVersion;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -79,14 +81,15 @@ void tearDown() throws IOException {
void versionTest() throws IOException {
LocalCommandExecutor commandExecutor = new LocalCommandExecutorMock("/dynawo_version.out");
ComputationManager computationManager = new LocalComputationManager(new LocalComputationConfig(fileSystem.getPath("/working-dir"), 1), commandExecutor, ForkJoinPool.commonPool());
assertTrue(DynawoUtil.checkDynawoVersion(env, computationManager, versionCmd, true));
assertEquals(new DynawoVersion(1, 5, 0), DynawoUtil.requireDynaMinVersion(env, computationManager, versionCmd, "DynaFlow", true));
}

@Test
void badVersionTest() throws IOException {
LocalCommandExecutor commandExecutor = new LocalCommandExecutorMock("/dynawo_bad_version.out");
ComputationManager computationManager = new LocalComputationManager(new LocalComputationConfig(fileSystem.getPath("/working-dir"), 1), commandExecutor, ForkJoinPool.commonPool());
assertFalse(DynawoUtil.checkDynawoVersion(env, computationManager, versionCmd, true));
PowsyblException e = assertThrows(PowsyblException.class, () -> DynawoUtil.requireDynaMinVersion(env, computationManager, versionCmd, "DynaFlow", true));
assertEquals("DynaFlow version not supported. Must be >= 1.5.0", e.getMessage());
}

@Test
Expand All @@ -97,7 +100,7 @@ void versionTestNotExistingFile() throws IOException {
.build();
LocalCommandExecutor commandExecutor = new LocalCommandExecutorMock("/dynaflow_version.out");
ComputationManager computationManager = new LocalComputationManager(new LocalComputationConfig(fileSystem.getPath("/working-dir"), 1), commandExecutor, ForkJoinPool.commonPool());
CompletionException e = assertThrows(CompletionException.class, () -> DynawoUtil.checkDynawoVersion(env, computationManager, badVersionCmd, true));
CompletionException e = assertThrows(CompletionException.class, () -> DynawoUtil.requireDynaMinVersion(env, computationManager, badVersionCmd, "DynaFlow", true));
assertEquals("com.powsybl.commons.PowsyblException: No output for DynaFlow version command", e.getMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.powsybl.dynamicsimulation.DynamicModelsSupplier;
import com.powsybl.dynawo.DynawoSimulationParameters;
import com.powsybl.dynawo.DynawoSimulationProvider;
import com.powsybl.dynawo.commons.DynawoVersion;
import com.powsybl.dynawo.models.utils.BlackBoxSupplierUtils;
import com.powsybl.dynawo.xml.DynawoSimulationConstants;
import com.powsybl.dynawo.commons.DynawoUtil;
Expand Down Expand Up @@ -79,14 +80,15 @@ public CompletableFuture<SecurityAnalysisReport> run(Network network, String wor
ReportNode dsaReportNode = DynamicSecurityAnalysisReports.createDynamicSecurityAnalysisReportNode(runParameters.getReportNode(), network.getId());
network.getVariantManager().setWorkingVariant(workingVariantId);
ExecutionEnvironment execEnv = new ExecutionEnvironment(Collections.emptyMap(), WORKING_DIR_PREFIX, config.isDebug());
DynawoUtil.requireDynaMinVersion(execEnv, runParameters.getComputationManager(), getVersionCommand(config), DYNAWO_LAUNCHER_PROGRAM_NAME, false);
DynawoVersion currentVersion = DynawoUtil.requireDynaMinVersion(execEnv, runParameters.getComputationManager(), getVersionCommand(config), DYNAWO_LAUNCHER_PROGRAM_NAME, false);
List<Contingency> contingencies = contingenciesProvider.getContingencies(network);
DynamicSecurityAnalysisParameters parameters = runParameters.getDynamicSecurityAnalysisParameters();
SecurityAnalysisContext context = new SecurityAnalysisContext(network, workingVariantId,
BlackBoxSupplierUtils.getBlackBoxModelList(dynamicModelsSupplier, network, dsaReportNode),
parameters,
DynawoSimulationParameters.load(parameters.getDynamicSimulationParameters()),
contingencies);
contingencies,
currentVersion);

return runParameters.getComputationManager().execute(execEnv, new DynawoSecurityAnalysisHandler(context, getCommand(config), runParameters.getFilter(), runParameters.getInterceptors(), dsaReportNode));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@
package com.powsybl.dynawo.security;

import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.report.ReportNode;
import com.powsybl.contingency.Contingency;
import com.powsybl.contingency.ContingencyElement;
import com.powsybl.dynawo.DynawoSimulationContext;
import com.powsybl.dynawo.DynawoSimulationParameters;
import com.powsybl.dynawo.commons.DynawoConstants;
import com.powsybl.dynawo.commons.DynawoVersion;
import com.powsybl.dynawo.models.BlackBoxModel;
import com.powsybl.dynawo.models.events.ContextDependentEvent;
import com.powsybl.dynawo.models.events.EventDisconnectionBuilder;
Expand All @@ -37,8 +40,17 @@ public SecurityAnalysisContext(Network network, String workingVariantId,
DynamicSecurityAnalysisParameters parameters,
DynawoSimulationParameters dynawoSimulationParameters,
List<Contingency> contingencies) {
this(network, workingVariantId, dynamicModels, parameters, dynawoSimulationParameters, contingencies, DynawoConstants.VERSION_MIN);
}

public SecurityAnalysisContext(Network network, String workingVariantId,
List<BlackBoxModel> dynamicModels,
DynamicSecurityAnalysisParameters parameters,
DynawoSimulationParameters dynawoSimulationParameters,
List<Contingency> contingencies,
DynawoVersion currentVersion) {
super(network, workingVariantId, dynamicModels, List.of(), Collections.emptyList(),
parameters.getDynamicSimulationParameters(), dynawoSimulationParameters);
parameters.getDynamicSimulationParameters(), dynawoSimulationParameters, currentVersion, ReportNode.NO_OP);
double contingenciesStartTime = parameters.getDynamicContingenciesParameters().getContingenciesStartTime();
this.contingencies = contingencies;
this.contingencyEventModels = contingencies.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
import com.powsybl.commons.report.ReportNode;
import com.powsybl.dynamicsimulation.Curve;
import com.powsybl.dynamicsimulation.DynamicSimulationParameters;
import com.powsybl.dynawo.builders.VersionInterval;
import com.powsybl.dynawo.commons.DynawoConstants;
import com.powsybl.dynawo.commons.DynawoVersion;
import com.powsybl.dynawo.curves.DynawoCurve;
import com.powsybl.dynawo.models.AbstractPureDynamicBlackBoxModel;
import com.powsybl.dynawo.models.BlackBoxModel;
Expand Down Expand Up @@ -63,26 +66,31 @@ public class DynawoSimulationContext {

public DynawoSimulationContext(Network network, String workingVariantId, List<BlackBoxModel> dynamicModels, List<BlackBoxModel> eventModels,
List<Curve> curves, DynamicSimulationParameters parameters, DynawoSimulationParameters dynawoSimulationParameters) {
this(network, workingVariantId, dynamicModels, eventModels, curves, parameters, dynawoSimulationParameters, ReportNode.NO_OP);
this(network, workingVariantId, dynamicModels, eventModels, curves, parameters, dynawoSimulationParameters, DynawoConstants.VERSION_MIN, ReportNode.NO_OP);
}

public DynawoSimulationContext(Network network, String workingVariantId, List<BlackBoxModel> dynamicModels, List<BlackBoxModel> eventModels,
List<Curve> curves, DynamicSimulationParameters parameters, DynawoSimulationParameters dynawoSimulationParameters, ReportNode reportNode) {
List<Curve> curves, DynamicSimulationParameters parameters, DynawoSimulationParameters dynawoSimulationParameters,
DynawoVersion currentVersion, ReportNode reportNode) {

ReportNode contextReportNode = DynawoSimulationReports.createDynawoSimulationContextReportNode(reportNode);
DynawoVersion dynawoVersion = Objects.requireNonNull(currentVersion);
this.network = Objects.requireNonNull(network);
this.workingVariantId = Objects.requireNonNull(workingVariantId);
this.parameters = Objects.requireNonNull(parameters);
this.dynawoSimulationParameters = Objects.requireNonNull(dynawoSimulationParameters);

Stream<BlackBoxModel> uniqueIdsDynamicModels = Objects.requireNonNull(dynamicModels).stream()
.filter(distinctByDynamicId(contextReportNode).and(distinctByStaticId(contextReportNode)));
.filter(distinctByDynamicId(contextReportNode)
.and(distinctByStaticId(contextReportNode)
.and(supportedVersion(dynawoVersion, contextReportNode))));
this.dynamicModels = dynawoSimulationParameters.isUseModelSimplifiers()
? simplifyModels(uniqueIdsDynamicModels, contextReportNode).toList()
: uniqueIdsDynamicModels.toList();

this.eventModels = Objects.requireNonNull(eventModels).stream()
.filter(distinctByDynamicId(contextReportNode))
.filter(distinctByDynamicId(contextReportNode)
.and(supportedVersion(dynawoVersion, contextReportNode)))
.toList();
this.staticIdBlackBoxModelMap = getInputBlackBoxDynamicModelStream()
.filter(EquipmentBlackBoxModel.class::isInstance)
Expand Down Expand Up @@ -235,6 +243,21 @@ protected static Predicate<BlackBoxModel> distinctByDynamicId(ReportNode reportN
};
}

protected static Predicate<BlackBoxModel> supportedVersion(DynawoVersion currentVersion, ReportNode reportNode) {
return bbm -> {
VersionInterval versionInterval = bbm.getVersionInterval();
if (currentVersion.compareTo(versionInterval.min()) < 0) {
DynawoSimulationReports.reportDynawoVersionTooHigh(reportNode, bbm.getName(), bbm.getDynamicModelId(), versionInterval.min(), currentVersion);
return false;
}
if (versionInterval.max() != null && currentVersion.compareTo(versionInterval.max()) >= 0) {
DynawoSimulationReports.reportDynawoVersionTooLow(reportNode, bbm.getName(), bbm.getDynamicModelId(), versionInterval.max(), currentVersion, versionInterval.endCause());
return false;
}
return true;
};
}

public boolean hasDynamicModel(Identifiable<?> equipment) {
return staticIdBlackBoxModelMap.containsKey(equipment.getId());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.powsybl.commons.report.ReportNode;
import com.powsybl.computation.*;
import com.powsybl.dynamicsimulation.*;
import com.powsybl.dynawo.commons.DynawoVersion;
import com.powsybl.dynawo.models.utils.BlackBoxSupplierUtils;
import com.powsybl.dynawo.commons.DynawoUtil;
import com.powsybl.dynawo.commons.PowsyblDynawoVersion;
Expand Down Expand Up @@ -88,13 +89,14 @@ public CompletableFuture<DynamicSimulationResult> run(Network network, DynamicMo
ReportNode dsReportNode = DynawoSimulationReports.createDynawoSimulationReportNode(reportNode, network.getId());
network.getVariantManager().setWorkingVariant(workingVariantId);
ExecutionEnvironment execEnv = new ExecutionEnvironment(Collections.emptyMap(), WORKING_DIR_PREFIX, config.isDebug());
DynawoUtil.requireDynaMinVersion(execEnv, computationManager, getVersionCommand(config), DynawoSimulationConfig.DYNAWO_LAUNCHER_PROGRAM_NAME, false);
DynawoVersion currentVersion = DynawoUtil.requireDynaMinVersion(execEnv, computationManager, getVersionCommand(config), DynawoSimulationConfig.DYNAWO_LAUNCHER_PROGRAM_NAME, false);
DynawoSimulationContext context = new DynawoSimulationContext(network, workingVariantId,
BlackBoxSupplierUtils.getBlackBoxModelList(dynamicModelsSupplier, network, dsReportNode),
BlackBoxSupplierUtils.getBlackBoxModelList(eventModelsSupplier, network, dsReportNode),
curvesSupplier.get(network),
parameters,
DynawoSimulationParameters.load(parameters),
currentVersion,
reportNode);

return computationManager.execute(execEnv, new DynawoSimulationHandler(context, getCommand(config), reportNode));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import com.powsybl.commons.report.ReportNode;
import com.powsybl.commons.report.TypedValue;
import com.powsybl.dynawo.commons.DynawoVersion;
import org.apache.commons.lang3.StringUtils;

/**
Expand All @@ -17,6 +18,7 @@
public final class DynawoSimulationReports {

private static final String DYNAMIC_ID_FIELD = "dynamicId";
private static final String MODEL_NAME_FIELD = "modelName";

private DynawoSimulationReports() {
}
Expand All @@ -38,7 +40,7 @@ public static void reportDuplicateStaticId(ReportNode reportNode, String duplica
reportNode.newReportNode()
.withMessageTemplate("duplicateStaticId", "Duplicate static id found: ${duplicateId} -> model ${modelName} ${dynamicId} will be skipped")
.withUntypedValue("duplicateId", duplicateId)
.withUntypedValue("modelName", modelName)
.withUntypedValue(MODEL_NAME_FIELD, modelName)
.withUntypedValue(DYNAMIC_ID_FIELD, dynamicId)
.withSeverity(TypedValue.WARN_SEVERITY)
.add();
Expand All @@ -49,7 +51,30 @@ public static void reportDuplicateDynamicId(ReportNode reportNode, String duplic
.withMessageTemplate("duplicateDynamicId",
"Duplicate dynamic id found: ${duplicateId} -> model ${modelName} will be skipped")
.withUntypedValue("duplicateId", duplicateId)
.withUntypedValue("modelName", modelName)
.withUntypedValue(MODEL_NAME_FIELD, modelName)
.withSeverity(TypedValue.WARN_SEVERITY)
.add();
}

public static void reportDynawoVersionTooHigh(ReportNode reportNode, String modelName, String dynamicId, DynawoVersion modelVersion, DynawoVersion currentVersion) {
reportNode.newReportNode()
.withMessageTemplate("highDynawoVersion", "Model version ${modelVersion} is too high for the current dynawo version ${currentVersion} -> model ${modelName} ${dynamicId} will be skipped")
.withUntypedValue("modelVersion", modelVersion.toString())
.withUntypedValue("currentVersion", currentVersion.toString())
.withUntypedValue(MODEL_NAME_FIELD, modelName)
.withUntypedValue(DYNAMIC_ID_FIELD, dynamicId)
.withSeverity(TypedValue.WARN_SEVERITY)
.add();
}

public static void reportDynawoVersionTooLow(ReportNode reportNode, String modelName, String dynamicId, DynawoVersion modelVersion, DynawoVersion currentVersion, String endCause) {
reportNode.newReportNode()
.withMessageTemplate("lowDynawoVersion", "Model version ${modelVersion} is too low for the current dynawo version ${currentVersion} ({$endCauses}) -> model ${modelName} ${dynamicId} will be skipped")
.withUntypedValue("modelVersion", modelVersion.toString())
.withUntypedValue("currentVersion", currentVersion.toString())
.withUntypedValue("endCause", endCause)
.withUntypedValue(MODEL_NAME_FIELD, modelName)
.withUntypedValue(DYNAMIC_ID_FIELD, dynamicId)
.withSeverity(TypedValue.WARN_SEVERITY)
.add();
}
Expand Down
Loading

0 comments on commit aa604dd

Please sign in to comment.