diff --git a/pom.xml b/pom.xml
index d4631d1fe..e82f2161a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,6 +49,8 @@
0.0.2
1.16.2
org.gridsuite.modification.server
+
+ 1.18.1
@@ -84,6 +86,24 @@
+
+ com.powsybl
+ powsybl-network-store-client
+
+ ${powsybl-network-store.version}
+
+
+
+ com.powsybl
+ powsybl-network-store-iidm-impl
+ ${powsybl-network-store.version}
+
+
+
+ com.powsybl
+ powsybl-network-store-model
+ ${powsybl-network-store.version}
+
diff --git a/src/main/java/org/gridsuite/modification/server/ModificationType.java b/src/main/java/org/gridsuite/modification/server/ModificationType.java
index a95415d71..2abc233c9 100644
--- a/src/main/java/org/gridsuite/modification/server/ModificationType.java
+++ b/src/main/java/org/gridsuite/modification/server/ModificationType.java
@@ -31,6 +31,7 @@ public enum ModificationType {
SUBSTATION_MODIFICATION(PreloadingStrategy.NONE),
SHUNT_COMPENSATOR_CREATION(PreloadingStrategy.NONE),
SHUNT_COMPENSATOR_MODIFICATION(PreloadingStrategy.NONE),
+ STATIC_VAR_COMPENSATOR_CREATION(PreloadingStrategy.NONE),
VOLTAGE_LEVEL_CREATION(PreloadingStrategy.NONE),
VOLTAGE_LEVEL_MODIFICATION(PreloadingStrategy.NONE),
LINE_SPLIT_WITH_VOLTAGE_LEVEL(PreloadingStrategy.NONE),
diff --git a/src/main/java/org/gridsuite/modification/server/NetworkModificationException.java b/src/main/java/org/gridsuite/modification/server/NetworkModificationException.java
index 493c4f654..2c72e6545 100644
--- a/src/main/java/org/gridsuite/modification/server/NetworkModificationException.java
+++ b/src/main/java/org/gridsuite/modification/server/NetworkModificationException.java
@@ -49,6 +49,7 @@ public enum Type {
CREATE_GENERATOR_ERROR(HttpStatus.INTERNAL_SERVER_ERROR),
CREATE_SHUNT_COMPENSATOR_ERROR(HttpStatus.INTERNAL_SERVER_ERROR),
MODIFY_SHUNT_COMPENSATOR_ERROR(HttpStatus.INTERNAL_SERVER_ERROR),
+ CREATE_STATIC_VAR_COMPENSATOR_ERROR(HttpStatus.INTERNAL_SERVER_ERROR),
DELETE_EQUIPMENT_ERROR(HttpStatus.INTERNAL_SERVER_ERROR),
BY_FILTER_DELETION_ERROR(HttpStatus.INTERNAL_SERVER_ERROR),
EQUIPMENT_NOT_FOUND(HttpStatus.NOT_FOUND),
@@ -70,6 +71,8 @@ public enum Type {
GENERATOR_ALREADY_EXISTS(HttpStatus.BAD_REQUEST),
SHUNT_COMPENSATOR_ALREADY_EXISTS(HttpStatus.BAD_REQUEST),
SHUNT_COMPENSATOR_NOT_FOUND(HttpStatus.NOT_FOUND),
+ STATIC_VAR_COMPENSATOR_ALREADY_EXISTS(HttpStatus.BAD_REQUEST),
+ STATIC_VAR_COMPENSATOR_NOT_FOUND(HttpStatus.NOT_FOUND),
LINE_ALREADY_EXISTS(HttpStatus.BAD_REQUEST),
TWO_WINDINGS_TRANSFORMER_ALREADY_EXISTS(HttpStatus.BAD_REQUEST),
TWO_WINDINGS_TRANSFORMER_CREATION_ERROR(HttpStatus.BAD_REQUEST),
diff --git a/src/main/java/org/gridsuite/modification/server/dto/ModificationInfos.java b/src/main/java/org/gridsuite/modification/server/dto/ModificationInfos.java
index eb5811353..2ef27c5e6 100644
--- a/src/main/java/org/gridsuite/modification/server/dto/ModificationInfos.java
+++ b/src/main/java/org/gridsuite/modification/server/dto/ModificationInfos.java
@@ -49,6 +49,7 @@
@JsonSubTypes.Type(value = VoltageLevelModificationInfos.class),
@JsonSubTypes.Type(value = ShuntCompensatorCreationInfos.class),
@JsonSubTypes.Type(value = ShuntCompensatorModificationInfos.class),
+ @JsonSubTypes.Type(value = StaticVarCompensatorCreationInfos.class),
@JsonSubTypes.Type(value = TwoWindingsTransformerCreationInfos.class),
@JsonSubTypes.Type(value = TwoWindingsTransformerModificationInfos.class),
@JsonSubTypes.Type(value = EquipmentDeletionInfos.class),
diff --git a/src/main/java/org/gridsuite/modification/server/dto/StaticVarCompensatorCreationInfos.java b/src/main/java/org/gridsuite/modification/server/dto/StaticVarCompensatorCreationInfos.java
new file mode 100644
index 000000000..b86fd6927
--- /dev/null
+++ b/src/main/java/org/gridsuite/modification/server/dto/StaticVarCompensatorCreationInfos.java
@@ -0,0 +1,109 @@
+/**
+ * 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/.
+ */
+package org.gridsuite.modification.server.dto;
+
+import com.fasterxml.jackson.annotation.JsonTypeName;
+import com.powsybl.commons.report.ReportNode;
+import com.powsybl.iidm.network.StaticVarCompensator;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.ToString;
+import lombok.experimental.SuperBuilder;
+import org.gridsuite.modification.server.ModificationType;
+import org.gridsuite.modification.server.dto.annotation.ModificationErrorTypeName;
+import org.gridsuite.modification.server.entities.equipment.creation.StaticCompensatorCreationEntity;
+import org.gridsuite.modification.server.modifications.AbstractModification;
+import org.gridsuite.modification.server.modifications.StaticVarCompensatorCreation;
+
+/**
+ * @author Ghazwa Rehili
+ */
+
+@SuperBuilder
+@NoArgsConstructor
+@Getter
+@Setter
+@ToString(callSuper = true)
+@Schema(description = "Static var compensator creation")
+@JsonTypeName("STATIC_VAR_COMPENSATOR_CREATION")
+@ModificationErrorTypeName("CREATE_STATIC_VAR_COMPENSATOR_ERROR")
+public class StaticVarCompensatorCreationInfos extends InjectionCreationInfos {
+ @Schema(description = "Susceptance max")
+ private Double maxSusceptance;
+
+ @Schema(description = "Susceptance min")
+ private Double minSusceptance;
+
+ @Schema(description = "Q max at nominal voltage")
+ private Double maxQAtNominalV;
+
+ @Schema(description = "Q min at nominal voltage")
+ private Double minQAtNominalV;
+
+ @Schema(description = "regulation mode")
+ private StaticVarCompensator.RegulationMode regulationMode;
+
+ @Schema(description = "Voltage set point")
+ private Double voltageSetpoint;
+
+ @Schema(description = "Reactive power set point")
+ private Double reactivePowerSetpoint;
+
+ @Schema(description = "Voltage Regulation type")
+ private VoltageRegulationType voltageRegulationType;
+
+ @Schema(description = "Regulating terminal equipment id")
+ private String regulatingTerminalId;
+
+ @Schema(description = "Regulating terminal equipment type")
+ private String regulatingTerminalType;
+
+ @Schema(description = "Regulating terminal voltage level id")
+ private String regulatingTerminalVlId;
+
+ @Schema(description = "standby automaton on")
+ private boolean standbyAutomatonOn;
+
+ @Schema(description = "Standby")
+ private boolean standby;
+
+ @Schema(description = "Fixed part of susceptance")
+ private Double b0;
+
+ @Schema(description = "Fixed part of Q at nominal voltage")
+ private Double q0;
+
+ @Schema(description = "Low voltage set point ")
+ private Double lowVoltageSetpoint;
+
+ @Schema(description = "High voltage set point")
+ private Double highVoltageSetpoint;
+
+ @Schema(description = "Low voltage threshold")
+ private Double lowVoltageThreshold;
+
+ @Schema(description = "High voltage threshold")
+ private Double highVoltageThreshold;
+
+ @Override
+ public StaticCompensatorCreationEntity toEntity() {
+ return new StaticCompensatorCreationEntity(this);
+ }
+
+ @Override
+ public AbstractModification toModification() {
+ return new StaticVarCompensatorCreation(this);
+ }
+
+ @Override
+ public ReportNode createSubReportNode(ReportNode reportNode) {
+ return reportNode.newReportNode().withMessageTemplate(ModificationType.STATIC_VAR_COMPENSATOR_CREATION.name(),
+ "Static var compensator creation ${id}").withUntypedValue("id", this.getEquipmentId()).add();
+ }
+}
diff --git a/src/main/java/org/gridsuite/modification/server/entities/equipment/creation/StaticCompensatorCreationEntity.java b/src/main/java/org/gridsuite/modification/server/entities/equipment/creation/StaticCompensatorCreationEntity.java
new file mode 100644
index 000000000..2e0d55800
--- /dev/null
+++ b/src/main/java/org/gridsuite/modification/server/entities/equipment/creation/StaticCompensatorCreationEntity.java
@@ -0,0 +1,168 @@
+/**
+ * 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/.
+ */
+package org.gridsuite.modification.server.entities.equipment.creation;
+
+import com.powsybl.iidm.network.StaticVarCompensator;
+import jakarta.persistence.*;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.gridsuite.modification.server.dto.ModificationInfos;
+import org.gridsuite.modification.server.dto.StaticVarCompensatorCreationInfos;
+import org.gridsuite.modification.server.dto.VoltageRegulationType;
+import org.gridsuite.modification.server.entities.equipment.modification.FreePropertyEntity;
+import org.springframework.util.CollectionUtils;
+
+/**
+ * @author Ghazwa Rehili
+ */
+@NoArgsConstructor
+@Getter
+@Entity
+@Table(name = "staticVarCompensatorCreation")
+@PrimaryKeyJoinColumn(foreignKey = @ForeignKey(name = "staticVarCompensatorCreation_id_fk_constraint"))
+public class StaticCompensatorCreationEntity extends InjectionCreationEntity {
+ @Column
+ private Double maxSusceptance;
+
+ @Column
+ private Double minSusceptance;
+
+ @Column
+ private Double maxQAtNominalV;
+
+ @Column
+ private Double minQAtNominalV;
+
+ @Enumerated(EnumType.STRING)
+ @Column(name = "regulationMode")
+ private StaticVarCompensator.RegulationMode regulationMode;
+
+ @Column
+ private Double voltageSetpoint;
+
+ @Column
+ private Double reactivePowerSetpoint;
+
+ @Enumerated(EnumType.STRING)
+ @Column(name = "voltageRegulationType")
+ private VoltageRegulationType voltageRegulationType;
+
+ @Column(name = "regulatingTerminalId")
+ private String regulatingTerminalId;
+
+ @Column(name = "regulatingTerminalType")
+ private String regulatingTerminalType;
+
+ @Column(name = "regulatingTerminalVlId")
+ private String regulatingTerminalVlId;
+
+ @Column
+ private boolean standbyAutomatonOn;
+
+ @Column
+ private boolean standby;
+
+ @Column
+ private Double b0;
+
+ @Column
+ private Double q0;
+
+ @Column
+ private Double lowVoltageSetpoint;
+
+ @Column
+ private Double highVoltageSetpoint;
+
+ @Column
+ private Double lowVoltageThreshold;
+
+ @Column
+ private Double highVoltageThreshold;
+
+ public StaticCompensatorCreationEntity(StaticVarCompensatorCreationInfos creationInfos) {
+ super(creationInfos);
+ assignAttributes(creationInfos);
+ }
+
+ @Override
+ public void update(ModificationInfos modificationInfos) {
+ super.update(modificationInfos);
+ StaticVarCompensatorCreationInfos staticVarCompensatorCreationInfos = (StaticVarCompensatorCreationInfos) modificationInfos;
+ assignAttributes(staticVarCompensatorCreationInfos);
+ }
+
+ private void assignAttributes(StaticVarCompensatorCreationInfos creationInfos) {
+ this.maxSusceptance = creationInfos.getMaxSusceptance();
+ this.minSusceptance = creationInfos.getMinSusceptance();
+ this.maxQAtNominalV = creationInfos.getMaxQAtNominalV();
+ this.minQAtNominalV = creationInfos.getMinQAtNominalV();
+ this.regulationMode = creationInfos.getRegulationMode();
+ this.voltageSetpoint = creationInfos.getVoltageSetpoint();
+ this.reactivePowerSetpoint = creationInfos.getReactivePowerSetpoint();
+ this.voltageRegulationType = creationInfos.getVoltageRegulationType();
+ this.regulatingTerminalId = creationInfos.getRegulatingTerminalId();
+ this.regulatingTerminalType = creationInfos.getRegulatingTerminalType();
+ this.regulatingTerminalVlId = creationInfos.getRegulatingTerminalVlId();
+ this.standbyAutomatonOn = creationInfos.isStandbyAutomatonOn();
+ this.standby = creationInfos.isStandby();
+ this.b0 = creationInfos.getB0();
+ this.q0 = creationInfos.getQ0();
+ this.highVoltageSetpoint = creationInfos.getHighVoltageSetpoint();
+ this.lowVoltageSetpoint = creationInfos.getLowVoltageSetpoint();
+ this.lowVoltageThreshold = creationInfos.getLowVoltageThreshold();
+ this.highVoltageThreshold = creationInfos.getHighVoltageThreshold();
+ }
+
+ @Override
+ public StaticVarCompensatorCreationInfos toModificationInfos() {
+ return toStaticVarCompensatorCreationInfosBuilder().build();
+ }
+
+ private StaticVarCompensatorCreationInfos.StaticVarCompensatorCreationInfosBuilder, ?> toStaticVarCompensatorCreationInfosBuilder() {
+ return StaticVarCompensatorCreationInfos
+ .builder()
+ .uuid(getId())
+ .date(getDate())
+ .stashed(getStashed())
+ .activated(getActivated())
+ .equipmentId(getEquipmentId())
+ .equipmentName(getEquipmentName())
+ // Injection
+ .voltageLevelId(getVoltageLevelId())
+ .busOrBusbarSectionId(getBusOrBusbarSectionId())
+ .connectionName(getConnectionName())
+ .connectionDirection(getConnectionDirection())
+ .connectionPosition(getConnectionPosition())
+ .terminalConnected(isTerminalConnected())
+ .maxSusceptance(getMaxSusceptance())
+ .minSusceptance(getMinSusceptance())
+ .minQAtNominalV(getMinQAtNominalV())
+ .maxQAtNominalV(getMaxQAtNominalV())
+ .regulationMode(getRegulationMode())
+ .reactivePowerSetpoint(getReactivePowerSetpoint())
+ .voltageSetpoint(getVoltageSetpoint())
+ .voltageRegulationType(getVoltageRegulationType())
+ .regulatingTerminalId(getRegulatingTerminalId())
+ .regulatingTerminalType(getRegulatingTerminalType())
+ .regulatingTerminalVlId(getRegulatingTerminalVlId())
+ // Standby automaton
+ .standbyAutomatonOn(isStandbyAutomatonOn())
+ .standby(isStandby())
+ .b0(getB0())
+ .q0(getQ0())
+ .lowVoltageSetpoint(getLowVoltageSetpoint())
+ .highVoltageSetpoint(getHighVoltageSetpoint())
+ .lowVoltageThreshold(getLowVoltageThreshold())
+ .highVoltageThreshold(getHighVoltageThreshold())
+ // properties
+ .properties(CollectionUtils.isEmpty(getProperties()) ? null :
+ getProperties().stream()
+ .map(FreePropertyEntity::toInfos)
+ .toList());
+ }
+}
diff --git a/src/main/java/org/gridsuite/modification/server/modifications/BatteryCreation.java b/src/main/java/org/gridsuite/modification/server/modifications/BatteryCreation.java
index d1c129089..10345a8e2 100644
--- a/src/main/java/org/gridsuite/modification/server/modifications/BatteryCreation.java
+++ b/src/main/java/org/gridsuite/modification/server/modifications/BatteryCreation.java
@@ -9,8 +9,6 @@
import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.report.ReportNode;
import com.powsybl.commons.report.TypedValue;
-import com.powsybl.iidm.modification.topology.CreateFeederBay;
-import com.powsybl.iidm.modification.topology.CreateFeederBayBuilder;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.ActivePowerControlAdder;
import org.gridsuite.modification.server.NetworkModificationException;
@@ -20,7 +18,7 @@
import java.util.List;
import static org.gridsuite.modification.server.NetworkModificationException.Type.BATTERY_ALREADY_EXISTS;
-import static org.gridsuite.modification.server.modifications.ModificationUtils.nanIfNull;
+import static org.gridsuite.modification.server.modifications.ModificationUtils.*;
/**
* @author Ghazwa Rehili
@@ -30,7 +28,6 @@ public class BatteryCreation extends AbstractModification {
private final BatteryCreationInfos modificationInfos;
private static final String LIMITS = "Limits";
private static final String ACTIVE_LIMITS = "Active limits";
- private static final String CONNECTIVITY = "Connectivity";
public BatteryCreation(BatteryCreationInfos modificationInfos) {
this.modificationInfos = modificationInfos;
@@ -73,21 +70,7 @@ public void apply(Network network, ReportNode subReportNode) {
private void createBatteryInNodeBreaker(VoltageLevel voltageLevel, BatteryCreationInfos batteryCreationInfos, Network network, ReportNode subReportNode) {
BatteryAdder batteryAdder = createBatteryAdderInNodeBreaker(voltageLevel, batteryCreationInfos);
- var position = ModificationUtils.getInstance().getPosition(batteryCreationInfos.getConnectionPosition(),
- batteryCreationInfos.getBusOrBusbarSectionId(), network, voltageLevel);
-
- CreateFeederBay algo = new CreateFeederBayBuilder()
- .withBusOrBusbarSectionId(batteryCreationInfos.getBusOrBusbarSectionId())
- .withInjectionDirection(batteryCreationInfos.getConnectionDirection())
- .withInjectionFeederName(batteryCreationInfos.getConnectionName() != null
- ? batteryCreationInfos.getConnectionName()
- : batteryCreationInfos.getEquipmentId())
- .withInjectionPositionOrder(position)
- .withInjectionAdder(batteryAdder)
- .build();
-
- algo.apply(network, true, subReportNode);
-
+ createInjectionInNodeBreaker(voltageLevel, batteryCreationInfos, network, batteryAdder, subReportNode);
var battery = ModificationUtils.getInstance().getBattery(network, batteryCreationInfos.getEquipmentId());
addExtensionsToBattery(batteryCreationInfos, battery, subReportNode);
}
@@ -131,7 +114,7 @@ private void addExtensionsToBattery(BatteryCreationInfos batteryCreationInfos, B
if (batteryCreationInfos.getEquipmentName() != null) {
ModificationUtils.getInstance().reportElementaryCreation(subReportNode, batteryCreationInfos.getEquipmentName(), "Name");
}
- reportBatteryConnectivity(batteryCreationInfos, subReportNode);
+ reportInjectionCreationConnectivity(batteryCreationInfos, subReportNode);
ReportNode subReportNodeLimits = reportBatteryActiveLimits(batteryCreationInfos, subReportNode);
ModificationUtils.getInstance().createReactiveLimits(batteryCreationInfos, battery, subReportNodeLimits);
ReportNode subReportNodeSetpoints = reportBatterySetPoints(batteryCreationInfos, subReportNode);
@@ -149,38 +132,6 @@ private ReportNode reportBatterySetPoints(BatteryCreationInfos batteryCreationIn
return ModificationUtils.getInstance().reportModifications(subReportNode, setPointReports, "SetPointCreated", "Setpoints");
}
- private void reportBatteryConnectivity(BatteryCreationInfos batteryCreationInfos, ReportNode subReportNode) {
- if (batteryCreationInfos.getVoltageLevelId() == null || batteryCreationInfos.getBusOrBusbarSectionId() == null) {
- return;
- }
-
- if (batteryCreationInfos.getConnectionName() != null ||
- batteryCreationInfos.getConnectionDirection() != null ||
- batteryCreationInfos.getConnectionPosition() != null) {
- List connectivityReports = new ArrayList<>();
- if (batteryCreationInfos.getConnectionName() != null) {
- connectivityReports.add(ModificationUtils.getInstance()
- .buildCreationReport(batteryCreationInfos.getConnectionName(), "Connection name"));
- }
- if (batteryCreationInfos.getConnectionDirection() != null) {
- connectivityReports.add(ModificationUtils.getInstance()
- .buildCreationReport(batteryCreationInfos.getConnectionDirection(), "Connection direction"));
- }
- if (batteryCreationInfos.getConnectionPosition() != null) {
- connectivityReports.add(ModificationUtils.getInstance()
- .buildCreationReport(batteryCreationInfos.getConnectionPosition(), "Connection position"));
- }
- if (!batteryCreationInfos.isTerminalConnected()) {
- connectivityReports.add(ReportNode.newRootReportNode()
- .withMessageTemplate("equipmentDisconnected", " Equipment with id=${id} disconnected")
- .withUntypedValue("id", batteryCreationInfos.getEquipmentId())
- .withSeverity(TypedValue.INFO_SEVERITY)
- .build());
- }
- ModificationUtils.getInstance().reportModifications(subReportNode, connectivityReports, "ConnectivityCreated", CONNECTIVITY);
- }
- }
-
private ReportNode reportBatteryActiveLimits(BatteryCreationInfos batteryCreationInfos, ReportNode subReportNode) {
ReportNode subReportNodeLimits = subReportNode.newReportNode().withMessageTemplate(LIMITS, LIMITS).add();
List limitsReports = new ArrayList<>();
diff --git a/src/main/java/org/gridsuite/modification/server/modifications/GeneratorCreation.java b/src/main/java/org/gridsuite/modification/server/modifications/GeneratorCreation.java
index da8c55a93..8931f4a3d 100644
--- a/src/main/java/org/gridsuite/modification/server/modifications/GeneratorCreation.java
+++ b/src/main/java/org/gridsuite/modification/server/modifications/GeneratorCreation.java
@@ -9,15 +9,7 @@
import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.report.ReportNode;
import com.powsybl.commons.report.TypedValue;
-import com.powsybl.iidm.modification.topology.CreateFeederBay;
-import com.powsybl.iidm.modification.topology.CreateFeederBayBuilder;
-import com.powsybl.iidm.network.Bus;
-import com.powsybl.iidm.network.Generator;
-import com.powsybl.iidm.network.GeneratorAdder;
-import com.powsybl.iidm.network.Network;
-import com.powsybl.iidm.network.Terminal;
-import com.powsybl.iidm.network.TopologyKind;
-import com.powsybl.iidm.network.VoltageLevel;
+import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.ActivePowerControlAdder;
import com.powsybl.iidm.network.extensions.GeneratorShortCircuitAdder;
import com.powsybl.network.store.iidm.impl.extensions.CoordinatedReactiveControlAdderImpl;
@@ -29,7 +21,7 @@
import java.util.List;
import static org.gridsuite.modification.server.NetworkModificationException.Type.GENERATOR_ALREADY_EXISTS;
-import static org.gridsuite.modification.server.modifications.ModificationUtils.nanIfNull;
+import static org.gridsuite.modification.server.modifications.ModificationUtils.*;
/**
* @author Ayoub Labidi
@@ -39,7 +31,6 @@ public class GeneratorCreation extends AbstractModification {
private final GeneratorCreationInfos modificationInfos;
private static final String LIMITS = "Limits";
private static final String ACTIVE_LIMITS = "Active limits";
- private static final String CONNECTIVITY = "Connectivity";
public GeneratorCreation(GeneratorCreationInfos modificationInfos) {
this.modificationInfos = modificationInfos;
@@ -88,20 +79,7 @@ public void apply(Network network, ReportNode subReportNode) {
private void createGeneratorInNodeBreaker(VoltageLevel voltageLevel, GeneratorCreationInfos generatorCreationInfos, Network network, ReportNode subReportNode) {
GeneratorAdder generatorAdder = createGeneratorAdderInNodeBreaker(voltageLevel, generatorCreationInfos);
- var position = ModificationUtils.getInstance().getPosition(generatorCreationInfos.getConnectionPosition(),
- generatorCreationInfos.getBusOrBusbarSectionId(), network, voltageLevel);
-
- CreateFeederBay algo = new CreateFeederBayBuilder()
- .withBusOrBusbarSectionId(generatorCreationInfos.getBusOrBusbarSectionId())
- .withInjectionDirection(generatorCreationInfos.getConnectionDirection())
- .withInjectionFeederName(generatorCreationInfos.getConnectionName() != null
- ? generatorCreationInfos.getConnectionName()
- : generatorCreationInfos.getEquipmentId())
- .withInjectionPositionOrder(position)
- .withInjectionAdder(generatorAdder)
- .build();
-
- algo.apply(network, true, subReportNode);
+ createInjectionInNodeBreaker(voltageLevel, generatorCreationInfos, network, generatorAdder, subReportNode);
// CreateFeederBayBuilder already create the generator using
// (withInjectionAdder(generatorAdder)) so then we can add the additional informations and extensions
@@ -143,7 +121,7 @@ private void addExtensionsToGenerator(GeneratorCreationInfos generatorCreationIn
if (generatorCreationInfos.getEnergySource() != null) {
ModificationUtils.getInstance().reportElementaryCreation(subReportNode, generatorCreationInfos.getEnergySource(), "Energy source");
}
- reportGeneratorConnectivity(generatorCreationInfos, subReportNode);
+ reportInjectionCreationConnectivity(generatorCreationInfos, subReportNode);
ReportNode subReporterLimits = reportGeneratorActiveLimits(generatorCreationInfos, subReportNode);
ModificationUtils.getInstance().createReactiveLimits(generatorCreationInfos, generator, subReporterLimits);
ReportNode subReporterSetpoints = reportGeneratorSetPoints(generatorCreationInfos, subReportNode);
@@ -241,38 +219,6 @@ private void updateGeneratorRegulatingTerminal(GeneratorCreationInfos generatorC
}
}
- private void reportGeneratorConnectivity(GeneratorCreationInfos generatorCreationInfos, ReportNode subReporter) {
- if (generatorCreationInfos.getVoltageLevelId() == null || generatorCreationInfos.getBusOrBusbarSectionId() == null) {
- return;
- }
-
- if (generatorCreationInfos.getConnectionName() != null ||
- generatorCreationInfos.getConnectionDirection() != null ||
- generatorCreationInfos.getConnectionPosition() != null) {
- List connectivityReports = new ArrayList<>();
- if (generatorCreationInfos.getConnectionName() != null) {
- connectivityReports.add(ModificationUtils.getInstance()
- .buildCreationReport(generatorCreationInfos.getConnectionName(), "Connection name"));
- }
- if (generatorCreationInfos.getConnectionDirection() != null) {
- connectivityReports.add(ModificationUtils.getInstance()
- .buildCreationReport(generatorCreationInfos.getConnectionDirection(), "Connection direction"));
- }
- if (generatorCreationInfos.getConnectionPosition() != null) {
- connectivityReports.add(ModificationUtils.getInstance()
- .buildCreationReport(generatorCreationInfos.getConnectionPosition(), "Connection position"));
- }
- if (!generatorCreationInfos.isTerminalConnected()) {
- connectivityReports.add(ReportNode.newRootReportNode()
- .withMessageTemplate("equipmentDisconnected", " Equipment with id=${id} disconnected")
- .withUntypedValue("id", generatorCreationInfos.getEquipmentId())
- .withSeverity(TypedValue.INFO_SEVERITY)
- .build());
- }
- ModificationUtils.getInstance().reportModifications(subReporter, connectivityReports, "ConnectivityCreated", CONNECTIVITY);
- }
- }
-
private ReportNode reportGeneratorActiveLimits(GeneratorCreationInfos generatorCreationInfos, ReportNode subReportNode) {
ReportNode subReportNodeLimits = subReportNode.newReportNode().withMessageTemplate(LIMITS, LIMITS).add();
List limitsReports = new ArrayList<>();
diff --git a/src/main/java/org/gridsuite/modification/server/modifications/LoadCreation.java b/src/main/java/org/gridsuite/modification/server/modifications/LoadCreation.java
index 5afdcde99..db0e67219 100644
--- a/src/main/java/org/gridsuite/modification/server/modifications/LoadCreation.java
+++ b/src/main/java/org/gridsuite/modification/server/modifications/LoadCreation.java
@@ -8,13 +8,12 @@
import com.powsybl.commons.report.ReportNode;
import com.powsybl.commons.report.TypedValue;
-import com.powsybl.iidm.modification.topology.CreateFeederBay;
-import com.powsybl.iidm.modification.topology.CreateFeederBayBuilder;
import com.powsybl.iidm.network.*;
import org.gridsuite.modification.server.NetworkModificationException;
import org.gridsuite.modification.server.dto.LoadCreationInfos;
-import static org.gridsuite.modification.server.NetworkModificationException.Type.*;
+import static org.gridsuite.modification.server.NetworkModificationException.Type.LOAD_ALREADY_EXISTS;
+import static org.gridsuite.modification.server.modifications.ModificationUtils.createInjectionInNodeBreaker;
/**
* @author Slimane Amar
@@ -42,16 +41,7 @@ public void apply(Network network, ReportNode subReporter) {
VoltageLevel voltageLevel = ModificationUtils.getInstance().getVoltageLevel(network, modificationInfos.getVoltageLevelId());
if (voltageLevel.getTopologyKind() == TopologyKind.NODE_BREAKER) {
LoadAdder loadAdder = createLoadAdderInNodeBreaker(voltageLevel, modificationInfos);
- var position = ModificationUtils.getInstance().getPosition(modificationInfos.getConnectionPosition(),
- modificationInfos.getBusOrBusbarSectionId(), network, voltageLevel);
- CreateFeederBay algo = new CreateFeederBayBuilder()
- .withBbsId(modificationInfos.getBusOrBusbarSectionId())
- .withInjectionDirection(modificationInfos.getConnectionDirection())
- .withInjectionFeederName(modificationInfos.getConnectionName() != null ? modificationInfos.getConnectionName() : modificationInfos.getEquipmentId())
- .withInjectionPositionOrder(position)
- .withInjectionAdder(loadAdder)
- .build();
- algo.apply(network, true, subReporter);
+ createInjectionInNodeBreaker(voltageLevel, modificationInfos, network, loadAdder, subReporter);
} else {
createLoadInBusBreaker(voltageLevel, modificationInfos);
subReporter.newReportNode()
diff --git a/src/main/java/org/gridsuite/modification/server/modifications/ModificationUtils.java b/src/main/java/org/gridsuite/modification/server/modifications/ModificationUtils.java
index b68ecc296..a2f5a4833 100644
--- a/src/main/java/org/gridsuite/modification/server/modifications/ModificationUtils.java
+++ b/src/main/java/org/gridsuite/modification/server/modifications/ModificationUtils.java
@@ -10,9 +10,7 @@
import com.powsybl.commons.report.ReportNode;
import com.powsybl.commons.report.ReportNodeAdder;
import com.powsybl.commons.report.TypedValue;
-import com.powsybl.iidm.modification.topology.CreateCouplingDeviceBuilder;
-import com.powsybl.iidm.modification.topology.CreateVoltageLevelTopologyBuilder;
-import com.powsybl.iidm.modification.topology.TopologyModificationUtils;
+import com.powsybl.iidm.modification.topology.*;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.*;
import com.powsybl.network.store.iidm.impl.MinMaxReactiveLimitsImpl;
@@ -44,6 +42,9 @@ public final class ModificationUtils {
public static final String DISCONNECTOR = "disconnector_";
public static final String BREAKER = "breaker_";
public static final String BUS_BAR_SECTION_ID = "busbarSectionId";
+
+ public static final String DOES_NOT_EXIST_IN_NETWORK = " does not exist in network";
+ public static final String EQUIPMENT_DISCONNECTED = "equipmentDisconnected";
public static final String NO_VALUE = "No value";
public static final String LIMITS = "Limits";
public static final String REACTIVE_LIMITS = "Reactive limits";
@@ -120,6 +121,14 @@ HvdcLine getHvdcLine(Network network, String hvdcLineId) {
return hvdcLine;
}
+ StaticVarCompensator getStaticVarCompensator(Network network, String staticVarCompensatorId) {
+ StaticVarCompensator staticVarCompensator = network.getStaticVarCompensator(staticVarCompensatorId);
+ if (staticVarCompensator == null) {
+ throw new NetworkModificationException(STATIC_VAR_COMPENSATOR_NOT_FOUND, "Static var compensator " + staticVarCompensatorId + DOES_NOT_EXIST_IN_NETWORK);
+ }
+ return staticVarCompensator;
+ }
+
public void controlConnectivity(Network network, String voltageLevelId, String busOrBusbarSectionId, Integer connectionPosition) {
VoltageLevel voltageLevel = getVoltageLevel(network, voltageLevelId);
if (voltageLevel.getTopologyKind() == TopologyKind.NODE_BREAKER) {
@@ -280,7 +289,7 @@ public void controlVoltageLevelCreation(VoltageLevelCreationInfos voltageLevelCr
throw new NetworkModificationException(CREATE_VOLTAGE_LEVEL_ERROR, "IpMax is required");
}
if (Objects.nonNull(voltageLevelCreationInfos.getIpMin()) && Objects.nonNull(voltageLevelCreationInfos.getIpMax())
- && voltageLevelCreationInfos.getIpMin() > voltageLevelCreationInfos.getIpMax()) {
+ && voltageLevelCreationInfos.getIpMin() > voltageLevelCreationInfos.getIpMax()) {
throw new NetworkModificationException(CREATE_VOLTAGE_LEVEL_ERROR, "IpMin cannot be greater than IpMax");
}
}
@@ -593,7 +602,7 @@ public void disconnectCreatedInjection(InjectionCreationInfos modificationInfos,
if (!modificationInfos.isTerminalConnected()) {
injection.getTerminal().disconnect();
subReportNode.newReportNode()
- .withMessageTemplate("equipmentDisconnected", "Equipment with id=${id} disconnected")
+ .withMessageTemplate(EQUIPMENT_DISCONNECTED, "Equipment with id=${id} disconnected")
.withUntypedValue("id", modificationInfos.getEquipmentId())
.withSeverity(TypedValue.INFO_SEVERITY)
.add();
@@ -1218,10 +1227,10 @@ public void checkMaxQGreaterThanMinQ(
}
public void checkMaxReactivePowerGreaterThanMinReactivePower(MinMaxReactiveLimits minMaxReactiveLimits, AttributeModification minimumReactivePowerInfo, AttributeModification maximumReactivePowerInfo, NetworkModificationException.Type exceptionType, String errorMessage) {
- Double previousMinimumReactivePower = minMaxReactiveLimits.getMinQ();
- Double previousMaximumReactivePower = minMaxReactiveLimits.getMaxQ();
- Double minReactivePower = minimumReactivePowerInfo != null ? minimumReactivePowerInfo.getValue() : previousMinimumReactivePower;
- Double maxReactivePower = maximumReactivePowerInfo != null ? maximumReactivePowerInfo.getValue() : previousMaximumReactivePower;
+ double previousMinimumReactivePower = minMaxReactiveLimits.getMinQ();
+ double previousMaximumReactivePower = minMaxReactiveLimits.getMaxQ();
+ double minReactivePower = minimumReactivePowerInfo != null ? minimumReactivePowerInfo.getValue() : previousMinimumReactivePower;
+ double maxReactivePower = maximumReactivePowerInfo != null ? maximumReactivePowerInfo.getValue() : previousMaximumReactivePower;
if (minReactivePower > maxReactivePower) {
throw new NetworkModificationException(exceptionType, errorMessage + "maximum reactive power " + maxReactivePower + " is expected to be greater than or equal to minimum reactive power " + minReactivePower);
}
@@ -1292,6 +1301,43 @@ public void checkReactiveLimitsCreation(ReactiveLimitsHolderInfos modificationIn
}
}
+ public void checkReactivePowerLimitsAndSetPointsCreation(StaticVarCompensatorCreationInfos creationInfos) {
+ String equipmentName = "StaticVarCompensator";
+ // check min max reactive limits
+ if (Objects.isNull(creationInfos.getMinSusceptance()) && Objects.isNull(creationInfos.getMinQAtNominalV())) {
+ throw makeEquipmentException(creationInfos.getErrorType(), creationInfos.getEquipmentId(), equipmentName, "minimum susceptance is not set");
+ }
+ if (Objects.isNull(creationInfos.getMaxSusceptance()) && Objects.isNull(creationInfos.getMaxQAtNominalV())) {
+ throw makeEquipmentException(creationInfos.getErrorType(), creationInfos.getEquipmentId(), equipmentName, "maximum susceptance is not set");
+ }
+ if (Objects.nonNull(creationInfos.getMaxSusceptance()) && Objects.nonNull(creationInfos.getMinSusceptance()) && creationInfos.getMaxSusceptance() < creationInfos.getMinSusceptance() ||
+ Objects.nonNull(creationInfos.getMaxQAtNominalV()) && Objects.nonNull(creationInfos.getMinQAtNominalV()) && creationInfos.getMaxQAtNominalV() < creationInfos.getMinQAtNominalV()) {
+ throw makeEquipmentException(creationInfos.getErrorType(), creationInfos.getEquipmentId(), equipmentName, "maximum susceptance is expected to be greater than or equal to minimum susceptance");
+ }
+
+ // check set points
+ if (Objects.requireNonNull(creationInfos.getRegulationMode()) == StaticVarCompensator.RegulationMode.VOLTAGE && creationInfos.getVoltageSetpoint() == null) {
+ throw makeEquipmentException(creationInfos.getErrorType(), creationInfos.getEquipmentId(), equipmentName, "Voltage setpoint is not set");
+ }
+ if (creationInfos.getRegulationMode() == StaticVarCompensator.RegulationMode.REACTIVE_POWER && creationInfos.getReactivePowerSetpoint() == null) {
+ throw makeEquipmentException(creationInfos.getErrorType(), creationInfos.getEquipmentId(), equipmentName, "Reactive power setpoint is not set");
+ }
+ }
+
+ public void checkStandbyAutomatonCreation(StaticVarCompensatorCreationInfos creationInfos) {
+ String equipmentName = "StaticVarCompensator";
+ if (Boolean.TRUE.equals(creationInfos.isStandby()) && creationInfos.getRegulationMode() != StaticVarCompensator.RegulationMode.VOLTAGE) {
+ throw makeEquipmentException(creationInfos.getErrorType(), creationInfos.getEquipmentId(), equipmentName, "Standby is only supported in Voltage Regulation mode");
+ }
+ if (Objects.nonNull(creationInfos.getB0()) && Objects.nonNull(creationInfos.getMinSusceptance()) && Objects.nonNull(creationInfos.getMaxSusceptance()) &&
+ (creationInfos.getB0() < creationInfos.getMinSusceptance() || creationInfos.getB0() > creationInfos.getMaxSusceptance())
+ || Objects.nonNull(creationInfos.getQ0()) && Objects.nonNull(creationInfos.getMinQAtNominalV()) && Objects.nonNull(creationInfos.getMaxQAtNominalV()) &&
+ (creationInfos.getQ0() < creationInfos.getMinQAtNominalV() || creationInfos.getQ0() > creationInfos.getMaxQAtNominalV())) {
+ throw makeEquipmentException(creationInfos.getErrorType(), creationInfos.getEquipmentId(), equipmentName,
+ "b0 must be within the range of minimun susceptance and maximum susceptance");
+ }
+ }
+
public static void addToReports(List reports, Double newValue, String fieldName) {
if (newValue != null) {
reports.add(ModificationUtils.getInstance().buildCreationReport(newValue, fieldName));
@@ -1438,5 +1484,53 @@ public static void insertReportNode(ReportNode parent, ReportNode child) {
child.getChildren().forEach(grandChild -> insertReportNode(insertedChild, grandChild));
}
}
+
+ public static void createInjectionInNodeBreaker(VoltageLevel voltageLevel, InjectionCreationInfos injectionCreationInfos,
+ Network network, InjectionAdder, ?> injectionAdder, ReportNode subReportNode) {
+ int position = ModificationUtils.getInstance().getPosition(injectionCreationInfos.getConnectionPosition(),
+ injectionCreationInfos.getBusOrBusbarSectionId(), network, voltageLevel);
+ CreateFeederBay algo = new CreateFeederBayBuilder()
+ .withBusOrBusbarSectionId(injectionCreationInfos.getBusOrBusbarSectionId())
+ .withInjectionDirection(injectionCreationInfos.getConnectionDirection())
+ .withInjectionFeederName(injectionCreationInfos.getConnectionName() != null
+ ? injectionCreationInfos.getConnectionName()
+ : injectionCreationInfos.getEquipmentId())
+ .withInjectionPositionOrder(position)
+ .withInjectionAdder(injectionAdder)
+ .build();
+ algo.apply(network, true, subReportNode);
+ }
+
+ public static void reportInjectionCreationConnectivity(InjectionCreationInfos injectionCreationInfos, ReportNode subReporter) {
+ if (Objects.isNull(injectionCreationInfos.getVoltageLevelId()) || Objects.isNull(injectionCreationInfos.getBusOrBusbarSectionId())) {
+ return;
+ }
+
+ if (injectionCreationInfos.getConnectionName() != null ||
+ injectionCreationInfos.getConnectionDirection() != null ||
+ injectionCreationInfos.getConnectionPosition() != null) {
+ List connectivityReports = new ArrayList<>();
+ if (injectionCreationInfos.getConnectionName() != null) {
+ connectivityReports.add(ModificationUtils.getInstance()
+ .buildCreationReport(injectionCreationInfos.getConnectionName(), CONNECTION_NAME_FIELD_NAME));
+ }
+ if (injectionCreationInfos.getConnectionDirection() != null) {
+ connectivityReports.add(ModificationUtils.getInstance()
+ .buildCreationReport(injectionCreationInfos.getConnectionDirection(), CONNECTION_DIRECTION_FIELD_NAME));
+ }
+ if (injectionCreationInfos.getConnectionPosition() != null) {
+ connectivityReports.add(ModificationUtils.getInstance()
+ .buildCreationReport(injectionCreationInfos.getConnectionPosition(), CONNECTION_POSITION_FIELD_NAME));
+ }
+ if (!injectionCreationInfos.isTerminalConnected()) {
+ connectivityReports.add(ReportNode.newRootReportNode()
+ .withMessageTemplate(EQUIPMENT_DISCONNECTED, " Equipment with id=${id} disconnected")
+ .withUntypedValue("id", injectionCreationInfos.getEquipmentId())
+ .withSeverity(TypedValue.INFO_SEVERITY)
+ .build());
+ }
+ ModificationUtils.getInstance().reportModifications(subReporter, connectivityReports, "ConnectivityCreated", CONNECTIVITY);
+ }
+ }
}
diff --git a/src/main/java/org/gridsuite/modification/server/modifications/ShuntCompensatorCreation.java b/src/main/java/org/gridsuite/modification/server/modifications/ShuntCompensatorCreation.java
index 2d957edb7..4c219d4ea 100644
--- a/src/main/java/org/gridsuite/modification/server/modifications/ShuntCompensatorCreation.java
+++ b/src/main/java/org/gridsuite/modification/server/modifications/ShuntCompensatorCreation.java
@@ -8,14 +8,14 @@
import com.powsybl.commons.report.ReportNode;
import com.powsybl.commons.report.TypedValue;
-import com.powsybl.iidm.modification.topology.CreateFeederBay;
-import com.powsybl.iidm.modification.topology.CreateFeederBayBuilder;
import com.powsybl.iidm.network.*;
import org.gridsuite.modification.server.NetworkModificationException;
import org.gridsuite.modification.server.dto.ShuntCompensatorCreationInfos;
import org.gridsuite.modification.server.dto.ShuntCompensatorType;
-import static org.gridsuite.modification.server.NetworkModificationException.Type.*;
+import static org.gridsuite.modification.server.NetworkModificationException.Type.CREATE_SHUNT_COMPENSATOR_ERROR;
+import static org.gridsuite.modification.server.NetworkModificationException.Type.SHUNT_COMPENSATOR_ALREADY_EXISTS;
+import static org.gridsuite.modification.server.modifications.ModificationUtils.createInjectionInNodeBreaker;
/**
* @author Slimane Amar
@@ -52,7 +52,7 @@ public void apply(Network network, ReportNode subReportNode) {
// create the shunt compensator in the network
VoltageLevel voltageLevel = ModificationUtils.getInstance().getVoltageLevel(network, modificationInfos.getVoltageLevelId());
if (modificationInfos.getMaxSusceptance() == null) {
- Double maxSusceptance = (modificationInfos.getMaxQAtNominalV()) / Math.pow(voltageLevel.getNominalV(), 2);
+ double maxSusceptance = (modificationInfos.getMaxQAtNominalV()) / Math.pow(voltageLevel.getNominalV(), 2);
modificationInfos.setMaxSusceptance(
modificationInfos.getShuntCompensatorType() == ShuntCompensatorType.CAPACITOR
? maxSusceptance
@@ -60,16 +60,7 @@ public void apply(Network network, ReportNode subReportNode) {
}
if (voltageLevel.getTopologyKind() == TopologyKind.NODE_BREAKER) {
ShuntCompensatorAdder shuntCompensatorAdder = createShuntAdderInNodeBreaker(voltageLevel, modificationInfos);
- var position = ModificationUtils.getInstance().getPosition(modificationInfos.getConnectionPosition(),
- modificationInfos.getBusOrBusbarSectionId(), network, voltageLevel);
- CreateFeederBay algo = new CreateFeederBayBuilder()
- .withBbsId(modificationInfos.getBusOrBusbarSectionId())
- .withInjectionDirection(modificationInfos.getConnectionDirection())
- .withInjectionFeederName(modificationInfos.getConnectionName())
- .withInjectionPositionOrder(position)
- .withInjectionAdder(shuntCompensatorAdder)
- .build();
- algo.apply(network, true, subReportNode);
+ createInjectionInNodeBreaker(voltageLevel, modificationInfos, network, shuntCompensatorAdder, subReportNode);
} else {
createShuntInBusBreaker(voltageLevel, modificationInfos);
subReportNode.newReportNode()
diff --git a/src/main/java/org/gridsuite/modification/server/modifications/StaticVarCompensatorCreation.java b/src/main/java/org/gridsuite/modification/server/modifications/StaticVarCompensatorCreation.java
new file mode 100644
index 000000000..bc99bbaa3
--- /dev/null
+++ b/src/main/java/org/gridsuite/modification/server/modifications/StaticVarCompensatorCreation.java
@@ -0,0 +1,234 @@
+/**
+ * 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/.
+ */
+package org.gridsuite.modification.server.modifications;
+
+import com.powsybl.commons.PowsyblException;
+import com.powsybl.commons.report.ReportNode;
+import com.powsybl.commons.report.TypedValue;
+import com.powsybl.iidm.network.*;
+import com.powsybl.iidm.network.extensions.StandbyAutomatonAdder;
+import org.gridsuite.modification.server.NetworkModificationException;
+import org.gridsuite.modification.server.dto.StaticVarCompensatorCreationInfos;
+import org.gridsuite.modification.server.dto.VoltageRegulationType;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import static org.gridsuite.modification.server.NetworkModificationException.Type.STATIC_VAR_COMPENSATOR_ALREADY_EXISTS;
+import static org.gridsuite.modification.server.modifications.ModificationUtils.*;
+
+/**
+ * @author Ghazwa Rehili
+ */
+public class StaticVarCompensatorCreation extends AbstractModification {
+
+ private final StaticVarCompensatorCreationInfos modificationInfos;
+
+ public StaticVarCompensatorCreation(StaticVarCompensatorCreationInfos modificationInfos) {
+ this.modificationInfos = modificationInfos;
+ }
+
+ @Override
+ public void check(Network network) throws NetworkModificationException {
+ if (network.getStaticVarCompensator(modificationInfos.getEquipmentId()) != null) {
+ throw new NetworkModificationException(STATIC_VAR_COMPENSATOR_ALREADY_EXISTS, modificationInfos.getEquipmentId());
+ }
+
+ // check connectivity
+ ModificationUtils.getInstance()
+ .controlConnectivity(network, modificationInfos.getVoltageLevelId(),
+ modificationInfos.getBusOrBusbarSectionId(), modificationInfos.getConnectionPosition());
+
+ // check reactive power limits and set points
+ ModificationUtils.getInstance().checkReactivePowerLimitsAndSetPointsCreation(modificationInfos);
+
+ // check regulated terminal
+ VoltageLevel voltageLevel = ModificationUtils.getInstance().getVoltageLevel(network, modificationInfos.getVoltageLevelId());
+ ModificationUtils.getInstance().getTerminalFromIdentifiable(voltageLevel.getNetwork(), modificationInfos.getRegulatingTerminalId(),
+ modificationInfos.getRegulatingTerminalType(), modificationInfos.getRegulatingTerminalVlId());
+
+ // check standby automaton
+ ModificationUtils.getInstance().checkStandbyAutomatonCreation(modificationInfos);
+ }
+
+ @Override
+ public void apply(Network network, ReportNode subReportNode) {
+ // create the static var compensator in the network
+ VoltageLevel voltageLevel = ModificationUtils.getInstance().getVoltageLevel(network, modificationInfos.getVoltageLevelId());
+ if (Objects.isNull(modificationInfos.getMaxSusceptance()) && Objects.nonNull(modificationInfos.getMaxQAtNominalV())) {
+ modificationInfos.setMaxSusceptance((modificationInfos.getMaxQAtNominalV()) / Math.pow(voltageLevel.getNominalV(), 2));
+ }
+ if (Objects.isNull(modificationInfos.getMinSusceptance()) && Objects.nonNull(modificationInfos.getMinQAtNominalV())) {
+ modificationInfos.setMinSusceptance((modificationInfos.getMinQAtNominalV()) / Math.pow(voltageLevel.getNominalV(), 2));
+ }
+ if (Boolean.TRUE.equals(modificationInfos.isStandbyAutomatonOn()) && Objects.isNull(modificationInfos.getB0())
+ && Objects.nonNull(modificationInfos.getQ0())) {
+ modificationInfos.setB0((modificationInfos.getQ0()) / Math.pow(voltageLevel.getNominalV(), 2));
+ }
+ if (voltageLevel.getTopologyKind() == TopologyKind.NODE_BREAKER) {
+ createStaticVarCompensatorInNodeBreaker(voltageLevel, modificationInfos, network, subReportNode);
+ } else {
+ createStaticVarCompensatorInBusBreaker(voltageLevel, modificationInfos, subReportNode);
+ }
+ ModificationUtils.getInstance().disconnectCreatedInjection(modificationInfos, network.getStaticVarCompensator(modificationInfos.getEquipmentId()), subReportNode);
+ // properties
+ StaticVarCompensator staticVarCompensator = network.getStaticVarCompensator(modificationInfos.getEquipmentId());
+ PropertiesUtils.applyProperties(staticVarCompensator, subReportNode, modificationInfos.getProperties(), "StaticVarCompensatorProperties");
+ subReportNode.newReportNode()
+ .withMessageTemplate("staticVarCompensatorCreated", "New static var compensator with id=${id} created")
+ .withUntypedValue("id", modificationInfos.getEquipmentId())
+ .withSeverity(TypedValue.INFO_SEVERITY)
+ .add();
+ }
+
+ private void createStaticVarCompensatorInNodeBreaker(VoltageLevel voltageLevel, StaticVarCompensatorCreationInfos staticVarCompensatorCreationInfos,
+ Network network, ReportNode subReportNode) {
+ StaticVarCompensatorAdder staticVarCompensatorAdder = createStaticVarCompensatorAdderInNodeBreaker(voltageLevel, staticVarCompensatorCreationInfos);
+ createInjectionInNodeBreaker(voltageLevel, staticVarCompensatorCreationInfos, network, staticVarCompensatorAdder, subReportNode);
+ var staticVarCompensator = ModificationUtils.getInstance().getStaticVarCompensator(network, staticVarCompensatorCreationInfos.getEquipmentId());
+ addExtensionsToStaticVarCompensator(staticVarCompensatorCreationInfos, staticVarCompensator, voltageLevel, subReportNode);
+ }
+
+ private StaticVarCompensatorAdder createStaticVarCompensatorAdderInNodeBreaker(VoltageLevel voltageLevel, StaticVarCompensatorCreationInfos staticVarCompensatorCreationInfos) {
+ Terminal terminal = ModificationUtils.getInstance().getTerminalFromIdentifiable(voltageLevel.getNetwork(),
+ staticVarCompensatorCreationInfos.getRegulatingTerminalId(),
+ staticVarCompensatorCreationInfos.getRegulatingTerminalType(),
+ staticVarCompensatorCreationInfos.getRegulatingTerminalVlId());
+
+ StaticVarCompensatorAdder staticVarCompensatorAdder = voltageLevel.newStaticVarCompensator()
+ .setId(staticVarCompensatorCreationInfos.getEquipmentId())
+ .setName(staticVarCompensatorCreationInfos.getEquipmentName())
+ .setBmax(nanIfNull(staticVarCompensatorCreationInfos.getMaxSusceptance()))
+ .setBmin(nanIfNull(staticVarCompensatorCreationInfos.getMinSusceptance()))
+ .setVoltageSetpoint(nanIfNull(staticVarCompensatorCreationInfos.getVoltageSetpoint()))
+ .setReactivePowerSetpoint(nanIfNull(staticVarCompensatorCreationInfos.getReactivePowerSetpoint()))
+ .setRegulationMode(staticVarCompensatorCreationInfos.getRegulationMode());
+
+ if (terminal != null) {
+ staticVarCompensatorAdder.setRegulatingTerminal(terminal);
+ }
+
+ return staticVarCompensatorAdder;
+ }
+
+ private void addExtensionsToStaticVarCompensator(StaticVarCompensatorCreationInfos staticVarCompensatorCreationInfos,
+ StaticVarCompensator staticVarCompensator,
+ VoltageLevel voltageLevel,
+ ReportNode subReportNode) {
+ if (staticVarCompensatorCreationInfos.getEquipmentName() != null) {
+ ModificationUtils.getInstance().reportElementaryCreation(subReportNode, staticVarCompensatorCreationInfos.getEquipmentName(), "Name");
+ }
+
+ reportInjectionCreationConnectivity(staticVarCompensatorCreationInfos, subReportNode);
+ createStaticVarCompensatorVoltageRegulation(staticVarCompensatorCreationInfos, staticVarCompensator, voltageLevel, subReportNode);
+ reportStaticVarCompensatorStandbyAutomaton(staticVarCompensatorCreationInfos, staticVarCompensator, subReportNode);
+ }
+
+ private void reportStaticVarCompensatorStandbyAutomaton(StaticVarCompensatorCreationInfos staticVarCompensatorCreationInfos,
+ StaticVarCompensator staticVarCompensator, ReportNode subReportNode) {
+ if (Boolean.TRUE.equals(staticVarCompensatorCreationInfos.isStandbyAutomatonOn())) {
+ List standbyAutomatonReports = new ArrayList<>();
+ try {
+ staticVarCompensator.newExtension(StandbyAutomatonAdder.class)
+ .withStandbyStatus(staticVarCompensatorCreationInfos.isStandby())
+ .withB0(staticVarCompensatorCreationInfos.getB0())
+ .withLowVoltageSetpoint(staticVarCompensatorCreationInfos.getLowVoltageSetpoint())
+ .withHighVoltageSetpoint(staticVarCompensatorCreationInfos.getHighVoltageSetpoint())
+ .withLowVoltageThreshold(staticVarCompensatorCreationInfos.getLowVoltageThreshold())
+ .withHighVoltageThreshold(staticVarCompensatorCreationInfos.getHighVoltageThreshold())
+ .add();
+ standbyAutomatonReports.add(ModificationUtils.getInstance().buildCreationReport(
+ staticVarCompensatorCreationInfos.isStandby(),
+ "Standby"));
+ standbyAutomatonReports.add(ModificationUtils.getInstance().buildCreationReport(
+ staticVarCompensatorCreationInfos.getB0(),
+ "Fixed part of susceptance"));
+ standbyAutomatonReports.add(ModificationUtils.getInstance().buildCreationReport(
+ staticVarCompensatorCreationInfos.getLowVoltageSetpoint(),
+ "Low voltage set point"));
+ standbyAutomatonReports.add(ModificationUtils.getInstance().buildCreationReport(
+ staticVarCompensatorCreationInfos.getHighVoltageSetpoint(),
+ "High voltage set point"));
+ standbyAutomatonReports.add(ModificationUtils.getInstance().buildCreationReport(
+ staticVarCompensatorCreationInfos.getHighVoltageThreshold(),
+ "High voltage threshold"));
+ standbyAutomatonReports.add(ModificationUtils.getInstance().buildCreationReport(
+ staticVarCompensatorCreationInfos.getLowVoltageThreshold(),
+ "Low voltage threshold"));
+ } catch (PowsyblException e) {
+ standbyAutomatonReports.add(ReportNode.newRootReportNode()
+ .withMessageTemplate("StandbyAutomatonExtensionAddError",
+ "Cannot add standby automaton extension on static var compensator with id=${id} : ${message}")
+ .withUntypedValue("id", staticVarCompensatorCreationInfos.getEquipmentId())
+ .withUntypedValue("message", e.getMessage())
+ .withSeverity(TypedValue.ERROR_SEVERITY)
+ .build());
+
+ }
+ ModificationUtils.getInstance().reportModifications(subReportNode, standbyAutomatonReports,
+ "StandbyAutomatonCreated", "Standby automaton");
+ }
+ }
+
+ private void createStaticVarCompensatorInBusBreaker(VoltageLevel voltageLevel, StaticVarCompensatorCreationInfos staticVarCompensatorCreationInfos,
+ ReportNode subReportNode) {
+
+ Bus bus = ModificationUtils.getInstance().getBusBreakerBus(voltageLevel, staticVarCompensatorCreationInfos.getBusOrBusbarSectionId());
+ /* creating the static var compensator */
+ StaticVarCompensator staticVarCompensator = voltageLevel.newStaticVarCompensator()
+ .setId(staticVarCompensatorCreationInfos.getEquipmentId())
+ .setName(staticVarCompensatorCreationInfos.getEquipmentName())
+ .setBus(bus.getId())
+ .setConnectableBus(bus.getId())
+ .setBmax(staticVarCompensatorCreationInfos.getMaxSusceptance())
+ .setBmin(staticVarCompensatorCreationInfos.getMinSusceptance())
+ .setVoltageSetpoint(staticVarCompensatorCreationInfos.getVoltageSetpoint())
+ .setReactivePowerSetpoint(staticVarCompensatorCreationInfos.getReactivePowerSetpoint())
+ .setRegulationMode(staticVarCompensatorCreationInfos.getRegulationMode())
+ .add();
+
+ addExtensionsToStaticVarCompensator(staticVarCompensatorCreationInfos, staticVarCompensator, voltageLevel, subReportNode);
+ }
+
+ private void createStaticVarCompensatorVoltageRegulation(StaticVarCompensatorCreationInfos staticVarCompensatorCreationInfos,
+ StaticVarCompensator staticVarCompensator, VoltageLevel voltageLevel, ReportNode subReportNode) {
+ List voltageReports = new ArrayList<>();
+ voltageReports.add(ModificationUtils.getInstance()
+ .createEnabledDisabledReport("VoltageRegulationOn", modificationInfos.getVoltageRegulationType() == VoltageRegulationType.DISTANT &&
+ modificationInfos.getRegulationMode() == StaticVarCompensator.RegulationMode.VOLTAGE));
+ voltageReports.add(ModificationUtils.getInstance().buildCreationReport(staticVarCompensatorCreationInfos.getVoltageSetpoint(), "Voltage set point"));
+ if (staticVarCompensatorCreationInfos.getRegulatingTerminalVlId() != null && staticVarCompensatorCreationInfos.getRegulatingTerminalId() != null &&
+ staticVarCompensatorCreationInfos.getRegulatingTerminalType() != null) {
+ Terminal terminal = ModificationUtils.getInstance().getTerminalFromIdentifiable(voltageLevel.getNetwork(),
+ staticVarCompensatorCreationInfos.getRegulatingTerminalId(),
+ staticVarCompensatorCreationInfos.getRegulatingTerminalType(),
+ staticVarCompensatorCreationInfos.getRegulatingTerminalVlId());
+ if (terminal != null) {
+ updateCompensatorRegulatingTerminal(staticVarCompensatorCreationInfos, staticVarCompensator, terminal, voltageReports);
+ }
+ }
+ ModificationUtils.getInstance().reportModifications(subReportNode, voltageReports, "VoltageRegulationCreated", "Voltage regulation");
+ }
+
+ private void updateCompensatorRegulatingTerminal(StaticVarCompensatorCreationInfos staticVarCompensatorCreationInfos, StaticVarCompensator staticVarCompensator,
+ Terminal terminal, List voltageReports) {
+ if (staticVarCompensatorCreationInfos.getRegulatingTerminalId() != null
+ && staticVarCompensatorCreationInfos.getRegulatingTerminalType() != null
+ && staticVarCompensatorCreationInfos.getRegulatingTerminalVlId() != null) {
+ staticVarCompensator.setRegulatingTerminal(terminal);
+ voltageReports.add(ModificationUtils.getInstance().buildCreationReport(
+ staticVarCompensatorCreationInfos.getRegulatingTerminalVlId(),
+ "Voltage level"));
+ voltageReports.add(ModificationUtils.getInstance().buildCreationReport(
+ staticVarCompensatorCreationInfos.getRegulatingTerminalType() + ":"
+ + staticVarCompensatorCreationInfos.getRegulatingTerminalId(),
+ "Equipment"));
+ }
+ }
+
+}
diff --git a/src/main/java/org/gridsuite/modification/server/modifications/VscCreation.java b/src/main/java/org/gridsuite/modification/server/modifications/VscCreation.java
index 4e4540e1c..8d0e0862e 100644
--- a/src/main/java/org/gridsuite/modification/server/modifications/VscCreation.java
+++ b/src/main/java/org/gridsuite/modification/server/modifications/VscCreation.java
@@ -9,8 +9,6 @@
import com.powsybl.commons.report.ReportNode;
import com.powsybl.commons.report.TypedValue;
-import com.powsybl.iidm.modification.topology.CreateFeederBay;
-import com.powsybl.iidm.modification.topology.CreateFeederBayBuilder;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.HvdcAngleDroopActivePowerControlAdder;
import com.powsybl.iidm.network.extensions.HvdcOperatorActivePowerRangeAdder;
@@ -22,6 +20,8 @@
import java.util.List;
import static org.gridsuite.modification.server.NetworkModificationException.Type.*;
+import static org.gridsuite.modification.server.modifications.ModificationUtils.createInjectionInNodeBreaker;
+import static org.gridsuite.modification.server.modifications.ModificationUtils.reportInjectionCreationConnectivity;
/**
* @author Seddik Yengui
@@ -212,22 +212,7 @@ private VscConverterStation createConverterStationInNodeBreaker(Network network,
if (converterStationCreationInfos.getVoltageSetpoint() != null) {
converterStationAdder.setVoltageSetpoint(converterStationCreationInfos.getVoltageSetpoint());
}
- int position = ModificationUtils.getInstance().getPosition(converterStationCreationInfos.getConnectionPosition(),
- converterStationCreationInfos.getBusOrBusbarSectionId(),
- network,
- voltageLevel);
-
- CreateFeederBay algo = new CreateFeederBayBuilder()
- .withBusOrBusbarSectionId(converterStationCreationInfos.getBusOrBusbarSectionId())
- .withInjectionDirection(converterStationCreationInfos.getConnectionDirection())
- .withInjectionFeederName(converterStationCreationInfos.getConnectionName() != null
- ? converterStationCreationInfos.getConnectionName()
- : converterStationCreationInfos.getEquipmentId())
- .withInjectionPositionOrder(position)
- .withInjectionAdder(converterStationAdder)
- .build();
-
- algo.apply(network, true, subReportNode);
+ createInjectionInNodeBreaker(voltageLevel, converterStationCreationInfos, network, converterStationAdder, subReportNode);
VscConverterStation vscConverterStation = ModificationUtils.getInstance()
.getVscConverterStation(network, converterStationCreationInfos.getEquipmentId());
@@ -261,7 +246,7 @@ private VscConverterStation createConverterStationInBusBreaker(VoltageLevel volt
private void addExtensionsAndReports(VscConverterStation vscConverterStation,
ConverterStationCreationInfos converterStationCreationInfos,
ReportNode subReporter) {
- reportConnectivity(converterStationCreationInfos, subReporter);
+ reportInjectionCreationConnectivity(converterStationCreationInfos, subReporter);
ModificationUtils.getInstance().reportModifications(subReporter,
List.of(ModificationUtils.getInstance().buildCreationReport(converterStationCreationInfos.getLossFactor(), "Loss Factor")),
@@ -294,34 +279,4 @@ private void reportConverterStationSetPoints(ConverterStationCreationInfos conve
"converterStationSetPointsVoltageRegulation",
"Voltage regulation");
}
-
- private void reportConnectivity(ConverterStationCreationInfos converterStationCreationInfos, ReportNode subReportNode) {
- if (converterStationCreationInfos.getConnectionName() == null &&
- converterStationCreationInfos.getConnectionDirection() == null &&
- converterStationCreationInfos.getConnectionPosition() == null) {
- return;
- }
-
- List connectivityReports = new ArrayList<>();
- if (converterStationCreationInfos.getConnectionName() != null) {
- connectivityReports.add(ModificationUtils.getInstance()
- .buildCreationReport(converterStationCreationInfos.getConnectionName(), "Connection name"));
- }
- if (converterStationCreationInfos.getConnectionDirection() != null) {
- connectivityReports.add(ModificationUtils.getInstance()
- .buildCreationReport(converterStationCreationInfos.getConnectionDirection(), "Connection direction"));
- }
- if (converterStationCreationInfos.getConnectionPosition() != null) {
- connectivityReports.add(ModificationUtils.getInstance()
- .buildCreationReport(converterStationCreationInfos.getConnectionPosition(), "Connection position"));
- }
- if (!converterStationCreationInfos.isTerminalConnected()) {
- connectivityReports.add(ReportNode.newRootReportNode()
- .withMessageTemplate("equipmentDisconnected", " Equipment with id=${id} disconnected")
- .withUntypedValue("id", converterStationCreationInfos.getEquipmentId())
- .withSeverity(TypedValue.INFO_SEVERITY)
- .build());
- }
- ModificationUtils.getInstance().reportModifications(subReportNode, connectivityReports, "ConnectivityCreated", "Connectivity");
- }
}
diff --git a/src/main/resources/db/changelog/changesets/changelog_20240912T100256Z.xml b/src/main/resources/db/changelog/changesets/changelog_20240912T100256Z.xml
new file mode 100644
index 000000000..9a6dd2ebd
--- /dev/null
+++ b/src/main/resources/db/changelog/changesets/changelog_20240912T100256Z.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml
index 1e8120d72..4ef96dc04 100644
--- a/src/main/resources/db/changelog/db.changelog-master.yaml
+++ b/src/main/resources/db/changelog/db.changelog-master.yaml
@@ -310,5 +310,8 @@ databaseChangeLog:
file: changesets/changelog_20240904T211456Z.xml
relativeToChangelogFile: true
- include:
- file: changesets/changelog_20240912T130742Z.xml
+ file: changesets/changelog_20240912T100256Z.xml
+ relativeToChangelogFile: true
+ - include:
relativeToChangelogFile: true
+ file: changesets/changelog_20240912T130742Z.xml
diff --git a/src/test/java/org/gridsuite/modification/server/modifications/StaticVarCompensatorCreationInBusBreakerTest.java b/src/test/java/org/gridsuite/modification/server/modifications/StaticVarCompensatorCreationInBusBreakerTest.java
new file mode 100644
index 000000000..d1b9ee08d
--- /dev/null
+++ b/src/test/java/org/gridsuite/modification/server/modifications/StaticVarCompensatorCreationInBusBreakerTest.java
@@ -0,0 +1,147 @@
+/**
+ * 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/.
+ */
+package org.gridsuite.modification.server.modifications;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.powsybl.iidm.network.Network;
+import com.powsybl.iidm.network.StaticVarCompensator;
+import com.powsybl.iidm.network.extensions.ConnectablePosition;
+import lombok.SneakyThrows;
+import org.gridsuite.modification.server.NetworkModificationException;
+import org.gridsuite.modification.server.dto.FreePropertyInfos;
+import org.gridsuite.modification.server.dto.ModificationInfos;
+import org.gridsuite.modification.server.dto.StaticVarCompensatorCreationInfos;
+import org.gridsuite.modification.server.dto.VoltageRegulationType;
+import org.gridsuite.modification.server.utils.NetworkCreation;
+import org.junit.Test;
+import org.junit.jupiter.api.Tag;
+import org.springframework.http.MediaType;
+
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import static org.gridsuite.modification.server.NetworkModificationException.Type.*;
+import static org.gridsuite.modification.server.utils.TestUtils.assertLogMessage;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+/**
+ * @author Ghazwa Rehili
+ */
+@Tag("IntegrationTest")
+public class StaticVarCompensatorCreationInBusBreakerTest extends AbstractNetworkModificationTest {
+ private static final String PROPERTY_NAME = "property-name";
+ private static final String PROPERTY_VALUE = "property-value";
+
+ @Override
+ protected Network createNetwork(UUID networkUuid) {
+ return NetworkCreation.createBusBreaker(networkUuid);
+ }
+
+ @Override
+ protected ModificationInfos buildModification() {
+ return StaticVarCompensatorCreationInfos.builder()
+ .stashed(false)
+ .equipmentId("idStaticVarCompensator2")
+ .equipmentName("nameStaticVarCompensator2")
+ .voltageLevelId("v1")
+ .busOrBusbarSectionId("bus1")
+ .connectionName("top")
+ .connectionDirection(ConnectablePosition.Direction.TOP)
+ .maxSusceptance(224.0)
+ .minSusceptance(200.0)
+ .regulationMode(StaticVarCompensator.RegulationMode.VOLTAGE)
+ .voltageSetpoint(120.0)
+ .reactivePowerSetpoint(300.0)
+ .voltageRegulationType(VoltageRegulationType.DISTANT)
+ .regulatingTerminalVlId("v1")
+ .regulatingTerminalId("idGenerator1")
+ .regulatingTerminalType("GENERATOR")
+ .standbyAutomatonOn(true)
+ .standby(true)
+ .b0(221.0)
+ .lowVoltageSetpoint(200.0)
+ .highVoltageSetpoint(400.0)
+ .lowVoltageThreshold(250.0)
+ .highVoltageThreshold(300.0)
+ .properties(List.of(FreePropertyInfos.builder().name(PROPERTY_NAME).value(PROPERTY_VALUE).build()))
+ .build();
+ }
+
+ @Override
+ protected ModificationInfos buildModificationUpdate() {
+ return StaticVarCompensatorCreationInfos.builder()
+ .stashed(false)
+ .equipmentId("idStaticVarCompensator2Edited")
+ .equipmentName("staticVarCompensatorNameEdited")
+ .voltageRegulationType(VoltageRegulationType.LOCAL)
+ .regulatingTerminalId("idStaticVarCompensator1")
+ .regulatingTerminalType("STATIC_VAR_COMPENSATOR")
+ .regulatingTerminalVlId("v1")
+ .build();
+ }
+
+ @Override
+ protected void assertAfterNetworkModificationCreation() {
+ assertNotNull(getNetwork().getStaticVarCompensator("idStaticVarCompensator2"));
+ assertEquals(1, getNetwork().getVoltageLevel("v1").getStaticVarCompensatorStream()
+ .filter(transformer -> transformer.getId().equals("idStaticVarCompensator2")).count());
+ assertEquals(PROPERTY_VALUE, getNetwork().getStaticVarCompensator("idStaticVarCompensator2").getProperty(PROPERTY_NAME));
+ }
+
+ @Override
+ protected void assertAfterNetworkModificationDeletion() {
+ assertNull(getNetwork().getStaticVarCompensator("idStaticVarCompensator2"));
+ assertEquals(0, getNetwork().getVoltageLevel("v1").getStaticVarCompensatorStream()
+ .filter(transformer -> transformer.getId().equals("idStaticVarCompensator2")).count());
+ }
+
+ @Test
+ public void testCreateWithBusBarSectionErrors() throws Exception {
+ StaticVarCompensatorCreationInfos staticVarCompensatorCreationInfos = (StaticVarCompensatorCreationInfos) buildModification();
+ staticVarCompensatorCreationInfos.setBusOrBusbarSectionId("notFoundBus");
+ mockMvc.perform(post(getNetworkModificationUri()).content(mapper.writeValueAsString(staticVarCompensatorCreationInfos)).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+ assertLogMessage(new NetworkModificationException(BUS_NOT_FOUND, "notFoundBus").getMessage(),
+ staticVarCompensatorCreationInfos.getErrorType().name(), reportService);
+ }
+
+ @Test
+ public void testCreateWithRegulatedTerminalError() throws Exception {
+ StaticVarCompensatorCreationInfos staticVarCompensatorCreationInfos = (StaticVarCompensatorCreationInfos) buildModification();
+ staticVarCompensatorCreationInfos.setVoltageRegulationType(VoltageRegulationType.DISTANT);
+ staticVarCompensatorCreationInfos.setRegulatingTerminalVlId("v1");
+ staticVarCompensatorCreationInfos.setRegulatingTerminalId("test");
+ staticVarCompensatorCreationInfos.setRegulatingTerminalType("STATIC_VAR_COMPENSATOR");
+
+ String staticVarCompensatorInfosJson = mapper.writeValueAsString(staticVarCompensatorCreationInfos);
+ mockMvc.perform(post(getNetworkModificationUri()).content(staticVarCompensatorInfosJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+ assertLogMessage(new NetworkModificationException(EQUIPMENT_NOT_FOUND, "Equipment with id=test not found with type STATIC_VAR_COMPENSATOR").getMessage(),
+ staticVarCompensatorCreationInfos.getErrorType().name(), reportService);
+ }
+
+ @Override
+ @SneakyThrows
+ protected void testCreationModificationMessage(ModificationInfos modificationInfos) {
+ assertEquals("STATIC_VAR_COMPENSATOR_CREATION", modificationInfos.getMessageType());
+ Map createdValues = mapper.readValue(modificationInfos.getMessageValues(), new TypeReference<>() { });
+ assertEquals("idStaticVarCompensator2", createdValues.get("equipmentId"));
+ }
+
+ @Override
+ @SneakyThrows
+ protected void testUpdateModificationMessage(ModificationInfos modificationInfos) {
+ assertEquals("STATIC_VAR_COMPENSATOR_CREATION", modificationInfos.getMessageType());
+ Map createdValues = mapper.readValue(modificationInfos.getMessageValues(), new TypeReference<>() { });
+ assertEquals("idStaticVarCompensator2Edited", createdValues.get("equipmentId"));
+ }
+}
diff --git a/src/test/java/org/gridsuite/modification/server/modifications/StaticVarCompensatorCreationInNodeBreakerTest.java b/src/test/java/org/gridsuite/modification/server/modifications/StaticVarCompensatorCreationInNodeBreakerTest.java
new file mode 100644
index 000000000..eed31aafb
--- /dev/null
+++ b/src/test/java/org/gridsuite/modification/server/modifications/StaticVarCompensatorCreationInNodeBreakerTest.java
@@ -0,0 +1,240 @@
+/**
+ * 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/.
+ */
+package org.gridsuite.modification.server.modifications;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.powsybl.iidm.network.Network;
+import com.powsybl.iidm.network.StaticVarCompensator;
+import com.powsybl.iidm.network.extensions.ConnectablePosition;
+import lombok.SneakyThrows;
+import org.gridsuite.modification.server.NetworkModificationException;
+import org.gridsuite.modification.server.dto.*;
+import org.gridsuite.modification.server.utils.NetworkCreation;
+import org.junit.Test;
+import org.junit.jupiter.api.Tag;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MvcResult;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+
+import static com.powsybl.iidm.network.StaticVarCompensator.RegulationMode.OFF;
+import static org.gridsuite.modification.server.NetworkModificationException.Type.BUSBAR_SECTION_NOT_FOUND;
+import static org.gridsuite.modification.server.NetworkModificationException.Type.VOLTAGE_LEVEL_NOT_FOUND;
+import static org.gridsuite.modification.server.utils.TestUtils.assertLogMessage;
+import static org.junit.Assert.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+/**
+ * @author Ghazwa Rehili
+ */
+@Tag("IntegrationTest")
+public class StaticVarCompensatorCreationInNodeBreakerTest extends AbstractNetworkModificationTest {
+ private static final String PROPERTY_NAME = "property-name";
+ private static final String PROPERTY_VALUE = "property-value";
+
+ @Override
+ protected Network createNetwork(UUID networkUuid) {
+ return NetworkCreation.create(networkUuid, true);
+ }
+
+ @Override
+ protected ModificationInfos buildModification() {
+ return StaticVarCompensatorCreationInfos.builder()
+ .stashed(false)
+ .equipmentId("idStaticVarCompensator1")
+ .equipmentName("nameStaticVarCompensator1")
+ .voltageLevelId("v2")
+ .busOrBusbarSectionId("1B")
+ .connectionName("top")
+ .connectionDirection(ConnectablePosition.Direction.TOP)
+ .maxSusceptance(224.0)
+ .minSusceptance(200.0)
+ .regulationMode(StaticVarCompensator.RegulationMode.VOLTAGE)
+ .voltageSetpoint(120.0)
+ .reactivePowerSetpoint(300.0)
+ .voltageRegulationType(VoltageRegulationType.LOCAL)
+ .standbyAutomatonOn(false)
+ .properties(List.of(FreePropertyInfos.builder().name(PROPERTY_NAME).value(PROPERTY_VALUE).build()))
+ .build();
+ }
+
+ @Override
+ protected ModificationInfos buildModificationUpdate() {
+ return StaticVarCompensatorCreationInfos.builder()
+ .stashed(false)
+ .equipmentId("idStaticVarCompensator1Edited")
+ .equipmentName("staticVarCompensatorNameEdited")
+ .standbyAutomatonOn(true)
+ .standby(true)
+ .b0(221.0)
+ .lowVoltageSetpoint(200.0)
+ .highVoltageSetpoint(400.0)
+ .lowVoltageThreshold(250.0)
+ .highVoltageThreshold(300.0)
+ .voltageRegulationType(VoltageRegulationType.DISTANT)
+ .regulatingTerminalId("idStaticVarCompensator1")
+ .regulatingTerminalType("STATIC_VAR_COMPENSATOR")
+ .regulatingTerminalVlId("v2")
+ .build();
+ }
+
+ @Override
+ protected void assertAfterNetworkModificationCreation() {
+ assertNotNull(getNetwork().getStaticVarCompensator("idStaticVarCompensator1"));
+ assertEquals(1, getNetwork().getVoltageLevel("v2").getStaticVarCompensatorStream()
+ .filter(transformer -> transformer.getId().equals("idStaticVarCompensator1")).count());
+ assertEquals(PROPERTY_VALUE, getNetwork().getStaticVarCompensator("idStaticVarCompensator1").getProperty(PROPERTY_NAME));
+ }
+
+ @Override
+ protected void assertAfterNetworkModificationDeletion() {
+ assertNull(getNetwork().getStaticVarCompensator("idStaticVarCompensator2"));
+ assertEquals(0, getNetwork().getVoltageLevel("v2").getStaticVarCompensatorStream()
+ .filter(transformer -> transformer.getId().equals("idStaticVarCompensator2")).count());
+ }
+
+ @Test
+ public void testCreateWithErrors() throws Exception {
+ // invalid Generator id
+ StaticVarCompensatorCreationInfos compensatorCreationInfos = (StaticVarCompensatorCreationInfos) buildModification();
+ compensatorCreationInfos.setEquipmentId("");
+ String compensatorCreationInfosJson = mapper.writeValueAsString(compensatorCreationInfos);
+ mockMvc.perform(post(getNetworkModificationUri()).content(compensatorCreationInfosJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+ assertLogMessage("Invalid id ''", compensatorCreationInfos.getErrorType().name(), reportService);
+
+ // not found voltage level
+ compensatorCreationInfos.setEquipmentId("idStaticVarCompensator2");
+ compensatorCreationInfos.setVoltageLevelId("notFoundVoltageLevelId");
+ compensatorCreationInfosJson = mapper.writeValueAsString(compensatorCreationInfos);
+ mockMvc.perform(post(getNetworkModificationUri()).content(compensatorCreationInfosJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+ assertLogMessage(new NetworkModificationException(VOLTAGE_LEVEL_NOT_FOUND, "notFoundVoltageLevelId").getMessage(),
+ compensatorCreationInfos.getErrorType().name(), reportService);
+
+ // not found busbar section
+ compensatorCreationInfos.setVoltageLevelId("v2");
+ compensatorCreationInfos.setBusOrBusbarSectionId("notFoundBusbarSection");
+ compensatorCreationInfosJson = mapper.writeValueAsString(compensatorCreationInfos);
+ mockMvc.perform(post(getNetworkModificationUri()).content(compensatorCreationInfosJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+ assertLogMessage(new NetworkModificationException(BUSBAR_SECTION_NOT_FOUND, "notFoundBusbarSection").getMessage(),
+ compensatorCreationInfos.getErrorType().name(), reportService);
+
+ // invalid min susceptance
+ compensatorCreationInfos.setVoltageLevelId("v2");
+ compensatorCreationInfos.setBusOrBusbarSectionId("1B");
+ compensatorCreationInfos.setMinSusceptance(null);
+ compensatorCreationInfos.setMinQAtNominalV(null);
+
+ compensatorCreationInfosJson = mapper.writeValueAsString(compensatorCreationInfos);
+ mockMvc.perform(post(getNetworkModificationUri()).content(compensatorCreationInfosJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+ assertLogMessage("CREATE_STATIC_VAR_COMPENSATOR_ERROR : StaticVarCompensator 'idStaticVarCompensator2' : minimum susceptance is not set",
+ compensatorCreationInfos.getErrorType().name(), reportService);
+ compensatorCreationInfos.setMinSusceptance(200.0);
+ compensatorCreationInfos.setMaxSusceptance(null);
+ compensatorCreationInfos.setMaxQAtNominalV(null);
+ compensatorCreationInfosJson = mapper.writeValueAsString(compensatorCreationInfos);
+ mockMvc.perform(post(getNetworkModificationUri()).content(compensatorCreationInfosJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+ assertLogMessage("CREATE_STATIC_VAR_COMPENSATOR_ERROR : " +
+ "StaticVarCompensator 'idStaticVarCompensator2' : maximum susceptance is not set",
+ compensatorCreationInfos.getErrorType().name(), reportService);
+
+ compensatorCreationInfos.setMaxSusceptance(100.0);
+ compensatorCreationInfos.setMinSusceptance(200.0);
+ compensatorCreationInfos.setRegulationMode(StaticVarCompensator.RegulationMode.REACTIVE_POWER);
+ compensatorCreationInfos.setReactivePowerSetpoint(null);
+ compensatorCreationInfosJson = mapper.writeValueAsString(compensatorCreationInfos);
+ mockMvc.perform(post(getNetworkModificationUri()).content(compensatorCreationInfosJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+ assertLogMessage("CREATE_STATIC_VAR_COMPENSATOR_ERROR : " +
+ "StaticVarCompensator 'idStaticVarCompensator2' : maximum susceptance is expected to be greater than or equal to minimum susceptance",
+ compensatorCreationInfos.getErrorType().name(), reportService);
+ compensatorCreationInfos.setMaxSusceptance(200.0);
+ compensatorCreationInfos.setMinSusceptance(100.0);
+ compensatorCreationInfos.setRegulationMode(StaticVarCompensator.RegulationMode.REACTIVE_POWER);
+ compensatorCreationInfos.setReactivePowerSetpoint(null);
+ compensatorCreationInfosJson = mapper.writeValueAsString(compensatorCreationInfos);
+ mockMvc.perform(post(getNetworkModificationUri()).content(compensatorCreationInfosJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+ assertLogMessage("CREATE_STATIC_VAR_COMPENSATOR_ERROR : " +
+ "StaticVarCompensator 'idStaticVarCompensator2' : Reactive power setpoint is not set",
+ compensatorCreationInfos.getErrorType().name(), reportService);
+
+ compensatorCreationInfos.setRegulationMode(StaticVarCompensator.RegulationMode.VOLTAGE);
+ compensatorCreationInfos.setVoltageSetpoint(null);
+ compensatorCreationInfosJson = mapper.writeValueAsString(compensatorCreationInfos);
+ mockMvc.perform(post(getNetworkModificationUri()).content(compensatorCreationInfosJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+ assertLogMessage("CREATE_STATIC_VAR_COMPENSATOR_ERROR : " +
+ "StaticVarCompensator 'idStaticVarCompensator2' : Voltage setpoint is not set",
+ compensatorCreationInfos.getErrorType().name(), reportService);
+ compensatorCreationInfos.setEquipmentId("idStaticVarCompensator3");
+ compensatorCreationInfos.setEquipmentName("nameStaticVarCompensator3");
+ compensatorCreationInfos.setVoltageLevelId("v2");
+ compensatorCreationInfos.setBusOrBusbarSectionId("1B");
+ compensatorCreationInfosJson = mapper.writeValueAsString(compensatorCreationInfos);
+ MvcResult mvcResult = mockMvc.perform(post(getNetworkModificationUriWithBadVariant()).content(compensatorCreationInfosJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk()).andReturn();
+ Optional networkModificationResult = mapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<>() {
+ });
+ assertTrue(networkModificationResult.isEmpty());
+ assertNull(getNetwork().getStaticVarCompensator("idStaticVarCompensator3"));
+ testNetworkModificationsCount(getGroupId(), 9);
+ }
+
+ @Test
+ public void testCreateWithStandbyAutomatonErrors() throws Exception {
+ StaticVarCompensatorCreationInfos compensatorCreationInfos = (StaticVarCompensatorCreationInfos) buildModification();
+ compensatorCreationInfos.setStandbyAutomatonOn(true);
+ compensatorCreationInfos.setB0(300.0);
+
+ String compensatorCreationInfosJson = mapper.writeValueAsString(compensatorCreationInfos);
+ mockMvc.perform(post(getNetworkModificationUri()).content(compensatorCreationInfosJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+ assertLogMessage("CREATE_STATIC_VAR_COMPENSATOR_ERROR : " +
+ "StaticVarCompensator 'idStaticVarCompensator1' : b0 must be within the range of minimun susceptance and maximum susceptance",
+ compensatorCreationInfos.getErrorType().name(), reportService);
+
+ compensatorCreationInfos.setB0(200.0);
+ compensatorCreationInfos.setRegulationMode(OFF);
+ compensatorCreationInfos.setStandby(true);
+
+ compensatorCreationInfosJson = mapper.writeValueAsString(compensatorCreationInfos);
+ mockMvc.perform(post(getNetworkModificationUri()).content(compensatorCreationInfosJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+ assertLogMessage("CREATE_STATIC_VAR_COMPENSATOR_ERROR : " +
+ "StaticVarCompensator 'idStaticVarCompensator1' : Standby is only supported in Voltage Regulation mode",
+ compensatorCreationInfos.getErrorType().name(), reportService);
+
+ }
+
+ @Override
+ @SneakyThrows
+ protected void testCreationModificationMessage(ModificationInfos modificationInfos) {
+ assertEquals("STATIC_VAR_COMPENSATOR_CREATION", modificationInfos.getMessageType());
+ Map updatedValues = mapper.readValue(modificationInfos.getMessageValues(), new TypeReference<>() {
+ });
+ assertEquals("idStaticVarCompensator1", updatedValues.get("equipmentId"));
+ }
+
+ @Override
+ @SneakyThrows
+ protected void testUpdateModificationMessage(ModificationInfos modificationInfos) {
+ assertEquals("STATIC_VAR_COMPENSATOR_CREATION", modificationInfos.getMessageType());
+ Map updatedValues = mapper.readValue(modificationInfos.getMessageValues(), new TypeReference<>() {
+ });
+ assertEquals("idStaticVarCompensator1Edited", updatedValues.get("equipmentId"));
+ }
+}
diff --git a/src/test/java/org/gridsuite/modification/server/service/ModificationRepositoryTest.java b/src/test/java/org/gridsuite/modification/server/service/ModificationRepositoryTest.java
index 4205beb42..402531564 100644
--- a/src/test/java/org/gridsuite/modification/server/service/ModificationRepositoryTest.java
+++ b/src/test/java/org/gridsuite/modification/server/service/ModificationRepositoryTest.java
@@ -35,9 +35,11 @@
import java.util.*;
import java.util.stream.Collectors;
+import static com.powsybl.iidm.network.StaticVarCompensator.RegulationMode.VOLTAGE;
import static org.gridsuite.modification.server.NetworkModificationException.Type.MODIFICATION_GROUP_NOT_FOUND;
import static org.gridsuite.modification.server.NetworkModificationException.Type.MODIFICATION_NOT_FOUND;
import static org.gridsuite.modification.server.NetworkModificationException.Type.MOVE_MODIFICATION_ERROR;
+import static org.gridsuite.modification.server.dto.VoltageRegulationType.DISTANT;
import static org.gridsuite.modification.server.utils.TestUtils.assertRequestsCount;
import static org.gridsuite.modification.server.utils.assertions.Assertions.assertThat;
import static org.junit.Assert.*;
@@ -103,6 +105,10 @@ public ShuntCompensatorCreationInfos getShuntCompensatorCreationModification(UUI
return (ShuntCompensatorCreationInfos) networkModificationRepository.getModificationInfo(modificationUuid);
}
+ private StaticVarCompensatorCreationInfos getStaticVarCompensatorCreationModification(UUID modificationUuid) {
+ return (StaticVarCompensatorCreationInfos) networkModificationRepository.getModificationInfo(modificationUuid);
+ }
+
private LineSplitWithVoltageLevelInfos getLineSplitWithVoltageLevelModification(UUID modificationUuid) {
return (LineSplitWithVoltageLevelInfos) networkModificationRepository.getModificationInfo(modificationUuid);
}
@@ -1272,4 +1278,71 @@ public void testModificationOrder() {
assertEquals(1, movedEntities.size());
assertEquals(1, movedEntities.get(0).getModificationsOrder());
}
+
+ @Test
+ public void testStaticVarCompensatorCreation() {
+ var createStaticVarCompensator1 = StaticVarCompensatorCreationInfos.builder()
+ .equipmentId("idStaticVarCompensator1").equipmentName("nameStaticVarCompensator1")
+ .voltageLevelId("vlId1")
+ .busOrBusbarSectionId("busId1")
+ .minSusceptance(200.0)
+ .maxSusceptance(224.0)
+ .regulationMode(VOLTAGE)
+ .voltageSetpoint(200.0)
+ .voltageRegulationType(DISTANT)
+ .regulatingTerminalId("testTerminalId1")
+ .regulatingTerminalType("STATIC_VAR_COMPENSATOR").regulatingTerminalVlId("idVlTest1")
+ .connectionName("Top").connectionDirection(ConnectablePosition.Direction.TOP)
+ .connectionPosition(1).build().toEntity();
+ var createStaticVarCompensator2 = StaticVarCompensatorCreationInfos.builder()
+ .equipmentId("idStaticVarCompensator2").equipmentName("nameStaticVarCompensator2")
+ .voltageLevelId("vlId2")
+ .busOrBusbarSectionId("busId2")
+ .regulatingTerminalId(null)
+ .regulatingTerminalType(null).regulatingTerminalVlId("idVlTest2")
+ .connectionName("Bot").connectionDirection(ConnectablePosition.Direction.BOTTOM)
+ .connectionPosition(2).build().toEntity();
+ var createStaticVarCompensator3 = StaticVarCompensatorCreationInfos.builder()
+ .equipmentId("idStaticVarCompensator3").equipmentName("nameStaticVarCompensator3")
+ .voltageLevelId("vlId2")
+ .busOrBusbarSectionId("busId2")
+ .regulatingTerminalId(null)
+ .regulatingTerminalType(null).regulatingTerminalVlId("idVlTest2")
+ .connectionName("Bot").connectionDirection(ConnectablePosition.Direction.BOTTOM)
+ .connectionPosition(2)
+ .regulationMode(VOLTAGE)
+ .standbyAutomatonOn(true)
+ .standby(true)
+ .build().toEntity();
+
+ networkModificationRepository.saveModifications(TEST_GROUP_ID, List.of(createStaticVarCompensator1, createStaticVarCompensator2, createStaticVarCompensator3));
+ assertRequestsCount(1, 3, 1, 0);
+
+ List modificationInfos = networkModificationRepository.getModifications(TEST_GROUP_ID, true, true);
+ assertEquals(3, modificationInfos.size());
+
+ assertThat(getStaticVarCompensatorCreationModification(modificationInfos.get(0).getUuid()))
+ .recursivelyEquals(createStaticVarCompensator1.toModificationInfos());
+ assertThat(getStaticVarCompensatorCreationModification(modificationInfos.get(1).getUuid()))
+ .recursivelyEquals(createStaticVarCompensator2.toModificationInfos());
+
+ assertEquals(3, networkModificationRepository.getModifications(TEST_GROUP_ID, true, true).size());
+ assertEquals(List.of(TEST_GROUP_ID), this.networkModificationRepository.getModificationGroupsUuids());
+
+ SQLStatementCountValidator.reset();
+ networkModificationRepository.deleteModifications(TEST_GROUP_ID, List.of(createStaticVarCompensator2.getId(), createStaticVarCompensator3.getId()));
+ assertRequestsCount(4, 0, 1, 2);
+
+ SQLStatementCountValidator.reset();
+ assertEquals(1, networkModificationRepository.getModifications(TEST_GROUP_ID, true, true).size());
+ assertRequestsCount(2, 0, 0, 0);
+
+ SQLStatementCountValidator.reset();
+ networkModificationRepository.deleteModificationGroup(TEST_GROUP_ID, true);
+ assertRequestsCount(3, 0, 0, 3);
+
+ assertThrows(new NetworkModificationException(MODIFICATION_GROUP_NOT_FOUND, TEST_GROUP_ID.toString()).getMessage(),
+ NetworkModificationException.class, () -> networkModificationRepository.getModifications(TEST_GROUP_ID, true, true)
+ );
+ }
}