Skip to content

Disconnect energized equipment #446

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: resource_bundle
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ dynawo.dynasim.jsonEventModels = Dynawo Event Models Supplier
dynawo.dynasim.lowDynawoVersion = Model version ${modelVersion} is too low for the current dynawo version ${currentVersion} ({$endCauses}) -> model ${modelName} ${dynamicId} will be skipped
dynawo.dynasim.modelInstantiation = Model ${modelName} ${dynamicId} instantiation ${state}
dynawo.dynasim.modelNotFound = Model ${lib} not found for ${builderName}
dynawo.dynasim.notEnergized = '${fieldName}' field value '${staticId}' should be energized
dynawo.dynasim.outputVariableInstantiationError = Output variable ${id} cannot be instantiated
dynawo.dynasim.staticIdUnknown = '${fieldName}' field value '${staticId}' not found for equipment type(s) ${equipmentType}, id will be used as pure dynamic model id
dynawo.dynasim.unknownIdToDynamic = '${fieldName}' field value '${staticId}' not found for equipment type(s) ${equipmentType}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class ContingencyEventModelsTest {

@Test
void test() {
Network network = EurostagTutorialExample1Factory.create();
Network network = EurostagTutorialExample1Factory.createWithLFResults();
BlackBoxModelSupplier bbmSupplier = BlackBoxModelSupplier.createFrom(List.of(
BaseGeneratorBuilder.of(network)
.staticId("GEN")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import java.util.List;

import static com.powsybl.dynawo.algorithms.xml.AlgorithmsConstants.MULTIPLE_JOBS_FILENAME;
import static com.powsybl.iidm.network.test.EurostagTutorialExample1Factory.NGEN;
import static com.powsybl.iidm.network.test.EurostagTutorialExample1Factory.NHV1;

/**
* @author Laurent Issertial <laurent.issertial at rte-france.com>
Expand All @@ -30,6 +32,18 @@ class MultiplesJobsXmlTest extends AbstractDynamicModelXmlTest {
@Override
protected void setupNetwork() {
network = EurostagTutorialExample1Factory.createWithMultipleConnectedComponents();
network.getBusBreakerView().getBus(NGEN)
.setV(24.500000610351563)
.setAngle(2.3259763717651367);
network.getBusBreakerView().getBus(NHV1)
.setV(402.1428451538086)
.setAngle(0.0);
network.getBusBreakerView().getBus("NHV2")
.setV(389.9526763916016)
.setAngle(-3.5063576698303223);
network.getBusBreakerView().getBus("NLOAD")
.setV(147.57861328125)
.setAngle(-9.614486694335938);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@
import com.powsybl.dynamicsimulation.groovy.GroovyEventModelsSupplier;
import com.powsybl.dynamicsimulation.groovy.GroovyExtension;
import com.powsybl.dynawo.DynawoSimulationProvider;
import com.powsybl.dynawo.LfResultsUtils;
import com.powsybl.dynawo.models.events.*;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.test.EurostagTutorialExample1Factory;
import com.powsybl.iidm.network.test.HvdcTestNetwork;
import com.powsybl.iidm.network.test.SvcTestCaseFactory;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
Expand Down Expand Up @@ -77,53 +76,54 @@ void assertEventModel(AbstractEvent em, String dynamicId, String equipmentStatic

private static Stream<Arguments> provideEventModelData() {
return Stream.of(
Arguments.of("/eventModels/branchDisconnection.groovy", EventBranchDisconnection.class, EurostagTutorialExample1Factory.create(), "NHV1_NHV2_1", "Disconnect_NHV1_NHV2_1", "EventQuadripoleDisconnection", 4),
Arguments.of("/eventModels/equipmentDisconnection.groovy", EventInjectionDisconnection.class, EurostagTutorialExample1Factory.create(), "GEN", "Disconnect_GEN", null, 1),
Arguments.of("/eventModels/hvdcDisconnection.groovy", EventHvdcDisconnection.class, HvdcTestNetwork.createVsc(), "L", "Disconnect_L", null, 2),
Arguments.of("/eventModels/nodeFault.groovy", NodeFaultEvent.class, EurostagTutorialExample1Factory.create(), "NGEN", "NodeFault_NGEN", "NodeFault", 1),
Arguments.of("/eventModels/step.groovy", EventActivePowerVariation.class, EurostagTutorialExample1Factory.create(), "LOAD", "Step_LOAD", null, 2)
Arguments.of("/eventModels/branchDisconnection.groovy", EventBranchDisconnection.class, EurostagTutorialExample1Factory.createWithLFResults(), "NHV1_NHV2_1", "Disconnect_NHV1_NHV2_1", "EventQuadripoleDisconnection", 4),
Arguments.of("/eventModels/equipmentDisconnection.groovy", EventInjectionDisconnection.class, EurostagTutorialExample1Factory.createWithLFResults(), "GEN", "Disconnect_GEN", null, 1),
Arguments.of("/eventModels/hvdcDisconnection.groovy", EventHvdcDisconnection.class, LfResultsUtils.createHvdcTestNetworkVscWithLFResults(), "L", "Disconnect_L", null, 2),
Arguments.of("/eventModels/nodeFault.groovy", NodeFaultEvent.class, EurostagTutorialExample1Factory.createWithLFResults(), "NGEN", "NodeFault_NGEN", "NodeFault", 1),
Arguments.of("/eventModels/step.groovy", EventActivePowerVariation.class, EurostagTutorialExample1Factory.createWithLFResults(), "LOAD", "Step_LOAD", null, 2)
);
}

private static Stream<Arguments> provideWarningsModel() {
return Stream.of(
Arguments.of("/eventWarnings/missingStaticId.groovy", EurostagTutorialExample1Factory.create(),
Arguments.of("/eventWarnings/missingStaticId.groovy", EurostagTutorialExample1Factory.createWithLFResults(),
"""
+ DSL tests
+ Groovy Event Models Supplier
+ Model NodeFault NodeFault_GEN instantiation failed
'staticId' field value 'GEN' not found for equipment type(s) BUS
"""),
Arguments.of("/eventWarnings/missingStartTime.groovy", EurostagTutorialExample1Factory.create(),
Arguments.of("/eventWarnings/missingStartTime.groovy", EurostagTutorialExample1Factory.createWithLFResults(),
"""
+ DSL tests
+ Groovy Event Models Supplier
+ Model NodeFault NodeFault_NGEN instantiation failed
'startTime' field is not set
"""),
Arguments.of("/eventWarnings/missingNodeFaultParameters.groovy", EurostagTutorialExample1Factory.create(),
Arguments.of("/eventWarnings/missingNodeFaultParameters.groovy", EurostagTutorialExample1Factory.createWithLFResults(),
"""
+ DSL tests
+ Groovy Event Models Supplier
+ Model NodeFault NodeFault_NGEN instantiation failed
faultTime should be strictly positive (0.0)
"""),
Arguments.of("/eventWarnings/missingAPVParameters.groovy", SvcTestCaseFactory.create(),
Arguments.of("/eventWarnings/missingAPVParameters.groovy",
LfResultsUtils.createSvcTestCaseWithLFResults(),
"""
+ DSL tests
+ Groovy Event Models Supplier
+ Model Step Step_SVC2 instantiation failed
'staticId' field value 'SVC2' not found for equipment type(s) GENERATOR/LOAD
'deltaP' field is not set
"""),
Arguments.of("/eventWarnings/missingDisconnectionEquipment.groovy", EurostagTutorialExample1Factory.create(),
Arguments.of("/eventWarnings/missingDisconnectionEquipment.groovy", EurostagTutorialExample1Factory.createWithLFResults(),
"""
+ DSL tests
+ Groovy Event Models Supplier
+ Model Disconnect Disconnect_WRONG_ID instantiation failed
'staticId' field value 'WRONG_ID' not found for equipment type(s) Disconnectable equipment
"""),
Arguments.of("/eventWarnings/missingDisconnectionSide.groovy", EurostagTutorialExample1Factory.create(),
Arguments.of("/eventWarnings/missingDisconnectionSide.groovy", EurostagTutorialExample1Factory.createWithLFResults(),
"""
+ DSL tests
+ Groovy Event Models Supplier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public final class BuilderReports {

private static final String FIELD_NAME = "fieldName";
private static final String EQUIPMENT_TYPE_FIELD = "equipmentType";
private static final String STATIC_ID = "staticId";

private BuilderReports() {
}
Expand Down Expand Up @@ -79,7 +80,7 @@ public static void reportStaticIdUnknown(ReportNode reportNode, String fieldName
.withMessageTemplate("dynawo.dynasim.unknownIdToDynamic")
.withUntypedValue(EQUIPMENT_TYPE_FIELD, equipmentType)
.withUntypedValue(FIELD_NAME, fieldName)
.withUntypedValue("staticId", staticId)
.withUntypedValue(STATIC_ID, staticId)
.withSeverity(TypedValue.WARN_SEVERITY)
.add();
}
Expand All @@ -89,7 +90,7 @@ public static void reportDifferentNetwork(ReportNode reportNode, String fieldNam
.withMessageTemplate("dynawo.dynasim.wrongNetwork")
.withUntypedValue(EQUIPMENT_TYPE_FIELD, equipmentType)
.withUntypedValue(FIELD_NAME, fieldName)
.withUntypedValue("staticId", staticId)
.withUntypedValue(STATIC_ID, staticId)
.withSeverity(TypedValue.WARN_SEVERITY)
.add();
}
Expand All @@ -98,7 +99,8 @@ public static void reportUnknownStaticIdHandling(ReportNode reportNode, String f
reportNode.newReportNode()
.withMessageTemplate("dynawo.dynasim.staticIdUnknown")
.withUntypedValue(EQUIPMENT_TYPE_FIELD, equipmentType)
.withUntypedValue(FIELD_NAME, fieldName).withUntypedValue("staticId", staticId)
.withUntypedValue(FIELD_NAME, fieldName)
.withUntypedValue(STATIC_ID, staticId)
.withSeverity(TypedValue.INFO_SEVERITY)
.add();
}
Expand Down Expand Up @@ -148,4 +150,13 @@ public static void reportFieldConflict(ReportNode reportNode, String firstFieldN
.withSeverity(TypedValue.TRACE_SEVERITY)
.add();
}

public static void reportNotEnergized(ReportNode reportNode, String fieldName, String staticId) {
reportNode.newReportNode()
.withMessageTemplate("dynawo.dynasim.notEnergized")
.withUntypedValue(FIELD_NAME, fieldName)
.withTypedValue(STATIC_ID, staticId, TypedValue.ID)
.withSeverity(TypedValue.WARN_SEVERITY)
.add();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

import com.powsybl.iidm.network.*;

import static com.powsybl.dynawo.models.utils.EnergizedUtils.isEnergized;

/**
* @author Laurent Issertial {@literal <laurent.issertial at rte-france.com>}
*/
Expand All @@ -29,18 +31,9 @@ private BuildersUtil() {
public static Identifiable<?> getActionConnectionPoint(Network network, String staticId) {
BusbarSection busbarSection = network.getBusbarSection(staticId);
if (busbarSection != null) {
return isEnergizedBus(busbarSection.getTerminal().getBusBreakerView().getBus()) ? busbarSection : null;
return isEnergized(busbarSection) ? busbarSection : null;
}
Bus bus = network.getBusBreakerView().getBus(staticId);
return isEnergizedBus(bus) ? bus : null;
}

/**
* Verifies a bus is energized and in main connected component
* @param bus the reviewed bus
* @return <code>true</code> if energized, <code>false</code> if not
*/
private static boolean isEnergizedBus(Bus bus) {
return bus != null && !Double.isNaN(bus.getV()) && bus.isInMainConnectedComponent();
return isEnergized(bus) ? bus : null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@
package com.powsybl.dynawo.models.events;

import com.powsybl.commons.report.ReportNode;
import com.powsybl.dynawo.builders.BuilderEquipment;
import com.powsybl.dynawo.builders.BuilderReports;
import com.powsybl.dynawo.builders.EventModelInfo;
import com.powsybl.dynawo.builders.ModelInfo;
import com.powsybl.dynawo.builders.*;
import com.powsybl.dynawo.commons.DynawoVersion;
import com.powsybl.dynawo.models.utils.EnergizedUtils;
import com.powsybl.iidm.network.*;

/**
Expand Down Expand Up @@ -86,17 +84,46 @@ protected void checkData() {
super.checkData();
if (builderEquipment.hasEquipment()) {
setDisconnectionType(builderEquipment.getEquipment().getType());
if (disconnectionType == DisconnectionType.NONE) {
BuilderReports.reportStaticIdUnknown(reportNode, "staticId", builderEquipment.getStaticId(), "Disconnectable equipment");
isInstantiable = false;
}
if ((DisconnectionType.INJECTION == disconnectionType || DisconnectionType.BUS == disconnectionType) && disconnectSide != null) {
BuilderReports.reportFieldSetWithWrongEquipment(reportNode, "disconnectOnly", builderEquipment.getEquipment().getType(), builderEquipment.getStaticId());
isInstantiable = false;
switch (disconnectionType) {
case BUS -> {
Bus bus = (Bus) builderEquipment.getEquipment();
handleNotEnergized(EnergizedUtils.isEnergized(bus));
if (disconnectSide != null) {
BuilderReports.reportFieldSetWithWrongEquipment(reportNode, "disconnectOnly", bus.getType(), bus.getId());
isInstantiable = false;
}
}
case INJECTION -> {
Injection<?> injection = (Injection<?>) builderEquipment.getEquipment();
handleNotEnergized(EnergizedUtils.isEnergized(injection));
if (disconnectSide != null) {
BuilderReports.reportFieldSetWithWrongEquipment(reportNode, "disconnectOnly", injection.getType(), injection.getId());
isInstantiable = false;
}
}
case BRANCH -> {
Branch<?> branch = (Branch<?>) builderEquipment.getEquipment();
handleNotEnergized(disconnectSide != null ? EnergizedUtils.isEnergized(branch, disconnectSide) : EnergizedUtils.isEnergized(branch));
}
case HVDC -> {
HvdcLine hvdcLine = (HvdcLine) builderEquipment.getEquipment();
handleNotEnergized(disconnectSide != null ? EnergizedUtils.isEnergized(hvdcLine, disconnectSide) : EnergizedUtils.isEnergized(hvdcLine));
}
case NONE -> {
BuilderReports.reportStaticIdUnknown(reportNode, "staticId", builderEquipment.getStaticId(), "Disconnectable equipment");
isInstantiable = false;
}
}
}
}

private void handleNotEnergized(boolean isEnergized) {
if (!isEnergized) {
BuilderReports.reportNotEnergized(reportNode, "staticId", builderEquipment.getStaticId());
isInstantiable = false;
}
}

@Override
public AbstractEvent build() {
if (isInstantiable()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* Copyright (c) 2025, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.dynawo.models.utils;

import com.powsybl.iidm.network.*;

/**
* Verifies na equipment terminal(s) are connected and the relates buses are energized and in main connected component
* @author Laurent Issertial {@literal <laurent.issertial at rte-france.com>}
*/
public final class EnergizedUtils {

private EnergizedUtils() {
}

public static boolean isEnergized(Injection<?> equipment) {
return isEnergized(equipment.getTerminal());
}

public static boolean isEnergized(Branch<?> equipment) {
return isEnergized(equipment.getTerminal1()) && isEnergized(equipment.getTerminal2());
}

public static boolean isEnergized(Branch<?> equipment, TwoSides side) {
return TwoSides.ONE == side ? isEnergized(equipment.getTerminal1()) : isEnergized(equipment.getTerminal2());
}

public static boolean isEnergized(HvdcLine equipment) {
return isEnergized(equipment.getConverterStation1().getTerminal())
&& isEnergized(equipment.getConverterStation1().getTerminal());
}

public static boolean isEnergized(HvdcLine equipment, TwoSides side) {
return TwoSides.ONE == side ? isEnergized(equipment.getConverterStation1().getTerminal())
: isEnergized(equipment.getConverterStation2().getTerminal());
}

public static boolean isEnergized(Terminal terminal) {
if (!terminal.isConnected()) {
return false;
}
return isEnergized(terminal.getBusBreakerView().getBus());
}

/**
* Verifies a bus is energized and in main connected component
* @param bus the reviewed bus
* @return <code>true</code> if energized, <code>false</code> if not
*/
public static boolean isEnergized(Bus bus) {
return bus != null && !Double.isNaN(bus.getV()) && bus.isInMainConnectedComponent();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* Copyright (c) 2025, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.dynawo;

import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.test.HvdcTestNetwork;
import com.powsybl.iidm.network.test.SvcTestCaseFactory;

/**
* @author Laurent Issertial {@literal <laurent.issertial at rte-france.com>}
*/
public final class LfResultsUtils {

private LfResultsUtils() {
}

public static Network createSvcTestCaseWithLFResults() {
Network network = SvcTestCaseFactory.create();
network.getBusBreakerView().getBuses().forEach(b -> b.setV(400).setAngle(0));
return network;
}

public static Network createHvdcTestNetworkVscWithLFResults() {
Network network = HvdcTestNetwork.createVsc();
network.getBusBreakerView().getBus("B1").setV(400).setAngle(0);
network.getVoltageLevel("VL2").getBusView().getBuses().forEach(b -> b.setV(400).setAngle(0));
return network;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class DynawoEventModelsSupplierTest {

@Test
void testEventSupplier() {
Network network = EurostagTutorialExample1Factory.create();
Network network = EurostagTutorialExample1Factory.createWithLFResults();
List<EventModelConfig> eventModelConfigList = getEventConfigs();
List<EventModel> events = new DynawoEventModelsSupplier(eventModelConfigList).get(network, ReportNode.NO_OP);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class DisconnectBranchEventXmlTest extends AbstractDynamicModelXmlTest {

@Override
protected void setupNetwork() {
network = EurostagTutorialExample1Factory.create();
network = EurostagTutorialExample1Factory.createWithLFResults();
}

@Override
Expand Down
Loading