diff --git a/pom.xml b/pom.xml
index 4ae6efa1a..7359947bc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -144,6 +144,11 @@
com.powsybl
powsybl-network-store-client
+
+ com.powsybl
+ powsybl-network-store-iidm-impl
+ 1.7.0
+
com.powsybl
powsybl-ws-commons
diff --git a/src/main/java/org/gridsuite/modification/server/dto/SubstationInfos.java b/src/main/java/org/gridsuite/modification/server/dto/SubstationInfos.java
index cb1ae27d5..83ac6de37 100644
--- a/src/main/java/org/gridsuite/modification/server/dto/SubstationInfos.java
+++ b/src/main/java/org/gridsuite/modification/server/dto/SubstationInfos.java
@@ -6,10 +6,7 @@
*/
package org.gridsuite.modification.server.dto;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.ToString;
+import lombok.*;
import lombok.experimental.SuperBuilder;
/**
@@ -17,6 +14,7 @@
*/
@SuperBuilder
@NoArgsConstructor
+@AllArgsConstructor
@Getter
@ToString
@EqualsAndHashCode
diff --git a/src/main/java/org/gridsuite/modification/server/dto/VoltageLevelInfos.java b/src/main/java/org/gridsuite/modification/server/dto/VoltageLevelInfos.java
index 272eb9627..a4d244eb8 100644
--- a/src/main/java/org/gridsuite/modification/server/dto/VoltageLevelInfos.java
+++ b/src/main/java/org/gridsuite/modification/server/dto/VoltageLevelInfos.java
@@ -6,10 +6,7 @@
*/
package org.gridsuite.modification.server.dto;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.ToString;
+import lombok.*;
import lombok.experimental.SuperBuilder;
/**
@@ -17,6 +14,7 @@
*/
@SuperBuilder
@NoArgsConstructor
+@AllArgsConstructor
@Getter
@ToString
@EqualsAndHashCode
diff --git a/src/main/java/org/gridsuite/modification/server/dto/elasticsearch/EquipmentInfos.java b/src/main/java/org/gridsuite/modification/server/dto/elasticsearch/EquipmentInfos.java
index 9770e4e69..92b748e6d 100644
--- a/src/main/java/org/gridsuite/modification/server/dto/elasticsearch/EquipmentInfos.java
+++ b/src/main/java/org/gridsuite/modification/server/dto/elasticsearch/EquipmentInfos.java
@@ -101,5 +101,4 @@ public static Set getSubstationsInfos(@NonNull Identifiable>
.name(vl.getSubstation().map(Substation::getNameOrId).orElse(null)).build())
.collect(Collectors.toSet());
}
-
}
diff --git a/src/main/java/org/gridsuite/modification/server/dto/formula/ReferenceFieldOrValue.java b/src/main/java/org/gridsuite/modification/server/dto/formula/ReferenceFieldOrValue.java
index a7d2ea60e..aaae6b502 100644
--- a/src/main/java/org/gridsuite/modification/server/dto/formula/ReferenceFieldOrValue.java
+++ b/src/main/java/org/gridsuite/modification/server/dto/formula/ReferenceFieldOrValue.java
@@ -13,6 +13,7 @@
import com.powsybl.iidm.network.IdentifiableType;
import com.powsybl.iidm.network.Load;
import com.powsybl.iidm.network.ShuntCompensator;
+import com.powsybl.iidm.network.TwoWindingsTransformer;
import com.powsybl.iidm.network.VoltageLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -24,6 +25,7 @@
import org.gridsuite.modification.server.dto.formula.equipmentfield.GeneratorField;
import org.gridsuite.modification.server.dto.formula.equipmentfield.LoadField;
import org.gridsuite.modification.server.dto.formula.equipmentfield.ShuntCompensatorField;
+import org.gridsuite.modification.server.dto.formula.equipmentfield.TwoWindingsTransformerField;
import org.gridsuite.modification.server.dto.formula.equipmentfield.VoltageLevelField;
@@ -52,21 +54,15 @@ public Double getRefOrValue(Identifiable> identifiable) {
}
IdentifiableType identifiableType = identifiable.getType();
- Double referenceValue = switch (identifiableType) {
+ return switch (identifiableType) {
case GENERATOR -> GeneratorField.getReferenceValue((Generator) identifiable, equipmentField);
case BATTERY -> BatteryField.getReferenceValue((Battery) identifiable, equipmentField);
case SHUNT_COMPENSATOR -> ShuntCompensatorField.getReferenceValue((ShuntCompensator) identifiable, equipmentField);
case VOLTAGE_LEVEL -> VoltageLevelField.getReferenceValue((VoltageLevel) identifiable, equipmentField);
case LOAD -> LoadField.getReferenceValue((Load) identifiable, equipmentField);
+ case TWO_WINDINGS_TRANSFORMER -> TwoWindingsTransformerField.getReferenceValue((TwoWindingsTransformer) identifiable, equipmentField);
default -> throw new NetworkModificationException(NetworkModificationException.Type.BY_FORMULA_MODIFICATION_ERROR,
String.format("Unsupported equipment type : %s", identifiableType.name()));
};
-
- if (referenceValue == null) {
- throw new NetworkModificationException(NetworkModificationException.Type.BY_FORMULA_MODIFICATION_ERROR,
- String.format("value of %s is null", equipmentField));
- }
-
- return referenceValue;
}
}
diff --git a/src/main/java/org/gridsuite/modification/server/dto/formula/equipmentfield/TwoWindingsTransformerField.java b/src/main/java/org/gridsuite/modification/server/dto/formula/equipmentfield/TwoWindingsTransformerField.java
new file mode 100644
index 000000000..e784d9744
--- /dev/null
+++ b/src/main/java/org/gridsuite/modification/server/dto/formula/equipmentfield/TwoWindingsTransformerField.java
@@ -0,0 +1,70 @@
+package org.gridsuite.modification.server.dto.formula.equipmentfield;
+
+import com.powsybl.iidm.network.PhaseTapChanger;
+import com.powsybl.iidm.network.RatioTapChanger;
+import com.powsybl.iidm.network.TwoWindingsTransformer;
+
+public enum TwoWindingsTransformerField {
+ SERIES_RESISTANCE,
+ SERIES_REACTANCE,
+ MAGNETIZING_CONDUCTANCE,
+ MAGNETIZING_SUSCEPTANCE,
+ RATED_VOLTAGE_1,
+ RATED_VOLTAGE_2,
+ RATED_S,
+ TARGET_V,
+ RATIO_LOW_TAP_POSITION,
+ RATIO_TAP_POSITION,
+ RATIO_TARGET_DEADBAND,
+ REGULATION_VALUE,
+ PHASE_LOW_TAP_POSITION,
+ PHASE_TAP_POSITION,
+ PHASE_TARGET_DEADBAND;
+
+ public static Double getReferenceValue(TwoWindingsTransformer transformer, String twoWindingsTransformerField) {
+ TwoWindingsTransformerField field = TwoWindingsTransformerField.valueOf(twoWindingsTransformerField);
+ final PhaseTapChanger phaseTapChanger = transformer.getPhaseTapChanger();
+ final RatioTapChanger ratioTapChanger = transformer.getRatioTapChanger();
+ return switch (field) {
+ case SERIES_RESISTANCE -> transformer.getR();
+ case SERIES_REACTANCE -> transformer.getX();
+ case MAGNETIZING_CONDUCTANCE -> transformer.getG();
+ case MAGNETIZING_SUSCEPTANCE -> transformer.getB();
+ case RATED_VOLTAGE_1 -> transformer.getRatedU1();
+ case RATED_VOLTAGE_2 -> transformer.getRatedU2();
+ case RATED_S -> transformer.getRatedS();
+ case TARGET_V -> ratioTapChanger != null ? ratioTapChanger.getTargetV() : null;
+ case RATIO_LOW_TAP_POSITION -> ratioTapChanger != null ? (double) ratioTapChanger.getLowTapPosition() : null;
+ case RATIO_TAP_POSITION -> ratioTapChanger != null ? (double) ratioTapChanger.getTapPosition() : null;
+ case RATIO_TARGET_DEADBAND -> ratioTapChanger != null ? ratioTapChanger.getTargetDeadband() : null;
+ case REGULATION_VALUE -> phaseTapChanger != null ? phaseTapChanger.getRegulationValue() : null;
+ case PHASE_LOW_TAP_POSITION -> phaseTapChanger != null ? (double) phaseTapChanger.getLowTapPosition() : null;
+ case PHASE_TAP_POSITION -> phaseTapChanger != null ? (double) phaseTapChanger.getTapPosition() : null;
+ case PHASE_TARGET_DEADBAND -> phaseTapChanger != null ? phaseTapChanger.getTargetDeadband() : null;
+ };
+ }
+
+ public static void setNewValue(TwoWindingsTransformer transformer, String twoWindingsTransformerField, Double newValue) {
+ TwoWindingsTransformerField field = TwoWindingsTransformerField.valueOf(twoWindingsTransformerField);
+ final PhaseTapChanger phaseTapChanger = transformer.getPhaseTapChanger();
+ final RatioTapChanger ratioTapChanger = transformer.getRatioTapChanger();
+
+ switch (field) {
+ case SERIES_RESISTANCE -> transformer.setR(newValue);
+ case SERIES_REACTANCE -> transformer.setX(newValue);
+ case MAGNETIZING_CONDUCTANCE -> transformer.setG(newValue);
+ case MAGNETIZING_SUSCEPTANCE -> transformer.setB(newValue);
+ case RATED_VOLTAGE_1 -> transformer.setRatedU1(newValue);
+ case RATED_VOLTAGE_2 -> transformer.setRatedU2(newValue);
+ case RATED_S -> transformer.setRatedS(newValue);
+ case TARGET_V -> ratioTapChanger.setTargetV(newValue);
+ case RATIO_LOW_TAP_POSITION -> ratioTapChanger.setLowTapPosition(newValue.intValue());
+ case RATIO_TAP_POSITION -> ratioTapChanger.setTapPosition(newValue.intValue());
+ case RATIO_TARGET_DEADBAND -> ratioTapChanger.setTargetDeadband(newValue);
+ case REGULATION_VALUE -> phaseTapChanger.setRegulationValue(newValue);
+ case PHASE_LOW_TAP_POSITION -> phaseTapChanger.setLowTapPosition(newValue.intValue());
+ case PHASE_TAP_POSITION -> phaseTapChanger.setTapPosition(newValue.intValue());
+ case PHASE_TARGET_DEADBAND -> phaseTapChanger.setTargetDeadband(newValue);
+ }
+ }
+}
diff --git a/src/main/java/org/gridsuite/modification/server/entities/TabularModificationEntity.java b/src/main/java/org/gridsuite/modification/server/entities/TabularModificationEntity.java
index 5fec9f1c4..8694d641b 100644
--- a/src/main/java/org/gridsuite/modification/server/entities/TabularModificationEntity.java
+++ b/src/main/java/org/gridsuite/modification/server/entities/TabularModificationEntity.java
@@ -18,6 +18,7 @@
import org.gridsuite.modification.server.dto.*;
import org.gridsuite.modification.server.entities.equipment.modification.GeneratorModificationEntity;
import org.gridsuite.modification.server.entities.equipment.modification.LoadModificationEntity;
+import org.gridsuite.modification.server.entities.equipment.modification.VoltageLevelModificationEntity;
/**
* @author Etienne Homer
@@ -46,6 +47,9 @@ public TabularModificationEntity(TabularModificationInfos tabularModificationInf
case "LOAD_MODIFICATION":
modifications = tabularModificationInfos.getModifications().stream().map(loadModificationInfos -> new LoadModificationEntity((LoadModificationInfos) loadModificationInfos)).collect(Collectors.toList());
break;
+ case "VOLTAGE_LEVEL_MODIFICATION":
+ modifications = tabularModificationInfos.getModifications().stream().map(voltageLevelModificationInfos -> new VoltageLevelModificationEntity((VoltageLevelModificationInfos) voltageLevelModificationInfos)).collect(Collectors.toList());
+ break;
default:
break;
}
@@ -76,6 +80,9 @@ public void update(@NonNull ModificationInfos modificationInfos) {
case "LOAD_MODIFICATION":
modifications.addAll(tabularModificationInfos.getModifications().stream().map(loadModificationInfos -> new LoadModificationEntity((LoadModificationInfos) loadModificationInfos)).collect(Collectors.toList()));
break;
+ case "VOLTAGE_LEVEL_MODIFICATION":
+ modifications.addAll(tabularModificationInfos.getModifications().stream().map(voltageLevelModificationInfos -> new VoltageLevelModificationEntity((VoltageLevelModificationInfos) voltageLevelModificationInfos)).collect(Collectors.toList()));
+ break;
default:
break;
}
diff --git a/src/main/java/org/gridsuite/modification/server/modifications/AbstractScaling.java b/src/main/java/org/gridsuite/modification/server/modifications/AbstractScaling.java
index 59aeb0895..bc966d805 100644
--- a/src/main/java/org/gridsuite/modification/server/modifications/AbstractScaling.java
+++ b/src/main/java/org/gridsuite/modification/server/modifications/AbstractScaling.java
@@ -10,18 +10,15 @@
import com.powsybl.commons.reporter.TypedValue;
import com.powsybl.iidm.modification.scalable.Scalable;
import com.powsybl.iidm.network.Network;
-import com.powsybl.network.store.iidm.impl.NetworkImpl;
import org.gridsuite.modification.server.NetworkModificationException;
import org.gridsuite.modification.server.dto.*;
import org.gridsuite.modification.server.service.FilterService;
import org.springframework.util.CollectionUtils;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Function;
import java.util.stream.Collectors;
import static org.gridsuite.modification.server.modifications.ModificationUtils.createReport;
@@ -52,66 +49,26 @@ public void apply(Network network, Reporter subReporter) {
.filter(distinctByKey(FilterInfos::getId))
.collect(Collectors.toMap(FilterInfos::getId, FilterInfos::getName));
- // export filters from filter server
- String workingVariantId = network.getVariantManager().getWorkingVariantId();
- UUID uuid = ((NetworkImpl) network).getUuid();
- Map exportFilters = filterService
- .exportFilters(new ArrayList<>(filters.keySet()), uuid, workingVariantId)
- .stream()
- .peek(t -> t.setFilterName(filters.get(t.getFilterId())))
- .collect(Collectors.toMap(FilterEquipments::getFilterId, Function.identity()));
-
- // collect all filters with wrong equipments ids
- Map filterWithWrongEquipmentsIds = exportFilters.entrySet().stream()
- .filter(e -> !CollectionUtils.isEmpty(e.getValue().getNotFoundEquipments()))
- .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
-
- Boolean noValidEquipmentId = exportFilters.values().stream()
- .allMatch(filterEquipments -> filterEquipments.getIdentifiableAttributes().isEmpty());
-
- if (noValidEquipmentId) {
- String errorMsg = scalingInfos.getErrorType() + ": There is no valid equipment ID among the provided filter(s)";
- createReport(subReporter, "invalidFilters", errorMsg, TypedValue.ERROR_SEVERITY);
- return;
+ Map exportFilters = ModificationUtils.getUuidFilterEquipmentsMap(filterService, network, subReporter, filters, scalingInfos.getErrorType());
+ if (exportFilters != null) {
+ Map filtersWithWrongEquipmentIds = ModificationUtils.getUuidFilterWrongEquipmentsIdsMap(subReporter, exportFilters, filters);
+
+ // apply variations
+ scalingInfos.getVariations().forEach(variation -> {
+ List identifiableAttributes = ModificationUtils.getIdentifiableAttributes(exportFilters, filtersWithWrongEquipmentIds, variation.getFilters(), subReporter);
+
+ if (CollectionUtils.isEmpty(identifiableAttributes)) {
+ String filterNames = variation.getFilters().stream().map(FilterInfos::getName).collect(Collectors.joining(", "));
+ createReport(subReporter,
+ "allFiltersWrong",
+ String.format("All of the following variation's filters have equipments with wrong id : %s", filterNames),
+ TypedValue.WARN_SEVERITY);
+ } else {
+ applyVariation(network, subReporter, identifiableAttributes, variation);
+ }
+ });
+ createReport(subReporter, "scalingCreated", "new scaling created", TypedValue.INFO_SEVERITY);
}
-
- // create report for each wrong filter
- filterWithWrongEquipmentsIds.values().forEach(f -> {
- var equipmentIds = String.join(", ", f.getNotFoundEquipments());
- createReport(subReporter,
- "filterEquipmentsNotFound_" + f.getFilterName(),
- String.format("Cannot find the following equipments %s in filter %s", equipmentIds, filters.get(f.getFilterId())),
- TypedValue.WARN_SEVERITY);
- });
-
- // apply variations
- scalingInfos.getVariations().forEach(variation -> {
- variation.getFilters().stream()
- .filter(f -> !exportFilters.containsKey(f.getId()))
- .forEach(f -> createReport(subReporter,
- "filterNotFound",
- String.format("Cannot find the following filter: %s", f.getName()),
- TypedValue.WARN_SEVERITY));
-
- List identifiableAttributes = variation.getFilters()
- .stream()
- .filter(f -> !filterWithWrongEquipmentsIds.containsKey(f.getId()) && exportFilters.containsKey(f.getId()))
- .flatMap(f -> exportFilters.get(f.getId())
- .getIdentifiableAttributes()
- .stream())
- .collect(Collectors.toList());
-
- if (CollectionUtils.isEmpty(identifiableAttributes)) {
- String filterNames = variation.getFilters().stream().map(FilterInfos::getName).collect(Collectors.joining(", "));
- createReport(subReporter,
- "allFiltersWrong",
- String.format("All of the following variation's filters have equipments with wrong id : %s", filterNames),
- TypedValue.WARN_SEVERITY);
- } else {
- applyVariation(network, subReporter, identifiableAttributes, variation);
- }
- });
- createReport(subReporter, "scalingCreated", "new scaling created", TypedValue.INFO_SEVERITY);
}
private void applyVariation(Network network,
diff --git a/src/main/java/org/gridsuite/modification/server/modifications/BatteryModification.java b/src/main/java/org/gridsuite/modification/server/modifications/BatteryModification.java
index adc3276d1..be532862e 100644
--- a/src/main/java/org/gridsuite/modification/server/modifications/BatteryModification.java
+++ b/src/main/java/org/gridsuite/modification/server/modifications/BatteryModification.java
@@ -56,6 +56,20 @@ public void check(Network network) throws NetworkModificationException {
if (!CollectionUtils.isEmpty(points) && modificationPoints != null) {
ModificationUtils.getInstance().checkMaxQGreaterThanMinQ(batteryPoints, modificationPoints, MODIFY_BATTERY_ERROR, errorMessage);
}
+ checkActivePowerZeroOrBetweenMinAndMaxActivePowerBattery(modificationInfos, battery, MODIFY_BATTERY_ERROR, errorMessage);
+ }
+
+ private void checkActivePowerZeroOrBetweenMinAndMaxActivePowerBattery(BatteryModificationInfos modificationInfos, Battery battery, NetworkModificationException.Type exceptionType, String errorMessage) {
+ ModificationUtils.getInstance().checkActivePowerZeroOrBetweenMinAndMaxActivePower(
+ modificationInfos.getActivePowerSetpoint(),
+ modificationInfos.getMinActivePower(),
+ modificationInfos.getMaxActivePower(),
+ battery.getMinP(),
+ battery.getMaxP(),
+ battery.getTargetP(),
+ exceptionType,
+ errorMessage
+ );
}
@Override
diff --git a/src/main/java/org/gridsuite/modification/server/modifications/ByFormulaModification.java b/src/main/java/org/gridsuite/modification/server/modifications/ByFormulaModification.java
index 6e8a62a61..aaa5ed341 100644
--- a/src/main/java/org/gridsuite/modification/server/modifications/ByFormulaModification.java
+++ b/src/main/java/org/gridsuite/modification/server/modifications/ByFormulaModification.java
@@ -10,26 +10,16 @@
import com.powsybl.commons.reporter.Report;
import com.powsybl.commons.reporter.Reporter;
import com.powsybl.commons.reporter.TypedValue;
-import com.powsybl.iidm.network.Battery;
-import com.powsybl.iidm.network.Generator;
-import com.powsybl.iidm.network.Identifiable;
-import com.powsybl.iidm.network.Load;
-import com.powsybl.iidm.network.Network;
-import com.powsybl.iidm.network.ShuntCompensator;
-import com.powsybl.iidm.network.VoltageLevel;
+import com.powsybl.iidm.network.*;
import org.gridsuite.modification.server.NetworkModificationException;
import org.gridsuite.modification.server.dto.ByFormulaModificationInfos;
import org.gridsuite.modification.server.dto.FilterEquipments;
import org.gridsuite.modification.server.dto.FilterInfos;
import org.gridsuite.modification.server.dto.formula.FormulaInfos;
import org.gridsuite.modification.server.dto.formula.Operator;
-import org.gridsuite.modification.server.dto.formula.equipmentfield.BatteryField;
-import org.gridsuite.modification.server.dto.formula.equipmentfield.GeneratorField;
-import org.gridsuite.modification.server.dto.formula.equipmentfield.LoadField;
-import org.gridsuite.modification.server.dto.formula.equipmentfield.ShuntCompensatorField;
-import org.gridsuite.modification.server.dto.formula.equipmentfield.VoltageLevelField;
+import org.gridsuite.modification.server.dto.formula.equipmentfield.*;
import org.gridsuite.modification.server.service.FilterService;
-import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
@@ -44,9 +34,11 @@
public class ByFormulaModification extends AbstractModification {
private final ByFormulaModificationInfos modificationInfos;
protected FilterService filterService;
+ private int equipmentNotModifiedCount;
public ByFormulaModification(ByFormulaModificationInfos modificationInfos) {
this.modificationInfos = modificationInfos;
+ equipmentNotModifiedCount = 0;
}
@Override
@@ -77,25 +69,56 @@ public void apply(Network network, Reporter subReporter) {
.filter(distinctByKey(FilterInfos::getId))
.collect(Collectors.toMap(FilterInfos::getId, FilterInfos::getName));
- Map exportFilters = getUuidFilterEquipmentsMap(network, subReporter, filters);
+ Map exportFilters = ModificationUtils.getUuidFilterEquipmentsMap(filterService, network, subReporter, filters, modificationInfos.getErrorType());
if (exportFilters != null) {
+ long equipmentCount = exportFilters.values()
+ .stream()
+ .filter(filterEquipments -> !CollectionUtils.isEmpty(filterEquipments.getIdentifiableAttributes()))
+ .mapToLong(filterEquipments -> filterEquipments.getIdentifiableAttributes().size())
+ .sum();
+ long equipmentNotFoundCount = exportFilters.values()
+ .stream()
+ .filter(filterEquipments -> !CollectionUtils.isEmpty(filterEquipments.getNotFoundEquipments()))
+ .mapToLong(filterEquipments -> filterEquipments.getNotFoundEquipments().size())
+ .sum();
Reporter formulaSubReporter = subReporter.createSubReporter("appliedFormulasModifications", "Formulas");
List formulaReports = new ArrayList<>();
modificationInfos.getFormulaInfosList().forEach(formulaInfos ->
formulaInfos.getFilters().forEach(filterInfos ->
applyFormulaOnFilterEquipments(network, exportFilters, formulaReports, formulaInfos, filterInfos)));
- createReport(subReporter, "byFormulaModification", "new modification by formula", TypedValue.INFO_SEVERITY);
- formulaSubReporter.report(Report.builder()
- .withKey("appliedFormulasModifications")
- .withDefaultMessage(" Formulas")
- .withSeverity(TypedValue.INFO_SEVERITY)
- .build());
- formulaReports.forEach(formulaSubReporter::report);
+ createReport(subReporter, "byFormulaModification", "New modification by formula", TypedValue.INFO_SEVERITY);
+ if (equipmentNotModifiedCount == 0 && equipmentNotFoundCount == 0) {
+ createReport(subReporter, "byFormulaModificationALL",
+ String.format("All equipment have been modified : %s equipment(s)", equipmentCount),
+ TypedValue.INFO_SEVERITY);
+ report(formulaSubReporter, formulaReports);
+ } else {
+ if (equipmentNotModifiedCount == equipmentCount) {
+ createReport(subReporter, "byFormulaModificationNone",
+ "No equipment have been modified",
+ TypedValue.ERROR_SEVERITY);
+ } else {
+ createReport(subReporter, "byFormulaModificationSome",
+ String.format("Some of the equipment have been modified : %s equipment(s) modified and %s equipment(s) not modified",
+ equipmentCount - equipmentNotModifiedCount, equipmentNotModifiedCount + equipmentNotFoundCount),
+ TypedValue.WARN_SEVERITY);
+ report(formulaSubReporter, formulaReports);
+ }
+ }
}
}
+ private void report(Reporter formulaSubReporter, List formulaReports) {
+ formulaSubReporter.report(Report.builder()
+ .withKey("appliedFormulasModifications")
+ .withDefaultMessage(" Formulas")
+ .withSeverity(TypedValue.INFO_SEVERITY)
+ .build());
+ formulaReports.forEach(formulaSubReporter::report);
+ }
+
private void applyFormulaOnFilterEquipments(Network network,
Map exportFilters,
List formulaReports,
@@ -103,16 +126,70 @@ private void applyFormulaOnFilterEquipments(Network network,
FilterInfos filterInfos) {
FilterEquipments filterEquipments = exportFilters.get(filterInfos.getId());
- formulaReports.add(Report.builder()
- .withKey("byFormulaModificationFormulaFilter_" + formulaReports.size())
- .withDefaultMessage(String.format("Successful application of new modification by formula on filter %s",
- filterInfos.getName()))
- .withSeverity(TypedValue.INFO_SEVERITY)
- .build());
+ if (CollectionUtils.isEmpty(filterEquipments.getIdentifiableAttributes())) {
+ formulaReports.add(Report.builder()
+ .withKey("byFormulaModificationFormulaFilter_" + formulaReports.size())
+ .withDefaultMessage(String.format("No equipments were found for filter %s",
+ filterInfos.getName()))
+ .withSeverity(TypedValue.WARN_SEVERITY)
+ .build());
+ } else {
+ List notEditableEquipments = new ArrayList<>();
+ List equipmentsReport = new ArrayList<>();
+ filterEquipments.getIdentifiableAttributes()
+ .stream()
+ .map(attributes -> network.getIdentifiable(attributes.getId()))
+ .filter(identifiable -> {
+ boolean isEditableEquipment = isEquipmentEditable(identifiable, formulaInfos);
+ if (!isEditableEquipment) {
+ notEditableEquipments.add(identifiable.getId());
+ equipmentNotModifiedCount += 1;
+ }
+ return isEditableEquipment;
+ })
+ .forEach(identifiable -> applyFormula(identifiable, formulaInfos, equipmentsReport, notEditableEquipments));
+
+ createFormulaReports(formulaReports, formulaInfos, filterInfos, filterEquipments, notEditableEquipments);
+
+ formulaReports.addAll(equipmentsReport);
+ }
+ }
+
+ private void createFormulaReports(List formulaReports, FormulaInfos formulaInfos, FilterInfos filterInfos, FilterEquipments filterEquipments, List notEditableEquipments) {
+ if (notEditableEquipments.size() == filterEquipments.getIdentifiableAttributes().size()) {
+ formulaReports.add(Report.builder()
+ .withKey("byFormulaModificationFormulaFilterFailed_" + formulaReports.size())
+ .withDefaultMessage(String.format("No equipment(s) have been modified on filter %s",
+ filterInfos.getName()))
+ .withSeverity(TypedValue.WARN_SEVERITY)
+ .build());
+ } else {
+ formulaReports.add(Report.builder()
+ .withKey("byFormulaModificationFormulaFilter_" + formulaReports.size())
+ .withDefaultMessage(String.format("Successful application of new modification by formula on filter %s",
+ filterInfos.getName()))
+ .withSeverity(TypedValue.INFO_SEVERITY)
+ .build());
+
+ formulaReports.add(Report.builder()
+ .withKey("numberOfValidEquipment" + formulaReports.size())
+ .withDefaultMessage(String.format(" Number of equipment modified : %s",
+ filterEquipments.getIdentifiableAttributes().size() - notEditableEquipments.size()))
+ .withSeverity(TypedValue.INFO_SEVERITY)
+ .build());
+
+ if (!CollectionUtils.isEmpty(notEditableEquipments)) {
+ formulaReports.add(Report.builder()
+ .withKey("NotEditedEquipmentsFilter_" + formulaReports.size())
+ .withDefaultMessage(String.format(" The following equipment were not modified : %s", String.join(", ", notEditableEquipments)))
+ .withSeverity(TypedValue.WARN_SEVERITY)
+ .build());
+ }
+ }
formulaReports.add(Report.builder()
- .withKey("numberOfValidEquipment" + formulaReports.size())
- .withDefaultMessage(String.format(" Number of equipment modified : %s", filterEquipments.getIdentifiableAttributes().size()))
+ .withKey("editedFieldFilter_" + formulaReports.size())
+ .withDefaultMessage(String.format(" Edited field : %s", formulaInfos.getEditedField()))
.withSeverity(TypedValue.INFO_SEVERITY)
.build());
@@ -125,75 +202,86 @@ private void applyFormulaOnFilterEquipments(Network network,
.withSeverity(TypedValue.WARN_SEVERITY)
.build());
}
-
- formulaReports.add(Report.builder()
- .withKey("editedFieldFilter_" + formulaReports.size())
- .withDefaultMessage(String.format(" Edited field : %s", formulaInfos.getEditedField()))
- .withSeverity(TypedValue.INFO_SEVERITY)
- .build());
-
- filterEquipments.getIdentifiableAttributes().forEach(attributes -> applyFormula(network,
- attributes.getId(),
- formulaInfos,
- formulaReports));
}
- @Nullable
- private Map getUuidFilterEquipmentsMap(Network network, Reporter subReporter, Map filters) {
- // export filters from filter server
- Map exportFilters = filterService.getUuidFilterEquipmentsMap(network, filters);
+ private boolean isEquipmentEditable(Identifiable> identifiable,
+ FormulaInfos formulaInfos) {
+ if (formulaInfos.getEditedField() == null) {
+ return false;
+ }
- boolean isValidFilter = ModificationUtils.getInstance().isValidFilter(subReporter, modificationInfos.getErrorType(), exportFilters);
- return isValidFilter ? exportFilters : null;
+ if (identifiable.getType() == IdentifiableType.TWO_WINDINGS_TRANSFORMER) {
+ TwoWindingsTransformerField editedField = TwoWindingsTransformerField.valueOf(formulaInfos.getEditedField());
+ TwoWindingsTransformer twoWindingsTransformer = (TwoWindingsTransformer) identifiable;
+ return switch (editedField) {
+ case TARGET_V, RATIO_LOW_TAP_POSITION, RATIO_TAP_POSITION, RATIO_TARGET_DEADBAND -> twoWindingsTransformer.getRatioTapChanger() != null;
+ case REGULATION_VALUE, PHASE_LOW_TAP_POSITION, PHASE_TAP_POSITION, PHASE_TARGET_DEADBAND -> twoWindingsTransformer.getPhaseTapChanger() != null;
+ default -> true;
+ };
+ }
+ return true;
}
- private void applyFormula(Network network,
- String identifiableId,
+ private void applyFormula(Identifiable> identifiable,
FormulaInfos formulaInfos,
- List reports) {
- Identifiable> identifiable = network.getIdentifiable(identifiableId);
+ List reports,
+ List notEditableEquipments) {
Double value1 = formulaInfos.getFieldOrValue1().getRefOrValue(identifiable);
Double value2 = formulaInfos.getFieldOrValue2().getRefOrValue(identifiable);
- final Double newValue = applyOperation(formulaInfos.getOperator(), value1, value2);
- switch (identifiable.getType()) {
- case GENERATOR -> GeneratorField.setNewValue((Generator) identifiable, formulaInfos.getEditedField(), newValue);
- case BATTERY -> BatteryField.setNewValue((Battery) identifiable, formulaInfos.getEditedField(), newValue);
- case SHUNT_COMPENSATOR -> ShuntCompensatorField.setNewValue((ShuntCompensator) identifiable, formulaInfos.getEditedField(), newValue);
- case VOLTAGE_LEVEL -> VoltageLevelField.setNewValue((VoltageLevel) identifiable, formulaInfos.getEditedField(), newValue);
- case LOAD -> LoadField.setNewValue((Load) identifiable, formulaInfos.getEditedField(), newValue);
- default -> throw new NetworkModificationException(NetworkModificationException.Type.BY_FORMULA_MODIFICATION_ERROR, "Unsupported equipment");
- }
-
- reports.add(Report.builder()
- .withKey("EquipmentModifiedReport_" + reports.size())
- .withDefaultMessage(String.format(" %s id : %s, new value of %s : %s",
- modificationInfos.getIdentifiableType(),
- identifiable.getId(),
- formulaInfos.getEditedField(),
- newValue))
- .withSeverity(TypedValue.TRACE_SEVERITY)
- .build());
- }
-
- private Double applyOperation(Operator operator, Double value1, Double value2) {
- if (value1 == null ||
- value2 == null) {
- throw new NetworkModificationException(NetworkModificationException.Type.BY_FORMULA_MODIFICATION_ERROR, "at least one of the value or referenced field is null");
+ if (value1 == null || value2 == null) {
+ equipmentNotModifiedCount += 1;
+ notEditableEquipments.add(identifiable.getId());
+ reports.add(Report.builder()
+ .withKey("EquipmentModifiedReportError_" + reports.size())
+ .withDefaultMessage(String.format(" Cannot modify equipment %s : At least one of the value or referenced field is null",
+ identifiable.getId()))
+ .withSeverity(TypedValue.TRACE_SEVERITY)
+ .build());
+ } else if (value2 == 0 && formulaInfos.getOperator() == Operator.DIVISION) {
+ equipmentNotModifiedCount += 1;
+ notEditableEquipments.add(identifiable.getId());
} else {
- return switch (operator) {
- case ADDITION -> value1 + value2;
- case SUBTRACTION -> value1 - value2;
- case MULTIPLICATION -> value1 * value2;
- case DIVISION -> {
- if (value2 == 0) {
- throw new NetworkModificationException(NetworkModificationException.Type.BY_FORMULA_MODIFICATION_ERROR,
- "there is a division by zero in a formula");
- } else {
- yield value1 / value2;
- }
+ try {
+ final Double newValue = applyOperation(formulaInfos.getOperator(), value1, value2);
+ switch (identifiable.getType()) {
+ case GENERATOR -> GeneratorField.setNewValue((Generator) identifiable, formulaInfos.getEditedField(), newValue);
+ case BATTERY -> BatteryField.setNewValue((Battery) identifiable, formulaInfos.getEditedField(), newValue);
+ case SHUNT_COMPENSATOR -> ShuntCompensatorField.setNewValue((ShuntCompensator) identifiable, formulaInfos.getEditedField(), newValue);
+ case VOLTAGE_LEVEL -> VoltageLevelField.setNewValue((VoltageLevel) identifiable, formulaInfos.getEditedField(), newValue);
+ case LOAD -> LoadField.setNewValue((Load) identifiable, formulaInfos.getEditedField(), newValue);
+ case TWO_WINDINGS_TRANSFORMER -> TwoWindingsTransformerField.setNewValue((TwoWindingsTransformer) identifiable, formulaInfos.getEditedField(), newValue);
+ default -> throw new NetworkModificationException(NetworkModificationException.Type.BY_FORMULA_MODIFICATION_ERROR, "Unsupported equipment");
}
- case PERCENTAGE -> value1 * (value2 / 100);
- };
+ reports.add(Report.builder()
+ .withKey("EquipmentModifiedReport_" + reports.size())
+ .withDefaultMessage(String.format(" %s id : %s, new value of %s : %s",
+ modificationInfos.getIdentifiableType(),
+ identifiable.getId(),
+ formulaInfos.getEditedField(),
+ newValue))
+ .withSeverity(TypedValue.TRACE_SEVERITY)
+ .build());
+ } catch (Exception e) {
+ notEditableEquipments.add(identifiable.getId());
+ equipmentNotModifiedCount += 1;
+ reports.add(Report.builder()
+ .withKey("EquipmentModifiedReportExceptionf_" + reports.size())
+ .withDefaultMessage(String.format(" Cannot modify equipment %s : %s",
+ identifiable.getId(),
+ e.getMessage()))
+ .withSeverity(TypedValue.TRACE_SEVERITY)
+ .build());
+ }
}
}
+
+ private Double applyOperation(Operator operator, @NotNull Double value1, @NotNull Double value2) {
+ return switch (operator) {
+ case ADDITION -> value1 + value2;
+ case SUBTRACTION -> value1 - value2;
+ case MULTIPLICATION -> value1 * value2;
+ case DIVISION -> value1 / value2;
+ case PERCENTAGE -> value1 * (value2 / 100);
+ };
+ }
}
diff --git a/src/main/java/org/gridsuite/modification/server/modifications/GenerationDispatch.java b/src/main/java/org/gridsuite/modification/server/modifications/GenerationDispatch.java
index d563ad9fc..a835c3e2b 100644
--- a/src/main/java/org/gridsuite/modification/server/modifications/GenerationDispatch.java
+++ b/src/main/java/org/gridsuite/modification/server/modifications/GenerationDispatch.java
@@ -82,6 +82,14 @@ private static double computeTotalDemand(Component component, double lossCoeffic
return totalLoad * (1. + lossCoefficient / 100.);
}
+ private static double computeTotalActiveBatteryTargetP(Component component) {
+ Objects.requireNonNull(component);
+ return component.getBusStream().flatMap(Bus::getBatteryStream)
+ .filter(battery -> battery.getTerminal().isConnected())
+ .mapToDouble(Battery::getTargetP)
+ .sum();
+ }
+
private static double computeTotalAmountFixedSupply(Network network, Component component, List generatorsWithFixedSupply, Reporter reporter) {
double totalAmountFixedSupply = 0.;
List generatorsWithoutSetpointList = new ArrayList<>();
@@ -306,7 +314,7 @@ public void endReport(List adjustableGenerators) {
report(reporter, suffixKey, "TotalGeneratorSetTargetP", "The active power set points of ${nbUpdatedGenerator} generator${isPlural} have been updated as a result of generation dispatch",
Map.of("nbUpdatedGenerator", updatedGenerators.size(), IS_PLURAL, updatedGenerators.size() > 1 ? "s" : ""), TypedValue.INFO_SEVERITY);
updatedGenerators.forEach(g -> report(reporter, suffixKey, "GeneratorSetTargetP", "The active power set point of generator ${generator} has been set to ${newValue} MW",
- Map.of(GENERATOR, g.getId(), "newValue", g.getTargetP()), TypedValue.TRACE_SEVERITY));
+ Map.of(GENERATOR, g.getId(), "newValue", round(g.getTargetP())), TypedValue.TRACE_SEVERITY));
// report unchanged generators
int nbUnchangedGenerators = adjustableGenerators.size() - updatedGenerators.size();
@@ -493,26 +501,30 @@ public void apply(Network network, Reporter subReporter) {
// get total value of connected loads in the connected component
double totalDemand = computeTotalDemand(component, generationDispatchInfos.getLossCoefficient());
report(powerToDispatchReporter, Integer.toString(componentNum), "TotalDemand", "The total demand is : ${totalDemand} MW",
- Map.of("totalDemand", totalDemand), TypedValue.INFO_SEVERITY);
+ Map.of("totalDemand", round(totalDemand)), TypedValue.INFO_SEVERITY);
// get total supply value for generators with fixed supply
double totalAmountFixedSupply = computeTotalAmountFixedSupply(network, component, generatorsWithFixedSupply, powerToDispatchReporter);
report(powerToDispatchReporter, Integer.toString(componentNum), "TotalAmountFixedSupply", "The total amount of fixed supply is : ${totalAmountFixedSupply} MW",
- Map.of("totalAmountFixedSupply", totalAmountFixedSupply), TypedValue.INFO_SEVERITY);
+ Map.of("totalAmountFixedSupply", round(totalAmountFixedSupply)), TypedValue.INFO_SEVERITY);
// compute hvdc balance to other synchronous components
double hvdcBalance = computeHvdcBalance(component);
report(powerToDispatchReporter, Integer.toString(componentNum), "TotalOutwardHvdcFlow", "The HVDC balance is : ${hvdcBalance} MW",
- Map.of("hvdcBalance", hvdcBalance), TypedValue.INFO_SEVERITY);
+ Map.of("hvdcBalance", round(hvdcBalance)), TypedValue.INFO_SEVERITY);
- double totalAmountSupplyToBeDispatched = totalDemand - totalAmountFixedSupply - hvdcBalance;
+ double activeBatteryTotalTargetP = computeTotalActiveBatteryTargetP(component);
+ report(powerToDispatchReporter, Integer.toString(componentNum), "TotalActiveBatteryTargetP", "The battery balance is : ${batteryBalance} MW",
+ Map.of("batteryBalance", round(activeBatteryTotalTargetP)), TypedValue.INFO_SEVERITY);
+
+ double totalAmountSupplyToBeDispatched = totalDemand - totalAmountFixedSupply - hvdcBalance - activeBatteryTotalTargetP;
if (totalAmountSupplyToBeDispatched < 0.) {
report(powerToDispatchReporter, Integer.toString(componentNum), "TotalAmountFixedSupplyExceedsTotalDemand", "The total amount of fixed supply exceeds the total demand",
Map.of(), TypedValue.WARN_SEVERITY);
continue;
} else {
report(powerToDispatchReporter, Integer.toString(componentNum), "TotalAmountSupplyToBeDispatched", "The total amount of supply to be dispatched is : ${totalAmountSupplyToBeDispatched} MW",
- Map.of("totalAmountSupplyToBeDispatched", totalAmountSupplyToBeDispatched), TypedValue.INFO_SEVERITY);
+ Map.of("totalAmountSupplyToBeDispatched", round(totalAmountSupplyToBeDispatched)), TypedValue.INFO_SEVERITY);
}
// get adjustable generators in the component
@@ -548,12 +560,22 @@ public void apply(Network network, Reporter subReporter) {
report(resultReporter, Integer.toString(componentNum), "SupplyDemandBalanceCouldBeMet", "The supply-demand balance could be met",
Map.of(), TypedValue.INFO_SEVERITY);
- generatorsByRegion.forEach((region, generators) -> report(resultReporter, Integer.toString(componentNum), "SumGeneratorActivePower" + region, "Sum of generator active power setpoints in ${region} region: ${sum} MW.",
- Map.of("region", region, "sum", getSumActivePower(generators)), TypedValue.INFO_SEVERITY));
+ generatorsByRegion.forEach((region, generators) -> {
+ Map activePowerSumByEnergySource = getActivePowerSumByEnergySource(generators);
+ report(resultReporter, Integer.toString(componentNum), "SumGeneratorActivePower" + region, "Sum of generator active power setpoints in ${region} region: ${sum} MW (NUCLEAR: ${nuclearSum} MW, THERMAL: ${thermalSum} MW, HYDRO: ${hydroSum} MW, WIND AND SOLAR: ${windAndSolarSum} MW, OTHER: ${otherSum} MW).",
+ Map.of("region", region,
+ "sum", round(activePowerSumByEnergySource.values().stream().reduce(0d, Double::sum)),
+ "nuclearSum", round(activePowerSumByEnergySource.getOrDefault(EnergySource.NUCLEAR, 0d)),
+ "thermalSum", round(activePowerSumByEnergySource.getOrDefault(EnergySource.THERMAL, 0d)),
+ "hydroSum", round(activePowerSumByEnergySource.getOrDefault(EnergySource.HYDRO, 0d)),
+ "windAndSolarSum", round(activePowerSumByEnergySource.getOrDefault(EnergySource.WIND, 0d) + activePowerSumByEnergySource.getOrDefault(EnergySource.SOLAR, 0d)),
+ "otherSum", round(activePowerSumByEnergySource.getOrDefault(EnergySource.OTHER, 0d))
+ ), TypedValue.INFO_SEVERITY);
+ });
} else {
double remainingPowerImbalance = totalAmountSupplyToBeDispatched - realized;
report(resultReporter, Integer.toString(componentNum), "SupplyDemandBalanceCouldNotBeMet", "The supply-demand balance could not be met : the remaining power imbalance is ${remainingPower} MW",
- Map.of("remainingPower", remainingPowerImbalance), TypedValue.WARN_SEVERITY);
+ Map.of("remainingPower", round(remainingPowerImbalance)), TypedValue.WARN_SEVERITY);
}
}
}
@@ -602,8 +624,11 @@ private boolean hasCvgPropertyName(Set propertyNames) {
return propertyNames.stream().anyMatch(REGION_CVG::equals);
}
- private double getSumActivePower(List generators) {
- return generators.stream().mapToDouble(Generator::getTargetP).sum();
+ private Map getActivePowerSumByEnergySource(List generators) {
+ return generators.stream().collect(Collectors.toMap(Generator::getEnergySource, Generator::getTargetP, Double::sum));
}
+ private static double round(double value) {
+ return Math.round(value * 10) / 10.;
+ }
}
diff --git a/src/main/java/org/gridsuite/modification/server/modifications/GeneratorModification.java b/src/main/java/org/gridsuite/modification/server/modifications/GeneratorModification.java
index 25c95d89d..5be503c7a 100644
--- a/src/main/java/org/gridsuite/modification/server/modifications/GeneratorModification.java
+++ b/src/main/java/org/gridsuite/modification/server/modifications/GeneratorModification.java
@@ -67,9 +67,23 @@ public void check(Network network) throws NetworkModificationException {
modificationInfos.getRegulatingTerminalType().getValue(),
modificationInfos.getRegulatingTerminalVlId().getValue());
}
+ checkActivePowerZeroOrBetweenMinAndMaxActivePowerGenerator(modificationInfos, generator, MODIFY_GENERATOR_ERROR, errorMessage);
}
}
+ private void checkActivePowerZeroOrBetweenMinAndMaxActivePowerGenerator(GeneratorModificationInfos modificationInfos, Generator generator, NetworkModificationException.Type exceptionType, String errorMessage) {
+ ModificationUtils.getInstance().checkActivePowerZeroOrBetweenMinAndMaxActivePower(
+ modificationInfos.getActivePowerSetpoint(),
+ modificationInfos.getMinActivePower(),
+ modificationInfos.getMaxActivePower(),
+ generator.getMinP(),
+ generator.getMaxP(),
+ generator.getTargetP(),
+ exceptionType,
+ errorMessage
+ );
+ }
+
@Override
public void apply(Network network, Reporter subReporter) {
if (modificationInfos == null) {
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 bbc4f1f0b..f9de96006 100644
--- a/src/main/java/org/gridsuite/modification/server/modifications/ModificationUtils.java
+++ b/src/main/java/org/gridsuite/modification/server/modifications/ModificationUtils.java
@@ -19,6 +19,8 @@
import com.powsybl.iidm.network.extensions.IdentifiableShortCircuitAdder;
import org.gridsuite.modification.server.NetworkModificationException;
import org.gridsuite.modification.server.dto.*;
+import org.gridsuite.modification.server.service.FilterService;
+import org.jetbrains.annotations.Nullable;
import org.springframework.util.CollectionUtils;
import java.util.*;
@@ -27,6 +29,7 @@
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
+import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static org.gridsuite.modification.server.NetworkModificationException.Type.*;
@@ -780,6 +783,41 @@ public void modifyMinMaxReactiveLimits(MinMaxReactiveLimits minMaxReactiveLimits
reportModifications(subReporterReactiveLimits, reports, "minMaxReactiveLimitsModified", "By range");
}
+ private void modifyExistingActivePowerControl(ActivePowerControl> activePowerControl,
+ AttributeModification participateInfo,
+ AttributeModification droopInfo,
+ List reports) {
+ double oldDroop = activePowerControl.getDroop();
+ boolean oldParticipate = activePowerControl.isParticipate();
+
+ Optional.ofNullable(participateInfo).ifPresent(info -> {
+ activePowerControl.setParticipate(info.getValue());
+ reports.add(buildModificationReport(oldParticipate, info.getValue(), "Participate"));
+ });
+
+ Optional.ofNullable(droopInfo).ifPresent(info -> {
+ activePowerControl.setDroop(info.getValue());
+ reports.add(buildModificationReport(oldDroop, info.getValue(), "Droop"));
+ });
+ }
+
+ private void createNewActivePowerControl(ActivePowerControlAdder> adder,
+ AttributeModification participateInfo,
+ AttributeModification droopInfo,
+ List reports) {
+ boolean participate = participateInfo != null ? participateInfo.getValue() : false;
+ adder.withParticipate(participate);
+ if (participateInfo != null) {
+ reports.add(buildModificationReport(null, participate, "Participate"));
+ }
+ double droop = droopInfo != null ? droopInfo.getValue() : Double.NaN;
+ adder.withDroop(droop);
+ if (droopInfo != null) {
+ reports.add(buildModificationReport(Double.NaN, droop, "Droop"));
+ }
+ adder.add();
+ }
+
public Reporter modifyActivePowerControlAttributes(ActivePowerControl> activePowerControl,
ActivePowerControlAdder> activePowerControlAdder,
AttributeModification participateInfo,
@@ -787,37 +825,11 @@ public Reporter modifyActivePowerControlAttributes(ActivePowerControl> activeP
Reporter subReporter,
Reporter subReporterSetpoints) {
List reports = new ArrayList<>();
- double oldDroop = Double.NaN;
- boolean oldParticipate = false;
- double droop = droopInfo != null ? droopInfo.getValue() : Double.NaN;
if (activePowerControl != null) {
- oldDroop = activePowerControl.getDroop();
- oldParticipate = activePowerControl.isParticipate();
- }
-
- if (participateInfo != null) {
- activePowerControlAdder
- .withParticipate(participateInfo.getValue());
- reports.add(ModificationUtils.getInstance().buildModificationReport(activePowerControl != null ? activePowerControl.isParticipate() : null,
- participateInfo.getValue(),
- "Participate"));
- } else {
- activePowerControlAdder
- .withParticipate(oldParticipate);
- }
-
- if (droopInfo != null) {
- activePowerControlAdder
- .withDroop(droop);
- reports.add(ModificationUtils.getInstance().buildModificationReport(oldDroop,
- droop,
- "Droop"));
+ modifyExistingActivePowerControl(activePowerControl, participateInfo, droopInfo, reports);
} else {
- activePowerControlAdder
- .withDroop(oldDroop);
+ createNewActivePowerControl(activePowerControlAdder, participateInfo, droopInfo, reports);
}
- activePowerControlAdder
- .add();
Reporter subReporterSetpoints2 = subReporterSetpoints;
if (subReporterSetpoints == null && !reports.isEmpty()) {
@@ -862,6 +874,16 @@ public void checkMaxReactivePowerGreaterThanMinReactivePower(MinMaxReactiveLimit
}
}
+ public void checkActivePowerZeroOrBetweenMinAndMaxActivePower(AttributeModification activePowerInfos, AttributeModification minActivePowerInfos, AttributeModification maxActivePowerInfos, Double previousMinActivePower, Double previousMaxActivePower, Double previousActivePower, NetworkModificationException.Type exceptionType, String errorMessage) {
+ Double minActivePower = minActivePowerInfos != null ? minActivePowerInfos.getValue() : previousMinActivePower;
+ Double maxActivePower = maxActivePowerInfos != null ? maxActivePowerInfos.getValue() : previousMaxActivePower;
+ Double activePower = activePowerInfos != null ? activePowerInfos.getValue() : previousActivePower;
+
+ if (activePower != 0 && (activePower < minActivePower || activePower > maxActivePower)) {
+ throw new NetworkModificationException(exceptionType, errorMessage + "Active power " + activePower + " is expected to be equal to 0 or within the range of minimum active power and maximum active power: [" + minActivePower + ", " + maxActivePower + "]");
+ }
+ }
+
private NetworkModificationException makeEquipmentException(NetworkModificationException.Type errorType,
String equipmentId,
String equipmentName,
@@ -998,7 +1020,7 @@ public boolean isValidFilter(Reporter subReporter,
NetworkModificationException.Type errorType,
Map exportFilters) {
boolean noValidEquipmentId = exportFilters.values().stream()
- .allMatch(filterEquipments -> filterEquipments.getIdentifiableAttributes().isEmpty());
+ .allMatch(filterEquipments -> CollectionUtils.isEmpty(filterEquipments.getIdentifiableAttributes()));
if (noValidEquipmentId) {
String errorMsg = errorType + ": There is no valid equipment ID among the provided filter(s)";
@@ -1008,5 +1030,47 @@ public boolean isValidFilter(Reporter subReporter,
return true;
}
+
+ public static List getIdentifiableAttributes(Map exportFilters, Map filtersWithWrongEquipmentIds, List filterInfos, Reporter subReporter) {
+ filterInfos.stream()
+ .filter(f -> !exportFilters.containsKey(f.getId()))
+ .forEach(f -> createReport(subReporter,
+ "filterNotFound",
+ String.format("Cannot find the following filter: %s", f.getName()),
+ TypedValue.WARN_SEVERITY));
+
+ return filterInfos
+ .stream()
+ .filter(f -> !filtersWithWrongEquipmentIds.containsKey(f.getId()) && exportFilters.containsKey(f.getId()))
+ .flatMap(f -> exportFilters.get(f.getId())
+ .getIdentifiableAttributes()
+ .stream())
+ .toList();
+ }
+
+ @Nullable
+ public static Map getUuidFilterEquipmentsMap(FilterService filterService, Network network, Reporter subReporter, Map filters, NetworkModificationException.Type errorType) {
+ Map exportFilters = filterService.getUuidFilterEquipmentsMap(network, filters);
+
+ boolean isValidFilter = ModificationUtils.getInstance().isValidFilter(subReporter, errorType, exportFilters);
+ return isValidFilter ? exportFilters : null;
+ }
+
+ public static Map getUuidFilterWrongEquipmentsIdsMap(Reporter subReporter, Map exportFilters, Map filters) {
+ // collect all filters with wrong equipments ids
+ Map filterWithWrongEquipmentsIds = exportFilters.entrySet().stream()
+ .filter(e -> !CollectionUtils.isEmpty(e.getValue().getNotFoundEquipments()))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+
+ // create report for each wrong filter
+ filterWithWrongEquipmentsIds.values().forEach(f -> {
+ var equipmentIds = String.join(", ", f.getNotFoundEquipments());
+ createReport(subReporter,
+ "filterEquipmentsNotFound_" + f.getFilterName(),
+ String.format("Cannot find the following equipments %s in filter %s", equipmentIds, filters.get(f.getFilterId())),
+ TypedValue.WARN_SEVERITY);
+ });
+ return filterWithWrongEquipmentsIds;
+ }
}
diff --git a/src/main/java/org/gridsuite/modification/server/modifications/NetworkStoreListener.java b/src/main/java/org/gridsuite/modification/server/modifications/NetworkStoreListener.java
index 928cda21b..e25fdcf17 100644
--- a/src/main/java/org/gridsuite/modification/server/modifications/NetworkStoreListener.java
+++ b/src/main/java/org/gridsuite/modification/server/modifications/NetworkStoreListener.java
@@ -6,6 +6,7 @@
*/
package org.gridsuite.modification.server.modifications;
+import com.google.common.collect.Iterables;
import com.powsybl.iidm.network.*;
import com.powsybl.network.store.client.NetworkStoreService;
import lombok.Setter;
@@ -40,6 +41,8 @@ public class NetworkStoreListener implements NetworkListener {
private final List createdEquipments = new ArrayList<>();
+ private final List modifiedEquipments = new ArrayList<>();
+
private final Set networkImpacts = new LinkedHashSet<>();
// TODO : Move to the NetworkModificationApplicator class
@@ -92,18 +95,6 @@ public Network getNetwork() {
return network;
}
- @Override
- public void onUpdate(Identifiable identifiable, String attribute, Object oldValue, Object newValue) {
- networkImpacts.add(
- SimpleElementImpact.builder()
- .impactType(SimpleElementImpact.SimpleImpactType.MODIFICATION)
- .elementType(identifiable.getType())
- .elementId(identifiable.getId())
- .substationIds(getSubstationIds(identifiable))
- .build()
- );
- }
-
private void addSimpleModificationImpact(Identifiable> identifiable) {
networkImpacts.add(
SimpleElementImpact.builder()
@@ -130,9 +121,66 @@ public void onElementReplaced(Identifiable identifiable, String attribute, Objec
addSimpleModificationImpact(identifiable);
}
+ @Override
+ public void onUpdate(Identifiable identifiable, String attribute, Object oldValue, Object newValue) {
+ addSimpleModificationImpact(identifiable);
+ updateEquipmentIndexation(identifiable, attribute, networkUuid, network.getVariantManager().getWorkingVariantId());
+ }
+
@Override
public void onUpdate(Identifiable identifiable, String attribute, String variantId, Object oldValue, Object newValue) {
addSimpleModificationImpact(identifiable);
+ updateEquipmentIndexation(identifiable, attribute, networkUuid, network.getVariantManager().getWorkingVariantId());
+ }
+
+ private void updateEquipmentIndexation(Identifiable> identifiable, String attribute, UUID networkUuid, String variantId) {
+ modifiedEquipments.add(toEquipmentInfos(identifiable, networkUuid, variantId));
+
+ // because all each equipment carry its linked voltage levels/substations name within its document
+ // if attribute is "name" and identifiable type is VOLTAGE_LEVEL or SUBSTATION, we need to update all equipments linked to it
+ if (attribute.equals("name") && (identifiable.getType().equals(IdentifiableType.VOLTAGE_LEVEL) || identifiable.getType().equals(IdentifiableType.SUBSTATION))) {
+ updateLinkedEquipments(identifiable);
+ }
+ }
+
+ private void updateLinkedEquipments(Identifiable> identifiable) {
+ if (identifiable.getType().equals(IdentifiableType.VOLTAGE_LEVEL)) {
+ VoltageLevel updatedVoltageLevel = network.getVoltageLevel(identifiable.getId());
+ // update all equipments linked to voltageLevel
+ updateEquipmentsLinkedToVoltageLevel(updatedVoltageLevel);
+ // update substation linked to voltageLevel
+ Optional linkedSubstation = updatedVoltageLevel.getSubstation();
+ if (linkedSubstation.isPresent()) {
+ modifiedEquipments.add(toEquipmentInfos(linkedSubstation.get(), networkUuid, network.getVariantManager().getWorkingVariantId()));
+ }
+ } else if (identifiable.getType().equals(IdentifiableType.SUBSTATION)) {
+ Substation updatedSubstation = network.getSubstation(identifiable.getId());
+ updateEquipmentsLinkedToSubstation(updatedSubstation);
+ }
+ }
+
+ private void updateEquipmentsLinkedToSubstation(Substation substation) {
+ Iterable linkedVoltageLevels = substation.getVoltageLevels();
+ // update all voltageLevels linked to substation
+ linkedVoltageLevels.forEach(vl -> modifiedEquipments.add(toEquipmentInfos(vl, networkUuid, network.getVariantManager().getWorkingVariantId())));
+ // update all equipments linked to each of the voltageLevels
+ linkedVoltageLevels.forEach(vl ->
+ Iterables.concat(
+ vl.getConnectables(),
+ vl.getSwitches()
+ ).forEach(c ->
+ modifiedEquipments.add(toEquipmentInfos(c, networkUuid, network.getVariantManager().getWorkingVariantId()))
+ )
+ );
+ }
+
+ private void updateEquipmentsLinkedToVoltageLevel(VoltageLevel voltageLevel) {
+ Iterables.concat(
+ voltageLevel.getConnectables(),
+ voltageLevel.getSwitches()
+ ).forEach(c ->
+ modifiedEquipments.add(toEquipmentInfos(c, networkUuid, network.getVariantManager().getWorkingVariantId()))
+ );
}
@Override
@@ -192,6 +240,18 @@ public NetworkModificationResult flushNetworkModifications() {
.build();
}
+ private static EquipmentInfos toEquipmentInfos(Identifiable> identifiable, UUID networkUuid, String variantId) {
+ return EquipmentInfos.builder()
+ .networkUuid(networkUuid)
+ .variantId(variantId)
+ .id(identifiable.getId())
+ .name(identifiable.getNameOrId())
+ .type(identifiable.getType().name())
+ .voltageLevels(EquipmentInfos.getVoltageLevelsInfos(identifiable))
+ .substations(EquipmentInfos.getSubstationsInfos(identifiable))
+ .build();
+ }
+
private void flushEquipmentInfos() {
String variantId = network.getVariantManager().getWorkingVariantId();
Set presentEquipmentDeletionsIds = equipmentInfosService.findEquipmentInfosList(deletedEquipmentsIds, networkUuid, variantId).stream().map(EquipmentInfos::getId).collect(Collectors.toSet());
@@ -213,5 +273,6 @@ private void flushEquipmentInfos() {
equipmentInfosService.deleteEquipmentInfosList(equipmentDeletionsIds, networkUuid, variantId);
equipmentInfosService.addAllTombstonedEquipmentInfos(tombstonedEquipmentInfos);
equipmentInfosService.addAllEquipmentInfos(createdEquipments);
+ equipmentInfosService.addAllEquipmentInfos(modifiedEquipments);
}
}
diff --git a/src/main/java/org/gridsuite/modification/server/modifications/TabularModification.java b/src/main/java/org/gridsuite/modification/server/modifications/TabularModification.java
index 2296e8e14..b5f992747 100644
--- a/src/main/java/org/gridsuite/modification/server/modifications/TabularModification.java
+++ b/src/main/java/org/gridsuite/modification/server/modifications/TabularModification.java
@@ -66,6 +66,9 @@ public void apply(Network network, Reporter subReporter) {
case "LOAD_MODIFICATION":
defaultMessage = "loads" + defaultMessage;
break;
+ case "VOLTAGE_LEVEL_MODIFICATION":
+ defaultMessage = "voltage levels" + defaultMessage;
+ break;
default:
defaultMessage = "equipments of unknown type" + defaultMessage;
break;
diff --git a/src/main/java/org/gridsuite/modification/server/modifications/VoltageInitModification.java b/src/main/java/org/gridsuite/modification/server/modifications/VoltageInitModification.java
index 782ba1551..38a84d4f7 100644
--- a/src/main/java/org/gridsuite/modification/server/modifications/VoltageInitModification.java
+++ b/src/main/java/org/gridsuite/modification/server/modifications/VoltageInitModification.java
@@ -26,14 +26,18 @@
public class VoltageInitModification extends AbstractModification {
private final VoltageInitModificationInfos voltageInitModificationInfos;
- private static final String GENERATOR_KEY = "GeneratorModifications";
- private static final String GENERATOR_NAME = "Generator ${generatorId}";
- private static final String STATIC_VAR_COMPENSATOR_KEY = "StaticVarCompensatorModifications";
- private static final String STATIC_VAR_COMPENSATOR_NAME = "Static var compensator ${compensatorId}";
- private static final String VSC_CONVERTER_STATION_KEY = "VscConverterStationModifications";
- private static final String VSC_CONVERTER_STATION_NAME = "Vsc converter station ${converterId}";
- private static final String SHUNT_COMPENSATOR_KEY = "ShuntCompensatorModifications";
- private static final String SHUNT_COMPENSATOR_NAME = "Shunt compensator ${compensatorId}";
+ private static final String GENERATORS_KEY = "GeneratorsModifications";
+ private static final String GENERATORS_NAME = "Generators";
+ private static final String TWO_WINDINGS_TRANSFORMERS_KEY = "2WindingsTransformersModifications";
+ private static final String TWO_WINDINGS_TRANSFORMERS_NAME = "2 windings transformers";
+ private static final String THREE_WINDINGS_TRANSFORMERS_KEY = "3WindingsTransformersModifications";
+ private static final String THREE_WINDINGS_TRANSFORMERS_NAME = "3 windings transformers";
+ private static final String STATIC_VAR_COMPENSATORS_KEY = "StaticVarCompensatorsModifications";
+ private static final String STATIC_VAR_COMPENSATORS_NAME = "Static var compensators";
+ private static final String VSC_CONVERTER_STATIONS_KEY = "VscConverterStationsModifications";
+ private static final String VSC_CONVERTER_STATIONS_NAME = "Vsc converter stations";
+ private static final String SHUNT_COMPENSATORS_KEY = "ShuntCompensatorsModifications";
+ private static final String SHUNT_COMPENSATORS_NAME = "Shunt compensators";
private static final String VOLTAGE_SET_POINT = "Voltage set point";
private static final String REACTIVE_POWER_SET_POINT = "Reactive power set point";
@@ -66,43 +70,48 @@ public void apply(Network network, Reporter subReporter) {
private void applyGeneratorModification(Network network, Reporter subReporter) {
int modificationsCount = 0;
+ List reports = new ArrayList<>();
for (final VoltageInitGeneratorModificationInfos m : voltageInitModificationInfos.getGenerators()) {
final Generator generator = network.getGenerator(m.getGeneratorId());
if (generator == null) {
- Reporter reporter = subReporter.createSubReporter(GENERATOR_KEY, GENERATOR_NAME, "generatorId", m.getGeneratorId());
- reporter.report(Report.builder().withKey("generatorNotFound")
- .withDefaultMessage("Generator with id=${id} not found")
- .withValue("id", m.getGeneratorId())
- .withSeverity(TypedValue.WARN_SEVERITY).build());
+ reports.add(Report.builder().withKey("generatorNotFound")
+ .withDefaultMessage("Generator with id=${id} not found")
+ .withValue("id", m.getGeneratorId())
+ .withSeverity(TypedValue.WARN_SEVERITY).build());
} else if (m.getVoltageSetpoint() != null || m.getReactivePowerSetpoint() != null) {
modificationsCount++;
- Reporter reporter = subReporter.createSubReporter(GENERATOR_KEY, GENERATOR_NAME, "generatorId", m.getGeneratorId());
- reporter.report(Report.builder().withKey("generatorModification")
- .withDefaultMessage("Generator with id=${id} modified :")
- .withValue("id", m.getGeneratorId())
- .withSeverity(TypedValue.TRACE_SEVERITY).build());
+ reports.add(Report.builder().withKey("generatorModification")
+ .withDefaultMessage("Generator with id=${id} modified :")
+ .withValue("id", m.getGeneratorId())
+ .withSeverity(TypedValue.TRACE_SEVERITY).build());
if (m.getVoltageSetpoint() != null) {
final double oldTargetV = generator.getTargetV();
generator.setTargetV(m.getVoltageSetpoint());
- reporter.report(ModificationUtils.buildModificationReport(oldTargetV, m.getVoltageSetpoint(), VOLTAGE_SET_POINT, 1, TypedValue.TRACE_SEVERITY));
+ reports.add(ModificationUtils.buildModificationReport(oldTargetV, m.getVoltageSetpoint(), VOLTAGE_SET_POINT, 1, TypedValue.TRACE_SEVERITY));
}
if (m.getReactivePowerSetpoint() != null) {
final double oldTargetQ = generator.getTargetQ();
generator.setTargetQ(m.getReactivePowerSetpoint());
- reporter.report(ModificationUtils.buildModificationReport(oldTargetQ, m.getReactivePowerSetpoint(), REACTIVE_POWER_SET_POINT, 1, TypedValue.TRACE_SEVERITY));
+ reports.add(ModificationUtils.buildModificationReport(oldTargetQ, m.getReactivePowerSetpoint(), REACTIVE_POWER_SET_POINT, 1, TypedValue.TRACE_SEVERITY));
}
}
}
+ if (!reports.isEmpty()) {
+ Reporter generatorsReporter = subReporter.createSubReporter(GENERATORS_KEY, GENERATORS_NAME);
+ reports.forEach(generatorsReporter::report);
+ }
if (modificationsCount > 0) {
subReporter.report(new Report("generatorModificationsResume", "${count} generator(s) have been modified.", Map.of(
- "count", new TypedValue(modificationsCount, TypedValue.UNTYPED),
- Report.REPORT_SEVERITY_KEY, TypedValue.INFO_SEVERITY
+ "count", new TypedValue(modificationsCount, TypedValue.UNTYPED),
+ Report.REPORT_SEVERITY_KEY, TypedValue.INFO_SEVERITY
)));
}
}
private void applyTransformerModification(Network network, Reporter subReporter) {
int modificationsCount = 0;
+ List reports2WT = new ArrayList<>();
+ List reports3WT = new ArrayList<>();
for (final VoltageInitTransformerModificationInfos t : voltageInitModificationInfos.getTransformers()) {
if (t.getRatioTapChangerPosition() == null) {
continue;
@@ -110,197 +119,212 @@ private void applyTransformerModification(Network network, Reporter subReporter)
modificationsCount++;
if (t.getLegSide() != null) {
final ThreeWindingsTransformer threeWindingsTransformer = network.getThreeWindingsTransformer(t.getTransformerId());
- Reporter reporter = subReporter.createSubReporter("3WindingsTransformerModifications", "3 windings transformer ${transformerId}", "transformerId", t.getTransformerId());
if (threeWindingsTransformer == null) {
- reporter.report(Report.builder().withKey("3WindingsTransformerNotFound")
- .withDefaultMessage("3 windings transformer with id=${id} not found")
- .withValue("id", t.getTransformerId())
- .withSeverity(TypedValue.WARN_SEVERITY).build());
+ reports3WT.add(Report.builder().withKey("3WindingsTransformerNotFound")
+ .withDefaultMessage("3 windings transformer with id=${id} not found")
+ .withValue("id", t.getTransformerId())
+ .withSeverity(TypedValue.WARN_SEVERITY).build());
} else if (threeWindingsTransformer.getLeg(t.getLegSide()).getRatioTapChanger() == null) {
- reporter.report(Report.builder().withKey("3WindingsTransformerRatioTapChangerNotFound")
- .withDefaultMessage("3 windings transformer with id=${id} : Ratio tap changer for leg ${leg} not found")
- .withValue("id", t.getTransformerId())
- .withValue("leg", t.getLegSide().name())
- .withSeverity(TypedValue.WARN_SEVERITY).build());
+ reports3WT.add(Report.builder().withKey("3WindingsTransformerRatioTapChangerNotFound")
+ .withDefaultMessage("3 windings transformer with id=${id} : Ratio tap changer for leg ${leg} not found")
+ .withValue("id", t.getTransformerId())
+ .withValue("leg", t.getLegSide().name())
+ .withSeverity(TypedValue.WARN_SEVERITY).build());
} else {
- reporter.report(Report.builder().withKey("3WindingsTransformerModification")
- .withDefaultMessage("3 windings transformer with id=${id} modified :")
- .withValue("id", t.getTransformerId())
- .withSeverity(TypedValue.TRACE_SEVERITY).build());
+ reports3WT.add(Report.builder().withKey("3WindingsTransformerModification")
+ .withDefaultMessage("3 windings transformer with id=${id} modified :")
+ .withValue("id", t.getTransformerId())
+ .withSeverity(TypedValue.TRACE_SEVERITY).build());
final int oldTapPosition = threeWindingsTransformer.getLeg(t.getLegSide()).getRatioTapChanger().getTapPosition();
threeWindingsTransformer.getLeg(t.getLegSide()).getRatioTapChanger().setTapPosition(t.getRatioTapChangerPosition());
- reporter.report(ModificationUtils.buildModificationReport(oldTapPosition, t.getRatioTapChangerPosition(), "Leg " + t.getLegSide().name() + " ratio tap changer position", 1, TypedValue.TRACE_SEVERITY));
+ reports3WT.add(ModificationUtils.buildModificationReport(oldTapPosition, t.getRatioTapChangerPosition(), "Leg " + t.getLegSide().name() + " ratio tap changer position", 1, TypedValue.TRACE_SEVERITY));
}
} else {
final TwoWindingsTransformer twoWindingsTransformer = network.getTwoWindingsTransformer(t.getTransformerId());
- Reporter reporter = subReporter.createSubReporter("2WindingsTransformerModifications", "2 windings transformer ${transformerId}", "transformerId", t.getTransformerId());
if (twoWindingsTransformer == null) {
- reporter.report(Report.builder().withKey("2WindingsTransformerNotFound")
- .withDefaultMessage("2 windings transformer with id=${id} not found")
- .withValue("id", t.getTransformerId())
- .withSeverity(TypedValue.WARN_SEVERITY).build());
+ reports2WT.add(Report.builder().withKey("2WindingsTransformerNotFound")
+ .withDefaultMessage("2 windings transformer with id=${id} not found")
+ .withValue("id", t.getTransformerId())
+ .withSeverity(TypedValue.WARN_SEVERITY).build());
} else if (twoWindingsTransformer.getRatioTapChanger() == null) {
- reporter.report(Report.builder().withKey("2WindingsTransformerRatioTapChangerNotFound")
- .withDefaultMessage("2 windings transformer with id=${id} : Ratio tap changer not found")
- .withValue("id", t.getTransformerId())
- .withSeverity(TypedValue.WARN_SEVERITY).build());
+ reports2WT.add(Report.builder().withKey("2WindingsTransformerRatioTapChangerNotFound")
+ .withDefaultMessage("2 windings transformer with id=${id} : Ratio tap changer not found")
+ .withValue("id", t.getTransformerId())
+ .withSeverity(TypedValue.WARN_SEVERITY).build());
} else {
- reporter.report(Report.builder().withKey("2WindingsTransformerModification")
- .withDefaultMessage("2 windings transformer with id=${id} modified :")
- .withValue("id", t.getTransformerId())
- .withSeverity(TypedValue.TRACE_SEVERITY).build());
+ reports2WT.add(Report.builder().withKey("2WindingsTransformerModification")
+ .withDefaultMessage("2 windings transformer with id=${id} modified :")
+ .withValue("id", t.getTransformerId())
+ .withSeverity(TypedValue.TRACE_SEVERITY).build());
final int oldTapPosition = twoWindingsTransformer.getRatioTapChanger().getTapPosition();
twoWindingsTransformer.getRatioTapChanger().setTapPosition(t.getRatioTapChangerPosition());
- reporter.report(ModificationUtils.buildModificationReport(oldTapPosition, t.getRatioTapChangerPosition(), "Ratio tap changer position", 1, TypedValue.TRACE_SEVERITY));
+ reports2WT.add(ModificationUtils.buildModificationReport(oldTapPosition, t.getRatioTapChangerPosition(), "Ratio tap changer position", 1, TypedValue.TRACE_SEVERITY));
}
}
}
+ if (!reports2WT.isEmpty()) {
+ Reporter twoWindingsTransformerReporter = subReporter.createSubReporter(TWO_WINDINGS_TRANSFORMERS_KEY, TWO_WINDINGS_TRANSFORMERS_NAME);
+ reports2WT.forEach(twoWindingsTransformerReporter::report);
+ }
+ if (!reports3WT.isEmpty()) {
+ Reporter threeWindingsTransformerReporter = subReporter.createSubReporter(THREE_WINDINGS_TRANSFORMERS_KEY, THREE_WINDINGS_TRANSFORMERS_NAME);
+ reports3WT.forEach(threeWindingsTransformerReporter::report);
+ }
if (modificationsCount > 0) {
subReporter.report(new Report("windingsTransformerModificationsResume", "${count} transformer(s) have been modified.", Map.of(
- "count", new TypedValue(modificationsCount, TypedValue.UNTYPED),
- Report.REPORT_SEVERITY_KEY, TypedValue.INFO_SEVERITY
+ "count", new TypedValue(modificationsCount, TypedValue.UNTYPED),
+ Report.REPORT_SEVERITY_KEY, TypedValue.INFO_SEVERITY
)));
}
}
private void applyStaticVarCompensatorModification(Network network, Reporter subReporter) {
int modificationsCount = 0;
+ List reports = new ArrayList<>();
for (VoltageInitStaticVarCompensatorModificationInfos s : voltageInitModificationInfos.getStaticVarCompensators()) {
final StaticVarCompensator staticVarCompensator = network.getStaticVarCompensator(s.getStaticVarCompensatorId());
if (staticVarCompensator == null) {
- Reporter reporter = subReporter.createSubReporter(STATIC_VAR_COMPENSATOR_KEY, STATIC_VAR_COMPENSATOR_NAME, "compensatorId", s.getStaticVarCompensatorId());
- reporter.report(Report.builder().withKey("staticVarCompensatorNotFound")
- .withDefaultMessage("Static var compensator with id=${id} not found")
- .withValue("id", s.getStaticVarCompensatorId())
- .withSeverity(TypedValue.WARN_SEVERITY).build());
+ reports.add(Report.builder().withKey("staticVarCompensatorNotFound")
+ .withDefaultMessage("Static var compensator with id=${id} not found")
+ .withValue("id", s.getStaticVarCompensatorId())
+ .withSeverity(TypedValue.WARN_SEVERITY).build());
} else if (s.getVoltageSetpoint() != null || s.getReactivePowerSetpoint() != null) {
modificationsCount++;
- Reporter reporter = subReporter.createSubReporter(STATIC_VAR_COMPENSATOR_KEY, STATIC_VAR_COMPENSATOR_NAME, "compensatorId", s.getStaticVarCompensatorId());
- reporter.report(Report.builder().withKey("staticVarCompensatorModification")
- .withDefaultMessage("Static var compensator with id=${id} modified :")
- .withValue("id", s.getStaticVarCompensatorId())
- .withSeverity(TypedValue.TRACE_SEVERITY).build());
+ reports.add(Report.builder().withKey("staticVarCompensatorModification")
+ .withDefaultMessage("Static var compensator with id=${id} modified :")
+ .withValue("id", s.getStaticVarCompensatorId())
+ .withSeverity(TypedValue.TRACE_SEVERITY).build());
if (s.getVoltageSetpoint() != null) {
final double oldTargetV = staticVarCompensator.getVoltageSetpoint();
staticVarCompensator.setVoltageSetpoint(s.getVoltageSetpoint());
- reporter.report(ModificationUtils.buildModificationReport(oldTargetV, s.getVoltageSetpoint(), VOLTAGE_SET_POINT, 1, TypedValue.TRACE_SEVERITY));
+ reports.add(ModificationUtils.buildModificationReport(oldTargetV, s.getVoltageSetpoint(), VOLTAGE_SET_POINT, 1, TypedValue.TRACE_SEVERITY));
}
if (s.getReactivePowerSetpoint() != null) {
final double oldTargetQ = staticVarCompensator.getReactivePowerSetpoint();
staticVarCompensator.setReactivePowerSetpoint(s.getReactivePowerSetpoint());
- reporter.report(ModificationUtils.buildModificationReport(oldTargetQ, s.getReactivePowerSetpoint(), REACTIVE_POWER_SET_POINT, 1, TypedValue.TRACE_SEVERITY));
+ reports.add(ModificationUtils.buildModificationReport(oldTargetQ, s.getReactivePowerSetpoint(), REACTIVE_POWER_SET_POINT, 1, TypedValue.TRACE_SEVERITY));
}
}
}
+ if (!reports.isEmpty()) {
+ Reporter staticVarsReporter = subReporter.createSubReporter(STATIC_VAR_COMPENSATORS_KEY, STATIC_VAR_COMPENSATORS_NAME);
+ reports.forEach(staticVarsReporter::report);
+ }
if (modificationsCount > 0) {
subReporter.report(new Report("svcModificationsResume", "${count} static var compensator(s) have been modified.", Map.of(
- "count", new TypedValue(modificationsCount, TypedValue.UNTYPED),
- Report.REPORT_SEVERITY_KEY, TypedValue.INFO_SEVERITY
+ "count", new TypedValue(modificationsCount, TypedValue.UNTYPED),
+ Report.REPORT_SEVERITY_KEY, TypedValue.INFO_SEVERITY
)));
}
}
private void applyVscConverterStationModification(Network network, Reporter subReporter) {
int modificationsCount = 0;
+ List reports = new ArrayList<>();
for (VoltageInitVscConverterStationModificationInfos v : voltageInitModificationInfos.getVscConverterStations()) {
final VscConverterStation vscConverterStation = network.getVscConverterStation(v.getVscConverterStationId());
if (vscConverterStation == null) {
- Reporter reporter = subReporter.createSubReporter(VSC_CONVERTER_STATION_KEY, VSC_CONVERTER_STATION_NAME, "converterId", v.getVscConverterStationId());
- reporter.report(Report.builder().withKey("vscConverterStationNotFound")
- .withDefaultMessage("Vsc converter station with id=${id} not found")
- .withValue("id", v.getVscConverterStationId())
- .withSeverity(TypedValue.WARN_SEVERITY).build());
+ reports.add(Report.builder().withKey("vscConverterStationNotFound")
+ .withDefaultMessage("Vsc converter station with id=${id} not found")
+ .withValue("id", v.getVscConverterStationId())
+ .withSeverity(TypedValue.WARN_SEVERITY).build());
} else if (v.getVoltageSetpoint() != null || v.getReactivePowerSetpoint() != null) {
modificationsCount++;
- Reporter reporter = subReporter.createSubReporter(VSC_CONVERTER_STATION_KEY, VSC_CONVERTER_STATION_NAME, "converterId", v.getVscConverterStationId());
- reporter.report(Report.builder().withKey("vscConverterStationModification")
- .withDefaultMessage("Vsc converter station with id=${id} modified :")
- .withValue("id", v.getVscConverterStationId())
- .withSeverity(TypedValue.TRACE_SEVERITY).build());
+ reports.add(Report.builder().withKey("vscConverterStationModification")
+ .withDefaultMessage("Vsc converter station with id=${id} modified :")
+ .withValue("id", v.getVscConverterStationId())
+ .withSeverity(TypedValue.TRACE_SEVERITY).build());
if (v.getVoltageSetpoint() != null) {
final double oldTargetV = vscConverterStation.getVoltageSetpoint();
vscConverterStation.setVoltageSetpoint(v.getVoltageSetpoint());
- reporter.report(ModificationUtils.buildModificationReport(oldTargetV, v.getVoltageSetpoint(), VOLTAGE_SET_POINT, 1, TypedValue.TRACE_SEVERITY));
+ reports.add(ModificationUtils.buildModificationReport(oldTargetV, v.getVoltageSetpoint(), VOLTAGE_SET_POINT, 1, TypedValue.TRACE_SEVERITY));
}
if (v.getReactivePowerSetpoint() != null) {
final double oldTargetQ = vscConverterStation.getReactivePowerSetpoint();
vscConverterStation.setReactivePowerSetpoint(v.getReactivePowerSetpoint());
- reporter.report(ModificationUtils.buildModificationReport(oldTargetQ, v.getReactivePowerSetpoint(), REACTIVE_POWER_SET_POINT, 1, TypedValue.TRACE_SEVERITY));
+ reports.add(ModificationUtils.buildModificationReport(oldTargetQ, v.getReactivePowerSetpoint(), REACTIVE_POWER_SET_POINT, 1, TypedValue.TRACE_SEVERITY));
}
}
}
+ if (!reports.isEmpty()) {
+ Reporter vscConverterStationsReporter = subReporter.createSubReporter(VSC_CONVERTER_STATIONS_KEY, VSC_CONVERTER_STATIONS_NAME);
+ reports.forEach(vscConverterStationsReporter::report);
+ }
if (modificationsCount > 0) {
subReporter.report(new Report("vscModificationsResume", "${count} vsc converter station(s) have been modified.", Map.of(
- "count", new TypedValue(modificationsCount, TypedValue.UNTYPED),
- Report.REPORT_SEVERITY_KEY, TypedValue.INFO_SEVERITY
+ "count", new TypedValue(modificationsCount, TypedValue.UNTYPED),
+ Report.REPORT_SEVERITY_KEY, TypedValue.INFO_SEVERITY
)));
}
}
private void applyShuntCompensatorModification(Network network, Reporter subReporter) {
int modificationsCount = 0;
+ List reports = new ArrayList<>();
for (VoltageInitShuntCompensatorModificationInfos m : voltageInitModificationInfos.getShuntCompensators()) {
final ShuntCompensator shuntCompensator = network.getShuntCompensator(m.getShuntCompensatorId());
if (shuntCompensator == null) {
- Reporter reporter = subReporter.createSubReporter(SHUNT_COMPENSATOR_KEY, SHUNT_COMPENSATOR_NAME, "compensatorId", m.getShuntCompensatorId());
- reporter.report(Report.builder().withKey("shuntCompensatorNotFound")
- .withDefaultMessage("Shunt compensator with id=${id} not found")
- .withValue("id", m.getShuntCompensatorId())
- .withSeverity(TypedValue.WARN_SEVERITY).build());
+ reports.add(Report.builder().withKey("shuntCompensatorNotFound")
+ .withDefaultMessage("Shunt compensator with id=${id} not found")
+ .withValue("id", m.getShuntCompensatorId())
+ .withSeverity(TypedValue.WARN_SEVERITY).build());
} else if (m.getSectionCount() != null || m.getConnect() != null) {
- List reports = new ArrayList<>();
+ List reportsShunt = new ArrayList<>();
final int currentSectionCount = shuntCompensator.getSectionCount();
final Terminal shuntCompensatorTerminal = shuntCompensator.getTerminal();
if (shuntCompensatorTerminal.isConnected()) { // shunt compensator is connected
if (m.getSectionCount() == null) {
- reports.add(Report.builder().withKey("shuntCompensatorSectionCountUndefined")
- .withDefaultMessage("\tSection count value is undefined")
- .withSeverity(TypedValue.WARN_SEVERITY).build());
+ reportsShunt.add(Report.builder().withKey("shuntCompensatorSectionCountUndefined")
+ .withDefaultMessage("\tSection count value is undefined")
+ .withSeverity(TypedValue.WARN_SEVERITY).build());
} else {
if (m.getSectionCount() == 0) {
shuntCompensatorTerminal.disconnect();
- reports.add(Report.builder().withKey("shuntCompensatorDisconnected")
- .withDefaultMessage("\tShunt compensator disconnected")
- .withSeverity(TypedValue.TRACE_SEVERITY).build());
+ reportsShunt.add(Report.builder().withKey("shuntCompensatorDisconnected")
+ .withDefaultMessage("\tShunt compensator disconnected")
+ .withSeverity(TypedValue.TRACE_SEVERITY).build());
}
if (m.getSectionCount() != currentSectionCount) {
shuntCompensator.setSectionCount(m.getSectionCount());
- reports.add(ModificationUtils.buildModificationReport(currentSectionCount, m.getSectionCount(), SECTION_COUNT, 1, TypedValue.TRACE_SEVERITY));
+ reportsShunt.add(ModificationUtils.buildModificationReport(currentSectionCount, m.getSectionCount(), SECTION_COUNT, 1, TypedValue.TRACE_SEVERITY));
}
}
} else { // shunt compensator is disconnected
if (m.getConnect() == null) {
- reports.add(Report.builder().withKey("shuntCompensatorConnectUndefined")
- .withDefaultMessage("\tConnect value is undefined")
- .withSeverity(TypedValue.WARN_SEVERITY).build());
+ reportsShunt.add(Report.builder().withKey("shuntCompensatorConnectUndefined")
+ .withDefaultMessage("\tConnect value is undefined")
+ .withSeverity(TypedValue.WARN_SEVERITY).build());
} else {
if (Boolean.TRUE.equals(m.getConnect())) {
shuntCompensatorTerminal.connect();
- reports.add(Report.builder().withKey("shuntCompensatorReconnected")
- .withDefaultMessage("\tShunt compensator reconnected")
- .withSeverity(TypedValue.TRACE_SEVERITY).build());
+ reportsShunt.add(Report.builder().withKey("shuntCompensatorReconnected")
+ .withDefaultMessage("\tShunt compensator reconnected")
+ .withSeverity(TypedValue.TRACE_SEVERITY).build());
}
if (m.getSectionCount() != currentSectionCount) {
shuntCompensator.setSectionCount(m.getSectionCount());
- reports.add(ModificationUtils.buildModificationReport(currentSectionCount, m.getSectionCount(), SECTION_COUNT, 1, TypedValue.TRACE_SEVERITY));
+ reportsShunt.add(ModificationUtils.buildModificationReport(currentSectionCount, m.getSectionCount(), SECTION_COUNT, 1, TypedValue.TRACE_SEVERITY));
}
}
}
- if (!reports.isEmpty()) {
+ if (!reportsShunt.isEmpty()) {
modificationsCount++;
- Reporter reporter = subReporter.createSubReporter(SHUNT_COMPENSATOR_KEY, SHUNT_COMPENSATOR_NAME, "compensatorId", m.getShuntCompensatorId());
- reporter.report(Report.builder().withKey("shuntCompensatorModification")
- .withDefaultMessage("Shunt compensator with id=${id} modified :")
- .withValue("id", m.getShuntCompensatorId())
- .withSeverity(TypedValue.TRACE_SEVERITY).build());
- reports.forEach(reporter::report);
+ reports.add(Report.builder().withKey("shuntCompensatorModification")
+ .withDefaultMessage("Shunt compensator with id=${id} modified :")
+ .withValue("id", m.getShuntCompensatorId())
+ .withSeverity(TypedValue.TRACE_SEVERITY).build());
+ reportsShunt.forEach(reports::add);
}
}
}
+ if (!reports.isEmpty()) {
+ Reporter shuntCompensatorsReporter = subReporter.createSubReporter(SHUNT_COMPENSATORS_KEY, SHUNT_COMPENSATORS_NAME);
+ reports.forEach(shuntCompensatorsReporter::report);
+ }
if (modificationsCount > 0) {
subReporter.report(new Report("shuntCompensatorModificationsResume", "${count} shunt compensator(s) have been modified.", Map.of(
- "count", new TypedValue(modificationsCount, TypedValue.UNTYPED),
- Report.REPORT_SEVERITY_KEY, TypedValue.INFO_SEVERITY
+ "count", new TypedValue(modificationsCount, TypedValue.UNTYPED),
+ Report.REPORT_SEVERITY_KEY, TypedValue.INFO_SEVERITY
)));
}
}
diff --git a/src/test/java/org/gridsuite/modification/server/modifications/AbstractByFormulaModificationTest.java b/src/test/java/org/gridsuite/modification/server/modifications/AbstractByFormulaModificationTest.java
index 81c010149..e08660a8b 100644
--- a/src/test/java/org/gridsuite/modification/server/modifications/AbstractByFormulaModificationTest.java
+++ b/src/test/java/org/gridsuite/modification/server/modifications/AbstractByFormulaModificationTest.java
@@ -70,6 +70,23 @@ public void specificSetUp() {
createEquipments();
}
+ @Test
+ public void testByModificationError() throws Exception {
+ // Test with empty list of formulas
+ checkCreationApplicationStatus(ByFormulaModificationInfos.builder().identifiableType(getIdentifiableType()).formulaInfosList(List.of()).build(),
+ NetworkModificationResult.ApplicationStatus.WITH_ERRORS);
+
+ // Test with empty list of filters in formula
+ FormulaInfos formulaInfos = FormulaInfos.builder()
+ .fieldOrValue1(ReferenceFieldOrValue.builder().value(50.).build())
+ .fieldOrValue2(ReferenceFieldOrValue.builder().value(50.).build())
+ .operator(Operator.ADDITION)
+ .filters(List.of())
+ .build();
+ checkCreationApplicationStatus(ByFormulaModificationInfos.builder().identifiableType(getIdentifiableType()).formulaInfosList(List.of(formulaInfos)).build(),
+ NetworkModificationResult.ApplicationStatus.WITH_ERRORS);
+ }
+
protected void checkCreateWithWarning(List formulaInfos, List existingEquipmentList) throws Exception {
FilterEquipments filter = getFilterEquipments(FILTER_WITH_ONE_WRONG_ID, "filterWithWrongId", existingEquipmentList, List.of("wrongId"));
@@ -135,7 +152,7 @@ public void testCopy() throws Exception {
wireMockUtils.verifyGetRequest(stubId, PATH, handleQueryParams(getNetworkUuid(), filters.stream().map(FilterEquipments::getFilterId).collect(Collectors.toList())), false);
}
- private void checkCreationApplicationStatus(ByFormulaModificationInfos byFormulaModificationInfos,
+ protected void checkCreationApplicationStatus(ByFormulaModificationInfos byFormulaModificationInfos,
NetworkModificationResult.ApplicationStatus applicationStatus) throws Exception {
String modificationToCreateJson = mapper.writeValueAsString(byFormulaModificationInfos);
@@ -201,11 +218,11 @@ protected FormulaInfos getFormulaInfo(String editedField,
.build();
}
- private Map handleQueryParams(UUID networkUuid, List filterIds) {
+ Map handleQueryParams(UUID networkUuid, List filterIds) {
return Map.of("networkUuid", WireMock.equalTo(String.valueOf(networkUuid)), "variantId", WireMock.equalTo("variant_1"), "ids", WireMock.matching(filterIds.stream().map(uuid -> ".+").collect(Collectors.joining(","))));
}
- private String getPath(UUID networkUuid, boolean isRegexPhat) {
+ String getPath(UUID networkUuid, boolean isRegexPhat) {
if (isRegexPhat) {
return "/v1/filters/export\\?networkUuid=" + networkUuid + "\\&variantId=variant_1\\&ids=";
}
diff --git a/src/test/java/org/gridsuite/modification/server/modifications/BatteryModificationTest.java b/src/test/java/org/gridsuite/modification/server/modifications/BatteryModificationTest.java
index d1319ea0f..8c9b2dea9 100644
--- a/src/test/java/org/gridsuite/modification/server/modifications/BatteryModificationTest.java
+++ b/src/test/java/org/gridsuite/modification/server/modifications/BatteryModificationTest.java
@@ -16,6 +16,7 @@
import org.junit.Test;
import org.junit.jupiter.api.Tag;
import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MvcResult;
import org.springframework.util.CollectionUtils;
import java.util.*;
@@ -217,6 +218,61 @@ public void testDroopUnchanged() throws Exception {
assertEquals(18f, createdModification.getDroop().getValue());
}
+ @Test
+ public void testImpactsAfterActivePowerControlModifications() throws Exception {
+ BatteryModificationInfos batteryModificationInfos = (BatteryModificationInfos) buildModification();
+ String modificationToCreateJson = mapper.writeValueAsString(batteryModificationInfos);
+ mockMvc.perform(post(getNetworkModificationUri()).content(modificationToCreateJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk()).andReturn();
+ Battery battery = getNetwork().getBattery("v3Battery");
+ assertEquals(0.1f, battery.getExtension(ActivePowerControl.class).getDroop());
+ assertEquals(true, battery.getExtension(ActivePowerControl.class).isParticipate());
+ //modify only droop
+ batteryModificationInfos.setDroop(new AttributeModification<>(0.5f, OperationType.SET));
+ modificationToCreateJson = mapper.writeValueAsString(batteryModificationInfos);
+ MvcResult mvcResult = mockMvc.perform(post(getNetworkModificationUri()).content(modificationToCreateJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk()).andReturn();
+ //check impacts
+ String resultAsString = mvcResult.getResponse().getContentAsString();
+ NetworkModificationResult networkModificationResult = mapper.readValue(resultAsString, NetworkModificationResult.class);
+ assertEquals(1, networkModificationResult.getNetworkImpacts().size());
+ assertEquals(1, networkModificationResult.getImpactedSubstationsIds().size());
+ assertEquals("[s2]", networkModificationResult.getImpactedSubstationsIds().toString());
+ //modify only participate
+ batteryModificationInfos.setParticipate(new AttributeModification<>(false, OperationType.SET));
+ modificationToCreateJson = mapper.writeValueAsString(batteryModificationInfos);
+ mvcResult = mockMvc.perform(post(getNetworkModificationUri()).content(modificationToCreateJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk()).andReturn();
+ //check impacts
+ resultAsString = mvcResult.getResponse().getContentAsString();
+ networkModificationResult = mapper.readValue(resultAsString, NetworkModificationResult.class);
+ assertEquals(1, networkModificationResult.getNetworkImpacts().size());
+ assertEquals(1, networkModificationResult.getImpactedSubstationsIds().size());
+ assertEquals("[s2]", networkModificationResult.getImpactedSubstationsIds().toString());
+
+ }
+
+ @Test
+ public void testActivePowerZeroOrBetweenMinAndMaxActivePower() throws Exception {
+ BatteryModificationInfos batteryModificationInfos = (BatteryModificationInfos) buildModification();
+ Battery battery = getNetwork().getBattery("v3Battery");
+ battery.setTargetP(80.)
+ .setMinP(0.)
+ .setMaxP(100.);
+ batteryModificationInfos.setActivePowerSetpoint(new AttributeModification<>(155.0, OperationType.SET));
+
+ Double minActivePower = batteryModificationInfos.getMinActivePower() != null ? batteryModificationInfos.getMinActivePower().getValue() : battery.getMinP();
+ Double maxActivePower = batteryModificationInfos.getMaxActivePower() != null ? batteryModificationInfos.getMaxActivePower().getValue() : battery.getMaxP();
+ Double activePower = batteryModificationInfos.getActivePowerSetpoint() != null ? batteryModificationInfos.getActivePowerSetpoint().getValue() : battery.getTargetP();
+
+ String modificationToCreateJson = mapper.writeValueAsString(batteryModificationInfos);
+ mockMvc.perform(post(getNetworkModificationUri()).content(modificationToCreateJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk()).andReturn();
+ assertLogMessage("MODIFY_BATTERY_ERROR : Battery '" + "v3Battery" + "' : Active power " + activePower + " is expected to be equal to 0 or within the range of minimum active power and maximum active power: [" + minActivePower + ", " + maxActivePower + "]",
+ batteryModificationInfos.getErrorType().name(), reportService);
+
+ }
+
@Test
public void testMinQGreaterThanMaxQ() throws Exception {
BatteryModificationInfos batteryModificationInfos = (BatteryModificationInfos) buildModification();
diff --git a/src/test/java/org/gridsuite/modification/server/modifications/GenerationDispatchTest.java b/src/test/java/org/gridsuite/modification/server/modifications/GenerationDispatchTest.java
index 84b7184ab..865804c5f 100644
--- a/src/test/java/org/gridsuite/modification/server/modifications/GenerationDispatchTest.java
+++ b/src/test/java/org/gridsuite/modification/server/modifications/GenerationDispatchTest.java
@@ -23,10 +23,9 @@
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 java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.*;
import java.util.stream.Collectors;
import static org.gridsuite.modification.server.utils.TestUtils.assertLogMessage;
@@ -34,6 +33,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -47,6 +47,9 @@ public class GenerationDispatchTest extends AbstractNetworkModificationTest {
private static final String GH3_ID = "GH3";
private static final String GTH1_ID = "GTH1";
private static final String GTH2_ID = "GTH2";
+ private static final String BATTERY1_ID = "BATTERY1";
+ private static final String BATTERY2_ID = "BATTERY2";
+ private static final String BATTERY3_ID = "BATTERY3";
private static final String TEST1_ID = "TEST1";
private static final String GROUP1_ID = "GROUP1";
private static final String GROUP2_ID = "GROUP2";
@@ -90,11 +93,34 @@ private FilterEquipments getFilterEquipments(UUID filterID, String filterName,
.build();
}
+ private void assertLogReportsForDefaultNetwork(double batteryBalanceOnSc2) {
+ int firstSynchronousComponentNum = getNetwork().getGenerator(GTH1_ID).getTerminal().getBusView().getBus().getSynchronousComponent().getNum(); // GTH1 is in first synchronous component
+ assertLogMessage("The total demand is : 528.0 MW", "TotalDemand" + firstSynchronousComponentNum, reportService);
+ assertLogMessage("The total amount of fixed supply is : 0.0 MW", "TotalAmountFixedSupply" + firstSynchronousComponentNum, reportService);
+ assertLogMessage("The HVDC balance is : 90.0 MW", "TotalOutwardHvdcFlow" + firstSynchronousComponentNum, reportService);
+ assertLogMessage("The battery balance is : 0.0 MW", "TotalActiveBatteryTargetP" + firstSynchronousComponentNum, reportService);
+ assertLogMessage("The total amount of supply to be dispatched is : 438.0 MW", "TotalAmountSupplyToBeDispatched" + firstSynchronousComponentNum, reportService);
+ assertLogMessage("The supply-demand balance could not be met : the remaining power imbalance is 138.0 MW", "SupplyDemandBalanceCouldNotBeMet" + firstSynchronousComponentNum, reportService);
+ // on SC 2, we have to substract the battery balance
+ final double defaultTotalAmount = 330.0;
+ DecimalFormat df = new DecimalFormat("#0.0", new DecimalFormatSymbols(Locale.US));
+ final String totalAmount = df.format(defaultTotalAmount - batteryBalanceOnSc2);
+ int secondSynchronousComponentNum = getNetwork().getGenerator(GH1_ID).getTerminal().getBusView().getBus().getSynchronousComponent().getNum(); // GH1 is in second synchronous component
+ assertLogMessage("The total demand is : 240.0 MW", "TotalDemand" + secondSynchronousComponentNum, reportService);
+ assertLogMessage("The total amount of fixed supply is : 0.0 MW", "TotalAmountFixedSupply" + secondSynchronousComponentNum, reportService);
+ assertLogMessage("The HVDC balance is : -90.0 MW", "TotalOutwardHvdcFlow" + secondSynchronousComponentNum, reportService);
+ assertLogMessage("The battery balance is : " + df.format(batteryBalanceOnSc2) + " MW", "TotalActiveBatteryTargetP" + secondSynchronousComponentNum, reportService);
+ assertLogMessage("The total amount of supply to be dispatched is : " + totalAmount + " MW", "TotalAmountSupplyToBeDispatched" + secondSynchronousComponentNum, reportService);
+ assertLogMessage("Marginal cost: 150.0", "MaxUsedMarginalCost" + secondSynchronousComponentNum, reportService);
+ assertLogMessage("The supply-demand balance could be met", "SupplyDemandBalanceCouldBeMet" + secondSynchronousComponentNum, reportService);
+ assertLogMessage("Sum of generator active power setpoints in SOUTH region: " + totalAmount + " MW (NUCLEAR: 0.0 MW, THERMAL: 0.0 MW, HYDRO: " + totalAmount + " MW, WIND AND SOLAR: 0.0 MW, OTHER: 0.0 MW).", "SumGeneratorActivePowerSOUTH" + secondSynchronousComponentNum, reportService);
+ }
+
@Test
public void testGenerationDispatch() throws Exception {
ModificationInfos modification = buildModification();
- // network with 2 synchronous components, 2 hvdc lines between them and no forcedOutageRate and plannedOutageRate for the generators
+ // network with 2 synchronous components, no battery, 2 hvdc lines between them and no forcedOutageRate and plannedOutageRate for the generators
setNetwork(Network.read("testGenerationDispatch.xiidm", getClass().getResourceAsStream("/testGenerationDispatch.xiidm")));
String modificationJson = mapper.writeValueAsString(modification);
@@ -103,22 +129,67 @@ public void testGenerationDispatch() throws Exception {
assertNetworkAfterCreationWithStandardLossCoefficient();
- // test total demand and remaining power imbalance on synchronous components
- int firstSynchronousComponentNum = getNetwork().getGenerator(GTH1_ID).getTerminal().getBusView().getBus().getSynchronousComponent().getNum(); // GTH1 is in first synchronous component
- assertLogMessage("The total demand is : 528.0 MW", "TotalDemand" + firstSynchronousComponentNum, reportService);
- assertLogMessage("The total amount of fixed supply is : 0.0 MW", "TotalAmountFixedSupply" + firstSynchronousComponentNum, reportService);
- assertLogMessage("The HVDC balance is : 90.0 MW", "TotalOutwardHvdcFlow" + firstSynchronousComponentNum, reportService);
- assertLogMessage("The total amount of supply to be dispatched is : 438.0 MW", "TotalAmountSupplyToBeDispatched" + firstSynchronousComponentNum, reportService);
- assertLogMessage("The supply-demand balance could not be met : the remaining power imbalance is 138.0 MW", "SupplyDemandBalanceCouldNotBeMet" + firstSynchronousComponentNum, reportService);
+ assertLogReportsForDefaultNetwork(0.);
+ }
- int secondSynchronousComponentNum = getNetwork().getGenerator(GH1_ID).getTerminal().getBusView().getBus().getSynchronousComponent().getNum(); // GH1 is in second synchronous component
- assertLogMessage("The total demand is : 240.0 MW", "TotalDemand" + secondSynchronousComponentNum, reportService);
- assertLogMessage("The total amount of fixed supply is : 0.0 MW", "TotalAmountFixedSupply" + secondSynchronousComponentNum, reportService);
- assertLogMessage("The HVDC balance is : -90.0 MW", "TotalOutwardHvdcFlow" + secondSynchronousComponentNum, reportService);
- assertLogMessage("The total amount of supply to be dispatched is : 330.0 MW", "TotalAmountSupplyToBeDispatched" + secondSynchronousComponentNum, reportService);
- assertLogMessage("Marginal cost: 150.0", "MaxUsedMarginalCost" + secondSynchronousComponentNum, reportService);
- assertLogMessage("The supply-demand balance could be met", "SupplyDemandBalanceCouldBeMet" + secondSynchronousComponentNum, reportService);
- assertLogMessage("Sum of generator active power setpoints in SOUTH region: 330.0 MW.", "SumGeneratorActivePowerSOUTH" + secondSynchronousComponentNum, reportService);
+ @Test
+ public void testGenerationDispatchWithBattery() throws Exception {
+ ModificationInfos modification = buildModification();
+
+ // same than testGenerationDispatch, with 3 Batteries (in 2nd SC)
+ setNetwork(Network.read("testGenerationDispatchWithBatteries.xiidm", getClass().getResourceAsStream("/testGenerationDispatchWithBatteries.xiidm")));
+ // only 2 are connected
+ assertTrue(getNetwork().getBattery(BATTERY1_ID).getTerminal().isConnected());
+ assertTrue(getNetwork().getBattery(BATTERY2_ID).getTerminal().isConnected());
+ assertFalse(getNetwork().getBattery(BATTERY3_ID).getTerminal().isConnected());
+ final double batteryTotalTargetP = getNetwork().getBattery(BATTERY1_ID).getTargetP() + getNetwork().getBattery(BATTERY2_ID).getTargetP();
+
+ String modificationJson = mapper.writeValueAsString(modification);
+ mockMvc.perform(post(getNetworkModificationUri()).content(modificationJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+
+ assertLogReportsForDefaultNetwork(batteryTotalTargetP);
+ }
+
+ @Test
+ public void testGenerationDispatchWithBatteryConnection() throws Exception {
+ ModificationInfos modification = buildModification();
+
+ // network with 3 Batteries (in 2nd SC)
+ setNetwork(Network.read("testGenerationDispatch.xiidm", getClass().getResourceAsStream("/testGenerationDispatchWithBatteries.xiidm")));
+ // connect the 3rd one
+ assertTrue(getNetwork().getBattery(BATTERY1_ID).getTerminal().isConnected());
+ assertTrue(getNetwork().getBattery(BATTERY2_ID).getTerminal().isConnected());
+ assertFalse(getNetwork().getBattery(BATTERY3_ID).getTerminal().isConnected());
+ assertTrue(getNetwork().getBattery(BATTERY3_ID).getTargetP() > 0);
+ getNetwork().getBattery(BATTERY3_ID).getTerminal().connect();
+ final double batteryTotalTargetP = getNetwork().getBattery(BATTERY1_ID).getTargetP() + getNetwork().getBattery(BATTERY2_ID).getTargetP() + getNetwork().getBattery(BATTERY3_ID).getTargetP();
+
+ String modificationJson = mapper.writeValueAsString(modification);
+ mockMvc.perform(post(getNetworkModificationUri()).content(modificationJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+
+ assertLogReportsForDefaultNetwork(batteryTotalTargetP);
+ }
+
+ @Test
+ public void testGenerationDispatchWithMultipleEnergySource() throws Exception {
+ ModificationInfos modification = buildModification();
+
+ setNetwork(Network.read("testGenerationDispatchWithMultipleEnergySource.xiidm", getClass().getResourceAsStream("/testGenerationDispatchWithMultipleEnergySource.xiidm")));
+
+ String modificationJson = mapper.writeValueAsString(modification);
+ mockMvc.perform(post(getNetworkModificationUri()).content(modificationJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+
+ int synchronousComponentNum = getNetwork().getGenerator(GH1_ID).getTerminal().getBusView().getBus().getSynchronousComponent().getNum();
+ assertLogMessage("The total demand is : 768.0 MW", "TotalDemand" + synchronousComponentNum, reportService);
+ assertLogMessage("The total amount of fixed supply is : 0.0 MW", "TotalAmountFixedSupply" + synchronousComponentNum, reportService);
+ assertLogMessage("The HVDC balance is : -90.0 MW", "TotalOutwardHvdcFlow" + synchronousComponentNum, reportService);
+ assertLogMessage("The total amount of supply to be dispatched is : 858.0 MW", "TotalAmountSupplyToBeDispatched" + synchronousComponentNum, reportService);
+ assertLogMessage("Marginal cost: 28.0", "MaxUsedMarginalCost" + synchronousComponentNum, reportService);
+ assertLogMessage("The supply-demand balance could be met", "SupplyDemandBalanceCouldBeMet" + synchronousComponentNum, reportService);
+ assertLogMessage("Sum of generator active power setpoints in SOUTH region: 858.0 MW (NUCLEAR: 150.0 MW, THERMAL: 200.0 MW, HYDRO: 108.0 MW, WIND AND SOLAR: 150.0 MW, OTHER: 250.0 MW).", "SumGeneratorActivePowerSOUTH" + synchronousComponentNum, reportService);
}
@Test
@@ -248,7 +319,7 @@ public void testGenerationDispatchWithMaxPReduction() throws Exception {
assertLogMessage("The total amount of supply to be dispatched is : 330.0 MW", "TotalAmountSupplyToBeDispatched" + secondSynchronousComponentNum, reportService);
assertLogMessage("Marginal cost: 150.0", "MaxUsedMarginalCost" + secondSynchronousComponentNum, reportService);
assertLogMessage("The supply-demand balance could be met", "SupplyDemandBalanceCouldBeMet" + secondSynchronousComponentNum, reportService);
- assertLogMessage("Sum of generator active power setpoints in WEST region: 330.0 MW.", "SumGeneratorActivePowerWEST" + secondSynchronousComponentNum, reportService);
+ assertLogMessage("Sum of generator active power setpoints in WEST region: 330.0 MW (NUCLEAR: 0.0 MW, THERMAL: 0.0 MW, HYDRO: 330.0 MW, WIND AND SOLAR: 0.0 MW, OTHER: 0.0 MW).", "SumGeneratorActivePowerWEST" + secondSynchronousComponentNum, reportService);
wireMockUtils.verifyGetRequest(stubId, PATH, handleQueryParams(getNetworkUuid(), filters.stream().map(FilterEquipments::getFilterId).collect(Collectors.toList())), false);
}
@@ -313,7 +384,7 @@ public void testGenerationDispatchGeneratorsWithFixedSupply() throws Exception {
assertLogMessage("The total amount of supply to be dispatched is : 330.0 MW", "TotalAmountSupplyToBeDispatched" + secondSynchronousComponentNum, reportService);
assertLogMessage("Marginal cost: 150.0", "MaxUsedMarginalCost" + secondSynchronousComponentNum, reportService);
assertLogMessage("The supply-demand balance could be met", "SupplyDemandBalanceCouldBeMet" + secondSynchronousComponentNum, reportService);
- assertLogMessage("Sum of generator active power setpoints in EAST region: 330.0 MW.", "SumGeneratorActivePowerEAST" + secondSynchronousComponentNum, reportService);
+ assertLogMessage("Sum of generator active power setpoints in EAST region: 330.0 MW (NUCLEAR: 0.0 MW, THERMAL: 0.0 MW, HYDRO: 330.0 MW, WIND AND SOLAR: 0.0 MW, OTHER: 0.0 MW).", "SumGeneratorActivePowerEAST" + secondSynchronousComponentNum, reportService);
wireMockUtils.verifyGetRequest(stubIdForPmaxReduction, PATH, handleQueryParams(getNetworkUuid(), filtersForPmaxReduction.stream().map(FilterEquipments::getFilterId).collect(Collectors.toList())), false);
wireMockUtils.verifyGetRequest(stubIdForFixedSupply, PATH, handleQueryParams(getNetworkUuid(), filtersForFixedSupply.stream().map(FilterEquipments::getFilterId).collect(Collectors.toList())), false);
@@ -396,7 +467,7 @@ public void testGenerationDispatchWithFrequencyReserve() throws Exception {
assertLogMessage("The total amount of fixed supply is : 0.0 MW", "TotalAmountFixedSupply" + firstSynchronousComponentNum, reportService);
assertLogMessage("The HVDC balance is : 90.0 MW", "TotalOutwardHvdcFlow" + firstSynchronousComponentNum, reportService);
assertLogMessage("The total amount of supply to be dispatched is : 438.0 MW", "TotalAmountSupplyToBeDispatched" + firstSynchronousComponentNum, reportService);
- assertLogMessage("The supply-demand balance could not be met : the remaining power imbalance is 177.92000000000002 MW", "SupplyDemandBalanceCouldNotBeMet" + firstSynchronousComponentNum, reportService);
+ assertLogMessage("The supply-demand balance could not be met : the remaining power imbalance is 177.9 MW", "SupplyDemandBalanceCouldNotBeMet" + firstSynchronousComponentNum, reportService);
int secondSynchronousComponentNum = getNetwork().getGenerator(GH1_ID).getTerminal().getBusView().getBus().getSynchronousComponent().getNum(); // GH1 is in second synchronous component
assertLogMessage("The total demand is : 240.0 MW", "TotalDemand" + secondSynchronousComponentNum, reportService);
@@ -405,7 +476,7 @@ public void testGenerationDispatchWithFrequencyReserve() throws Exception {
assertLogMessage("The total amount of supply to be dispatched is : 330.0 MW", "TotalAmountSupplyToBeDispatched" + secondSynchronousComponentNum, reportService);
assertLogMessage("Marginal cost: 150.0", "MaxUsedMarginalCost" + secondSynchronousComponentNum, reportService);
assertLogMessage("The supply-demand balance could be met", "SupplyDemandBalanceCouldBeMet" + secondSynchronousComponentNum, reportService);
- assertLogMessage("Sum of generator active power setpoints in WEST region: 330.0 MW.", "SumGeneratorActivePowerWEST" + secondSynchronousComponentNum, reportService);
+ assertLogMessage("Sum of generator active power setpoints in WEST region: 330.0 MW (NUCLEAR: 0.0 MW, THERMAL: 0.0 MW, HYDRO: 330.0 MW, WIND AND SOLAR: 0.0 MW, OTHER: 0.0 MW).", "SumGeneratorActivePowerWEST" + secondSynchronousComponentNum, reportService);
wireMockUtils.verifyGetRequest(stubIdForPmaxReduction, PATH, handleQueryParams(getNetworkUuid(), getGeneratorsWithoutOutageFilters123().stream().map(FilterEquipments::getFilterId).collect(Collectors.toList())), false);
wireMockUtils.verifyGetRequest(stubIdForFrequencyReserve1, PATH, handleQueryParams(getNetworkUuid(), getGeneratorsFrequencyReserveFilters45().stream().map(FilterEquipments::getFilterId).collect(Collectors.toList())), false);
@@ -544,10 +615,10 @@ public void testGenerationDispatchWithMaxValueLessThanMinP() throws Exception {
assertLogMessage("The total amount of fixed supply is : 0.0 MW", "TotalAmountFixedSupply" + firstSynchronousComponentNum, reportService);
assertLogMessage("The HVDC balance is : 90.0 MW", "TotalOutwardHvdcFlow" + firstSynchronousComponentNum, reportService);
assertLogMessage("The total amount of supply to be dispatched is : 438.0 MW", "TotalAmountSupplyToBeDispatched" + firstSynchronousComponentNum, reportService);
- assertLogNthMessage("The active power set point of generator TEST1 has been set to 40.375 MW", "GeneratorSetTargetP" + firstSynchronousComponentNum, reportService, 1);
+ assertLogNthMessage("The active power set point of generator TEST1 has been set to 40.4 MW", "GeneratorSetTargetP" + firstSynchronousComponentNum, reportService, 1);
assertLogNthMessage("The active power set point of generator GTH1 has been set to 80.0 MW", "GeneratorSetTargetP" + firstSynchronousComponentNum, reportService, 2);
assertLogNthMessage("The active power set point of generator GTH2 has been set to 146.0 MW", "GeneratorSetTargetP" + firstSynchronousComponentNum, reportService, 3);
- assertLogMessage("The supply-demand balance could not be met : the remaining power imbalance is 171.625 MW", "SupplyDemandBalanceCouldNotBeMet" + firstSynchronousComponentNum, reportService);
+ assertLogMessage("The supply-demand balance could not be met : the remaining power imbalance is 171.6 MW", "SupplyDemandBalanceCouldNotBeMet" + firstSynchronousComponentNum, reportService);
int secondSynchronousComponentNum = getNetwork().getGenerator(GH1_ID).getTerminal().getBusView().getBus().getSynchronousComponent().getNum(); // GH1 is in second synchronous component
assertLogMessage("The total demand is : 240.0 MW", "TotalDemand" + secondSynchronousComponentNum, reportService);
assertLogMessage("The total amount of fixed supply is : 0.0 MW", "TotalAmountFixedSupply" + secondSynchronousComponentNum, reportService);
@@ -556,10 +627,10 @@ public void testGenerationDispatchWithMaxValueLessThanMinP() throws Exception {
assertLogNthMessage("The active power set point of generator GH1 has been set to 80.0 MW", "GeneratorSetTargetP" + secondSynchronousComponentNum, reportService, 1);
assertLogNthMessage("The active power set point of generator GH2 has been set to 60.0 MW", "GeneratorSetTargetP" + secondSynchronousComponentNum, reportService, 2);
assertLogNthMessage("The active power set point of generator GH3 has been set to 126.1 MW", "GeneratorSetTargetP" + secondSynchronousComponentNum, reportService, 3);
- assertLogNthMessage("The active power set point of generator ABC has been set to 63.900000000000006 MW", "GeneratorSetTargetP" + secondSynchronousComponentNum, reportService, 4);
+ assertLogNthMessage("The active power set point of generator ABC has been set to 63.9 MW", "GeneratorSetTargetP" + secondSynchronousComponentNum, reportService, 4);
assertLogMessage("Marginal cost: 150.0", "MaxUsedMarginalCost" + secondSynchronousComponentNum, reportService);
assertLogMessage("The supply-demand balance could be met", "SupplyDemandBalanceCouldBeMet" + secondSynchronousComponentNum, reportService);
- assertLogMessage("Sum of generator active power setpoints in NORTH region: 330.0 MW.", "SumGeneratorActivePowerNORTH" + secondSynchronousComponentNum, reportService);
+ assertLogMessage("Sum of generator active power setpoints in NORTH region: 330.0 MW (NUCLEAR: 0.0 MW, THERMAL: 0.0 MW, HYDRO: 330.0 MW, WIND AND SOLAR: 0.0 MW, OTHER: 0.0 MW).", "SumGeneratorActivePowerNORTH" + secondSynchronousComponentNum, reportService);
wireMockUtils.verifyGetRequest(stubIdForPmaxReduction, PATH, handleQueryParams(getNetworkUuid(), getGeneratorsWithoutOutageFilters123().stream().map(FilterEquipments::getFilterId).collect(Collectors.toList())), false);
wireMockUtils.verifyGetRequest(stubIdForFrequencyReserve1, PATH, handleQueryParams(getNetworkUuid(), getGeneratorsFrequencyReserveFilters45().stream().map(FilterEquipments::getFilterId).collect(Collectors.toList())), false);
diff --git a/src/test/java/org/gridsuite/modification/server/modifications/GeneratorModificationTest.java b/src/test/java/org/gridsuite/modification/server/modifications/GeneratorModificationTest.java
index 6b753fdc1..32eed149c 100644
--- a/src/test/java/org/gridsuite/modification/server/modifications/GeneratorModificationTest.java
+++ b/src/test/java/org/gridsuite/modification/server/modifications/GeneratorModificationTest.java
@@ -391,6 +391,28 @@ public void testMinQGreaterThanMaxQ() throws Exception {
generatorModificationInfos.getErrorType().name(), reportService);
}
+ @Test
+ public void testActivePowerZeroOrBetweenMinAndMaxActivePower() throws Exception {
+ GeneratorModificationInfos generatorModificationInfos = (GeneratorModificationInfos) buildModification();
+ Generator generator = getNetwork().getGenerator("idGenerator");
+ generator.setTargetP(80.)
+ .setMinP(10.)
+ .setMaxP(150.);
+
+ generatorModificationInfos.setActivePowerSetpoint(new AttributeModification<>(110.0, OperationType.SET));
+
+ Double minActivePower = generatorModificationInfos.getMinActivePower() != null ? generatorModificationInfos.getMinActivePower().getValue() : generator.getMinP();
+ Double maxActivePower = generatorModificationInfos.getMaxActivePower() != null ? generatorModificationInfos.getMaxActivePower().getValue() : generator.getMaxP();
+ Double activePower = generatorModificationInfos.getActivePowerSetpoint() != null ? generatorModificationInfos.getActivePowerSetpoint().getValue() : generator.getTargetP();
+
+ String modificationToCreateJson = mapper.writeValueAsString(generatorModificationInfos);
+ mockMvc.perform(post(getNetworkModificationUri()).content(modificationToCreateJson).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk()).andReturn();
+ assertLogMessage("MODIFY_GENERATOR_ERROR : Generator '" + "idGenerator" + "' : Active power " + activePower + " is expected to be equal to 0 or within the range of minimum active power and maximum active power: [" + minActivePower + ", " + maxActivePower + "]",
+ generatorModificationInfos.getErrorType().name(), reportService);
+
+ }
+
@Test
public void testUnsetAttributes() throws Exception {
GeneratorModificationInfos generatorModificationInfos = (GeneratorModificationInfos) buildModification();
diff --git a/src/test/java/org/gridsuite/modification/server/modifications/TwoWindingsTransformerByFormulaModificationTest.java b/src/test/java/org/gridsuite/modification/server/modifications/TwoWindingsTransformerByFormulaModificationTest.java
new file mode 100644
index 000000000..b3d78c507
--- /dev/null
+++ b/src/test/java/org/gridsuite/modification/server/modifications/TwoWindingsTransformerByFormulaModificationTest.java
@@ -0,0 +1,576 @@
+package org.gridsuite.modification.server.modifications;
+
+import com.github.tomakehurst.wiremock.client.WireMock;
+import com.powsybl.iidm.network.IdentifiableType;
+import com.powsybl.iidm.network.PhaseTapChanger;
+import com.powsybl.iidm.network.PhaseTapChangerAdder;
+import com.powsybl.iidm.network.RatioTapChanger;
+import com.powsybl.iidm.network.RatioTapChangerAdder;
+import com.powsybl.iidm.network.Substation;
+import com.powsybl.iidm.network.TwoWindingsTransformer;
+import com.powsybl.iidm.network.extensions.ConnectablePosition;
+import org.gridsuite.modification.server.dto.ByFormulaModificationInfos;
+import org.gridsuite.modification.server.dto.FilterEquipments;
+import org.gridsuite.modification.server.dto.IdentifiableAttributes;
+import org.gridsuite.modification.server.dto.NetworkModificationResult;
+import org.gridsuite.modification.server.dto.formula.FormulaInfos;
+import org.gridsuite.modification.server.dto.formula.Operator;
+import org.gridsuite.modification.server.dto.formula.ReferenceFieldOrValue;
+import org.gridsuite.modification.server.dto.formula.equipmentfield.TwoWindingsTransformerField;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.UUID;
+
+import static org.gridsuite.modification.server.utils.NetworkUtil.createTwoWindingsTransformer;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class TwoWindingsTransformerByFormulaModificationTest extends AbstractByFormulaModificationTest {
+ private static final String TWT_ID_1 = "twt1";
+ private static final String TWT_ID_2 = "twt2";
+ private static final String TWT_ID_3 = "twt3";
+ private static final String TWT_ID_4 = "twt4";
+ private static final String TWT_ID_5 = "twt5";
+ private static final String TWT_ID_6 = "twt6";
+
+ @Test
+ public void testModifyTwtWithError() throws Exception {
+ IdentifiableAttributes identifiableAttributes1 = getIdentifiableAttributes(TWT_ID_4, 1.);
+ IdentifiableAttributes identifiableAttributes2 = getIdentifiableAttributes(TWT_ID_6, 1.);
+ FilterEquipments filter = getFilterEquipments(FILTER_ID_4, "filter4", List.of(identifiableAttributes1, identifiableAttributes2), List.of());
+
+ UUID stubId = wireMockServer.stubFor(WireMock.get(WireMock.urlMatching("/v1/filters/export\\?networkUuid=" + getNetworkUuid() + "&variantId=variant_1&ids=" + FILTER_ID_4))
+ .willReturn(WireMock.ok()
+ .withBody(mapper.writeValueAsString(List.of(filter)))
+ .withHeader("Content-Type", "application/json"))).getId();
+ FormulaInfos formulaInfos = FormulaInfos.builder()
+ .filters(List.of(filter4))
+ .fieldOrValue2(ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.RATIO_TAP_POSITION.name()).build())
+ .fieldOrValue1(ReferenceFieldOrValue.builder().value(1.).build())
+ .editedField(TwoWindingsTransformerField.RATIO_TAP_POSITION.name())
+ .operator(Operator.ADDITION)
+ .build();
+ checkCreationApplicationStatus(ByFormulaModificationInfos.builder()
+ .identifiableType(getIdentifiableType())
+ .formulaInfosList(List.of(formulaInfos))
+ .build(),
+ NetworkModificationResult.ApplicationStatus.WITH_ERRORS);
+
+ assertNull(getNetwork().getTwoWindingsTransformer(TWT_ID_4).getRatioTapChanger());
+ assertNull(getNetwork().getTwoWindingsTransformer(TWT_ID_6).getRatioTapChanger());
+
+ wireMockUtils.verifyGetRequest(stubId, PATH, handleQueryParams(getNetworkUuid(), List.of(FILTER_ID_4)), false);
+ }
+
+ @Test
+ public void testDivisionByZero() throws Exception {
+ IdentifiableAttributes identifiableAttributes1 = getIdentifiableAttributes(TWT_ID_4, 1.);
+ IdentifiableAttributes identifiableAttributes2 = getIdentifiableAttributes(TWT_ID_6, 1.);
+ FilterEquipments filter = getFilterEquipments(FILTER_ID_4, "filter4", List.of(identifiableAttributes1, identifiableAttributes2), List.of());
+
+ UUID stubId = wireMockServer.stubFor(WireMock.get(WireMock.urlMatching("/v1/filters/export\\?networkUuid=" + getNetworkUuid() + "&variantId=variant_1&ids=" + FILTER_ID_4))
+ .willReturn(WireMock.ok()
+ .withBody(mapper.writeValueAsString(List.of(filter)))
+ .withHeader("Content-Type", "application/json"))).getId();
+
+ // Test division by 0
+ FormulaInfos formulaInfos2 = FormulaInfos.builder()
+ .fieldOrValue1(ReferenceFieldOrValue.builder().value(50.).build())
+ .fieldOrValue2(ReferenceFieldOrValue.builder().value(0.).build())
+ .operator(Operator.DIVISION)
+ .filters(List.of(filter4))
+ .build();
+
+ checkCreationApplicationStatus(ByFormulaModificationInfos.builder().identifiableType(getIdentifiableType()).formulaInfosList(List.of(formulaInfos2)).build(),
+ NetworkModificationResult.ApplicationStatus.WITH_ERRORS);
+
+ wireMockUtils.verifyGetRequest(stubId, PATH, handleQueryParams(getNetworkUuid(), List.of(FILTER_ID_4)), false);
+ }
+
+ @Test
+ public void testModifyTwtWithWarning() throws Exception {
+ IdentifiableAttributes identifiableAttributes1 = getIdentifiableAttributes(TWT_ID_1, 1.);
+ IdentifiableAttributes identifiableAttributes2 = getIdentifiableAttributes(TWT_ID_2, 1.);
+ IdentifiableAttributes identifiableAttributes3 = getIdentifiableAttributes(TWT_ID_4, 1.);
+ IdentifiableAttributes identifiableAttributes4 = getIdentifiableAttributes(TWT_ID_6, 1.);
+ FilterEquipments filterTwt1 = getFilterEquipments(FILTER_ID_1, "filter1", List.of(identifiableAttributes1, identifiableAttributes2), List.of());
+ FilterEquipments filterTwt2 = getFilterEquipments(FILTER_ID_4, "filter4", List.of(identifiableAttributes3, identifiableAttributes4), List.of());
+
+ UUID stubId = wireMockServer.stubFor(WireMock.get(WireMock.urlMatching(getPath(getNetworkUuid(), true) + ".{2,}"))
+ .willReturn(WireMock.ok()
+ .withBody(mapper.writeValueAsString(List.of(filterTwt1, filterTwt2)))
+ .withHeader("Content-Type", "application/json"))).getId();
+
+ FormulaInfos formulaInfos = FormulaInfos.builder()
+ .filters(List.of(filter1, filter4))
+ .fieldOrValue2(ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.RATIO_TAP_POSITION.name()).build())
+ .fieldOrValue1(ReferenceFieldOrValue.builder().value(1.).build())
+ .editedField(TwoWindingsTransformerField.RATIO_TAP_POSITION.name())
+ .operator(Operator.ADDITION)
+ .build();
+
+ checkCreationApplicationStatus(ByFormulaModificationInfos.builder()
+ .identifiableType(getIdentifiableType())
+ .formulaInfosList(List.of(formulaInfos))
+ .build(),
+ NetworkModificationResult.ApplicationStatus.WITH_WARNINGS);
+
+ assertNotNull(getNetwork().getTwoWindingsTransformer(TWT_ID_1).getRatioTapChanger());
+ assertNotNull(getNetwork().getTwoWindingsTransformer(TWT_ID_2).getRatioTapChanger());
+ assertEquals(2, getNetwork().getTwoWindingsTransformer(TWT_ID_1).getRatioTapChanger().getTapPosition());
+ assertEquals(5, getNetwork().getTwoWindingsTransformer(TWT_ID_2).getRatioTapChanger().getTapPosition());
+ assertNull(getNetwork().getTwoWindingsTransformer(TWT_ID_4).getRatioTapChanger());
+ assertNull(getNetwork().getTwoWindingsTransformer(TWT_ID_6).getRatioTapChanger());
+
+ wireMockUtils.verifyGetRequest(stubId, PATH, handleQueryParams(getNetworkUuid(), List.of(FILTER_ID_1, FILTER_ID_4)), false);
+ }
+
+ @Override
+ protected void createEquipments() {
+ Substation s1 = getNetwork().getSubstation("s1");
+ Substation s3 = getNetwork().getSubstation("s3");
+ TwoWindingsTransformer twt1 = createTwoWindingsTransformer(s1, TWT_ID_1, TWT_ID_1, 30, 40, 50, 60, 10, 20, 100, 110,
+ "v1", "v2",
+ "trf1", 11, ConnectablePosition.Direction.TOP,
+ "trf1", 22, ConnectablePosition.Direction.BOTTOM);
+ twt1.setRatedS(11);
+ addRatioTapChangerSteps(twt1.newRatioTapChanger().setTargetV(50).setLowTapPosition(0).setTapPosition(1).setTargetDeadband(55));
+
+ TwoWindingsTransformer twt2 = createTwoWindingsTransformer(s1, TWT_ID_2, TWT_ID_2, 35, 45, 55, 65, 15, 25, 105, 115,
+ "v1", "v4",
+ "trf1", 33, ConnectablePosition.Direction.TOP,
+ "trf1", 44, ConnectablePosition.Direction.BOTTOM);
+ twt2.setRatedS(10);
+ addRatioTapChangerSteps(twt2.newRatioTapChanger().setTargetV(53).setLowTapPosition(3).setTapPosition(4).setTargetDeadband(58));
+
+ TwoWindingsTransformer twt3 = createTwoWindingsTransformer(s1, TWT_ID_3, TWT_ID_3, 40, 50, 60, 70, 20, 30, 110, 120,
+ "v2", "v4",
+ "trf1", 10, ConnectablePosition.Direction.TOP,
+ "trf1", 20, ConnectablePosition.Direction.BOTTOM);
+ twt3.setRatedS(25);
+ addRatioTapChangerSteps(twt3.newRatioTapChanger().setTargetV(56).setLowTapPosition(0).setTapPosition(1).setTargetDeadband(61));
+
+ TwoWindingsTransformer twt4 = createTwoWindingsTransformer(s3, TWT_ID_4, TWT_ID_4, 45, 55, 65, 75, 25, 35, 115, 125,
+ "v5", "v6",
+ "trf1", 30, ConnectablePosition.Direction.TOP,
+ "trf1", 40, ConnectablePosition.Direction.BOTTOM);
+ twt4.setRatedS(15);
+ addPhaseTapChangerSteps(twt4.newPhaseTapChanger().setRegulationValue(45).setLowTapPosition(1).setTapPosition(2).setTargetDeadband(34));
+
+ TwoWindingsTransformer twt5 = createTwoWindingsTransformer(s3, TWT_ID_5, TWT_ID_5, 50, 60, 70, 80, 30, 40, 120, 130,
+ "v5", "v6",
+ "trf1", 15, ConnectablePosition.Direction.TOP,
+ "trf1", 26, ConnectablePosition.Direction.BOTTOM);
+ twt5.setRatedS(30);
+ addPhaseTapChangerSteps(twt5.newPhaseTapChanger().setRegulationValue(46).setLowTapPosition(2).setTapPosition(2).setTargetDeadband(35));
+
+ TwoWindingsTransformer twt6 = createTwoWindingsTransformer(s3, TWT_ID_6, TWT_ID_6, 55, 65, 75, 85, 35, 45, 125, 135,
+ "v5", "v6",
+ "trf1", 38, ConnectablePosition.Direction.TOP,
+ "trf1", 49, ConnectablePosition.Direction.BOTTOM);
+ twt6.setRatedS(20);
+ addPhaseTapChangerSteps(twt6.newPhaseTapChanger().setRegulationValue(47).setLowTapPosition(1).setTapPosition(1).setTargetDeadband(36));
+ }
+
+ @Override
+ protected List getTestFilters() {
+ IdentifiableAttributes twt1 = getIdentifiableAttributes(TWT_ID_1, 1.0);
+ IdentifiableAttributes twt2 = getIdentifiableAttributes(TWT_ID_2, 2.0);
+ IdentifiableAttributes twt3 = getIdentifiableAttributes(TWT_ID_3, 2.0);
+ IdentifiableAttributes twt4 = getIdentifiableAttributes(TWT_ID_4, 5.0);
+ IdentifiableAttributes twt5 = getIdentifiableAttributes(TWT_ID_5, 6.0);
+ IdentifiableAttributes twt6 = getIdentifiableAttributes(TWT_ID_6, 7.0);
+
+ FilterEquipments filter1 = getFilterEquipments(FILTER_ID_1, "filter1", List.of(twt1, twt2), List.of());
+ FilterEquipments filter2 = getFilterEquipments(FILTER_ID_2, "filter2", List.of(twt1, twt3), List.of());
+ FilterEquipments filter3 = getFilterEquipments(FILTER_ID_3, "filter3", List.of(twt4, twt5), List.of());
+ FilterEquipments filter4 = getFilterEquipments(FILTER_ID_4, "filter4", List.of(twt4, twt6), List.of());
+
+ return List.of(filter1, filter2, filter3, filter4);
+ }
+
+ @Override
+ protected List getFormulaInfos() {
+ FormulaInfos formulaInfos1 = getFormulaInfo(TwoWindingsTransformerField.TARGET_V.name(),
+ List.of(filter1),
+ Operator.PERCENTAGE,
+ ReferenceFieldOrValue.builder().value(200.).build(),
+ ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.TARGET_V.name()).build());
+
+ FormulaInfos formulaInfos2 = getFormulaInfo(TwoWindingsTransformerField.RATIO_TAP_POSITION.name(),
+ List.of(filter2),
+ Operator.MULTIPLICATION,
+ ReferenceFieldOrValue.builder().value(4.).build(),
+ ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.RATIO_TAP_POSITION.name()).build());
+
+ FormulaInfos formulaInfos3 = getFormulaInfo(TwoWindingsTransformerField.RATIO_LOW_TAP_POSITION.name(),
+ List.of(filter2),
+ Operator.ADDITION,
+ ReferenceFieldOrValue.builder().value(1.).build(),
+ ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.RATIO_LOW_TAP_POSITION.name()).build());
+
+ FormulaInfos formulaInfos4 = getFormulaInfo(TwoWindingsTransformerField.RATIO_TARGET_DEADBAND.name(),
+ List.of(filter1),
+ Operator.DIVISION,
+ ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.RATIO_TARGET_DEADBAND.name()).build(),
+ ReferenceFieldOrValue.builder().value(5.).build());
+
+ FormulaInfos formulaInfos5 = getFormulaInfo(TwoWindingsTransformerField.REGULATION_VALUE.name(),
+ List.of(filter4),
+ Operator.PERCENTAGE,
+ ReferenceFieldOrValue.builder().value(200.).build(),
+ ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.REGULATION_VALUE.name()).build());
+
+ FormulaInfos formulaInfos6 = getFormulaInfo(TwoWindingsTransformerField.PHASE_TAP_POSITION.name(),
+ List.of(filter3),
+ Operator.MULTIPLICATION,
+ ReferenceFieldOrValue.builder().value(2.).build(),
+ ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.PHASE_TAP_POSITION.name()).build());
+
+ FormulaInfos formulaInfos7 = getFormulaInfo(TwoWindingsTransformerField.PHASE_LOW_TAP_POSITION.name(),
+ List.of(filter3),
+ Operator.MULTIPLICATION,
+ ReferenceFieldOrValue.builder().value(2.).build(),
+ ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.PHASE_LOW_TAP_POSITION.name()).build());
+
+ FormulaInfos formulaInfos8 = getFormulaInfo(TwoWindingsTransformerField.PHASE_TARGET_DEADBAND.name(),
+ List.of(filter4),
+ Operator.SUBTRACTION,
+ ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.PHASE_TARGET_DEADBAND.name()).build(),
+ ReferenceFieldOrValue.builder().value(10.).build());
+
+ FormulaInfos formulaInfos9 = getFormulaInfo(TwoWindingsTransformerField.SERIES_REACTANCE.name(),
+ List.of(filter1, filter4),
+ Operator.ADDITION,
+ ReferenceFieldOrValue.builder().value(20.).build(),
+ ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.SERIES_REACTANCE.name()).build());
+
+ FormulaInfos formulaInfos10 = getFormulaInfo(TwoWindingsTransformerField.SERIES_RESISTANCE.name(),
+ List.of(filter2, filter3),
+ Operator.PERCENTAGE,
+ ReferenceFieldOrValue.builder().value(200.).build(),
+ ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.SERIES_RESISTANCE.name()).build());
+
+ FormulaInfos formulaInfos11 = getFormulaInfo(TwoWindingsTransformerField.MAGNETIZING_CONDUCTANCE.name(),
+ List.of(filter4, filter2),
+ Operator.ADDITION,
+ ReferenceFieldOrValue.builder().value(25.).build(),
+ ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.MAGNETIZING_CONDUCTANCE.name()).build());
+
+ FormulaInfos formulaInfos12 = getFormulaInfo(TwoWindingsTransformerField.MAGNETIZING_SUSCEPTANCE.name(),
+ List.of(filter1, filter3),
+ Operator.MULTIPLICATION,
+ ReferenceFieldOrValue.builder().value(2.5).build(),
+ ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.MAGNETIZING_SUSCEPTANCE.name()).build());
+
+ FormulaInfos formulaInfos13 = getFormulaInfo(TwoWindingsTransformerField.RATED_VOLTAGE_1.name(),
+ List.of(filter2),
+ Operator.ADDITION,
+ ReferenceFieldOrValue.builder().value(15.).build(),
+ ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.RATED_VOLTAGE_1.name()).build());
+
+ FormulaInfos formulaInfos14 = getFormulaInfo(TwoWindingsTransformerField.RATED_VOLTAGE_2.name(),
+ List.of(filter3, filter2),
+ Operator.PERCENTAGE,
+ ReferenceFieldOrValue.builder().value(50.).build(),
+ ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.RATED_VOLTAGE_2.name()).build());
+
+ FormulaInfos formulaInfos15 = getFormulaInfo(TwoWindingsTransformerField.RATED_S.name(),
+ List.of(filter1, filter2),
+ Operator.PERCENTAGE,
+ ReferenceFieldOrValue.builder().value(200.).build(),
+ ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.RATED_S.name()).build());
+
+ return List.of(formulaInfos1,
+ formulaInfos2,
+ formulaInfos3,
+ formulaInfos4,
+ formulaInfos5,
+ formulaInfos6,
+ formulaInfos7,
+ formulaInfos8,
+ formulaInfos9,
+ formulaInfos10,
+ formulaInfos11,
+ formulaInfos12,
+ formulaInfos13,
+ formulaInfos14,
+ formulaInfos15);
+ }
+
+ @Override
+ protected List getUpdatedFormulaInfos() {
+ FormulaInfos formulaInfos1 = getFormulaInfo(TwoWindingsTransformerField.TARGET_V.name(),
+ List.of(filter3),
+ Operator.PERCENTAGE,
+ ReferenceFieldOrValue.builder().value(200.).build(),
+ ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.TARGET_V.name()).build());
+
+ FormulaInfos formulaInfos2 = getFormulaInfo(TwoWindingsTransformerField.RATIO_TAP_POSITION.name(),
+ List.of(filter2),
+ Operator.MULTIPLICATION,
+ ReferenceFieldOrValue.builder().value(3.5).build(),
+ ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.RATIO_TAP_POSITION.name()).build());
+
+ FormulaInfos formulaInfos3 = getFormulaInfo(TwoWindingsTransformerField.RATIO_LOW_TAP_POSITION.name(),
+ List.of(filter1),
+ Operator.MULTIPLICATION,
+ ReferenceFieldOrValue.builder().value(3.).build(),
+ ReferenceFieldOrValue.builder().equipmentField(TwoWindingsTransformerField.RATIO_LOW_TAP_POSITION.name()).build());
+
+ return List.of(formulaInfos1,
+ formulaInfos2,
+ formulaInfos3);
+ }
+
+ @Override
+ protected IdentifiableType getIdentifiableType() {
+ return IdentifiableType.TWO_WINDINGS_TRANSFORMER;
+ }
+
+ @Override
+ protected void assertAfterNetworkModificationCreation() {
+ TwoWindingsTransformer twt1 = getNetwork().getTwoWindingsTransformer(TWT_ID_1);
+ RatioTapChanger ratioTapChanger1 = twt1.getRatioTapChanger();
+ assertNotNull(ratioTapChanger1);
+ assertEquals(100, ratioTapChanger1.getTargetV(), 0);
+ assertEquals(1, ratioTapChanger1.getLowTapPosition());
+ assertEquals(4, ratioTapChanger1.getTapPosition());
+ assertEquals(11, ratioTapChanger1.getTargetDeadband(), 0);
+ assertEquals(60, twt1.getX(), 0);
+ assertEquals(150, twt1.getB(), 0);
+ assertEquals(60, twt1.getR(), 0);
+ assertEquals(75, twt1.getG(), 0);
+ assertEquals(25, twt1.getRatedU1(), 0);
+ assertEquals(10, twt1.getRatedU2(), 0);
+ assertEquals(44, twt1.getRatedS(), 0);
+
+ TwoWindingsTransformer twt2 = getNetwork().getTwoWindingsTransformer(TWT_ID_2);
+ RatioTapChanger ratioTapChanger2 = twt2.getRatioTapChanger();
+ assertNotNull(ratioTapChanger2);
+ assertEquals(106, ratioTapChanger2.getTargetV(), 0);
+ assertEquals(3, ratioTapChanger2.getLowTapPosition());
+ assertEquals(4, ratioTapChanger2.getTapPosition());
+ assertEquals(11.6, ratioTapChanger2.getTargetDeadband(), 0);
+ assertEquals(65, twt2.getX(), 0);
+ assertEquals(162.5, twt2.getB(), 0);
+ assertEquals(15, twt2.getRatedU1(), 0);
+ assertEquals(20, twt2.getRatedS(), 0);
+
+ TwoWindingsTransformer twt3 = getNetwork().getTwoWindingsTransformer(TWT_ID_3);
+ RatioTapChanger ratioTapChanger3 = twt3.getRatioTapChanger();
+ assertNotNull(ratioTapChanger3);
+ assertEquals(1, ratioTapChanger3.getLowTapPosition());
+ assertEquals(4, ratioTapChanger3.getTapPosition());
+ assertEquals(80, twt3.getR(), 0);
+ assertEquals(85, twt3.getG(), 0);
+ assertEquals(35, twt3.getRatedU1(), 0);
+ assertEquals(15, twt3.getRatedU2(), 0);
+ assertEquals(50, twt3.getRatedS(), 0);
+
+ TwoWindingsTransformer twt4 = getNetwork().getTwoWindingsTransformer(TWT_ID_4);
+ PhaseTapChanger phaseTapChanger4 = twt4.getPhaseTapChanger();
+ assertNotNull(phaseTapChanger4);
+ assertEquals(90, phaseTapChanger4.getRegulationValue(), 0);
+ assertEquals(2, phaseTapChanger4.getLowTapPosition());
+ assertEquals(4, phaseTapChanger4.getTapPosition());
+ assertEquals(24, phaseTapChanger4.getTargetDeadband(), 0);
+ assertEquals(90, twt4.getR(), 0);
+ assertEquals(75, twt4.getX(), 0);
+ assertEquals(90, twt4.getG(), 0);
+ assertEquals(187.5, twt4.getB(), 0);
+ assertEquals(25, twt4.getRatedU1(), 0);
+ assertEquals(17.5, twt4.getRatedU2(), 0);
+ assertEquals(15, twt4.getRatedS(), 0);
+
+ TwoWindingsTransformer twt5 = getNetwork().getTwoWindingsTransformer(TWT_ID_5);
+ PhaseTapChanger phaseTapChanger5 = twt5.getPhaseTapChanger();
+ assertNotNull(phaseTapChanger4);
+ assertEquals(4, phaseTapChanger5.getLowTapPosition());
+ assertEquals(4, phaseTapChanger5.getTapPosition());
+ assertEquals(100, twt5.getR(), 0);
+ assertEquals(200, twt5.getB(), 0);
+ assertEquals(20, twt5.getRatedU2(), 0);
+
+ TwoWindingsTransformer twt6 = getNetwork().getTwoWindingsTransformer(TWT_ID_6);
+ PhaseTapChanger phaseTapChanger6 = twt6.getPhaseTapChanger();
+ assertNotNull(phaseTapChanger4);
+ assertEquals(94, phaseTapChanger6.getRegulationValue(), 0);
+ assertEquals(26, phaseTapChanger6.getTargetDeadband(), 0);
+ assertEquals(85, twt6.getX(), 0);
+ assertEquals(100, twt6.getG(), 0);
+ }
+
+ @Override
+ protected void assertAfterNetworkModificationDeletion() {
+ TwoWindingsTransformer twt1 = getNetwork().getTwoWindingsTransformer(TWT_ID_1);
+ RatioTapChanger ratioTapChanger1 = twt1.getRatioTapChanger();
+ assertNotNull(ratioTapChanger1);
+ assertEquals(50, ratioTapChanger1.getTargetV(), 0);
+ assertEquals(0, ratioTapChanger1.getLowTapPosition());
+ assertEquals(1, ratioTapChanger1.getTapPosition());
+ assertEquals(55, ratioTapChanger1.getTargetDeadband(), 0);
+ assertEquals(40, twt1.getX(), 0);
+ assertEquals(60, twt1.getB(), 0);
+ assertEquals(30, twt1.getR(), 0);
+ assertEquals(50, twt1.getG(), 0);
+ assertEquals(10, twt1.getRatedU1(), 0);
+ assertEquals(20, twt1.getRatedU2(), 0);
+ assertEquals(11, twt1.getRatedS(), 0);
+
+ TwoWindingsTransformer twt2 = getNetwork().getTwoWindingsTransformer(TWT_ID_2);
+ RatioTapChanger ratioTapChanger2 = twt2.getRatioTapChanger();
+ assertNotNull(ratioTapChanger2);
+ assertEquals(53, ratioTapChanger2.getTargetV(), 0);
+ assertEquals(3, ratioTapChanger2.getLowTapPosition());
+ assertEquals(4, ratioTapChanger2.getTapPosition());
+ assertEquals(58, ratioTapChanger2.getTargetDeadband(), 0);
+ assertEquals(45, twt2.getX(), 0);
+ assertEquals(65, twt2.getB(), 0);
+ assertEquals(15, twt2.getRatedU1(), 0);
+ assertEquals(10, twt2.getRatedS(), 0);
+
+ TwoWindingsTransformer twt3 = getNetwork().getTwoWindingsTransformer(TWT_ID_3);
+ RatioTapChanger ratioTapChanger3 = twt3.getRatioTapChanger();
+ assertNotNull(ratioTapChanger3);
+ assertEquals(0, ratioTapChanger3.getLowTapPosition());
+ assertEquals(1, ratioTapChanger3.getTapPosition());
+ assertEquals(40, twt3.getR(), 0);
+ assertEquals(60, twt3.getG(), 0);
+ assertEquals(20, twt3.getRatedU1(), 0);
+ assertEquals(30, twt3.getRatedU2(), 0);
+ assertEquals(25, twt3.getRatedS(), 0);
+
+ TwoWindingsTransformer twt4 = getNetwork().getTwoWindingsTransformer(TWT_ID_4);
+ PhaseTapChanger phaseTapChanger4 = twt4.getPhaseTapChanger();
+ assertNotNull(phaseTapChanger4);
+ assertEquals(45, phaseTapChanger4.getRegulationValue(), 0);
+ assertEquals(1, phaseTapChanger4.getLowTapPosition());
+ assertEquals(2, phaseTapChanger4.getTapPosition());
+ assertEquals(34, phaseTapChanger4.getTargetDeadband(), 0);
+ assertEquals(45, twt4.getR(), 0);
+ assertEquals(55, twt4.getX(), 0);
+ assertEquals(65, twt4.getG(), 0);
+ assertEquals(75, twt4.getB(), 0);
+ assertEquals(25, twt4.getRatedU1(), 0);
+ assertEquals(35, twt4.getRatedU2(), 0);
+ assertEquals(15, twt4.getRatedS(), 0);
+
+ TwoWindingsTransformer twt5 = getNetwork().getTwoWindingsTransformer(TWT_ID_5);
+ PhaseTapChanger phaseTapChanger5 = twt5.getPhaseTapChanger();
+ assertNotNull(phaseTapChanger4);
+ assertEquals(2, phaseTapChanger5.getLowTapPosition());
+ assertEquals(2, phaseTapChanger5.getTapPosition());
+ assertEquals(50, twt5.getR(), 0);
+ assertEquals(80, twt5.getB(), 0);
+ assertEquals(40, twt5.getRatedU2(), 0);
+
+ TwoWindingsTransformer twt6 = getNetwork().getTwoWindingsTransformer(TWT_ID_6);
+ PhaseTapChanger phaseTapChanger6 = twt6.getPhaseTapChanger();
+ assertNotNull(phaseTapChanger4);
+ assertEquals(47, phaseTapChanger6.getRegulationValue(), 0);
+ assertEquals(36, phaseTapChanger6.getTargetDeadband(), 0);
+ assertEquals(65, twt6.getX(), 0);
+ assertEquals(75, twt6.getG(), 0);
+ }
+
+ private void addRatioTapChangerSteps(RatioTapChangerAdder ratioTapChangerAdder) {
+ ratioTapChangerAdder.beginStep()
+ .setR(39.78473)
+ .setX(39.784725)
+ .setG(0.0)
+ .setB(0.0)
+ .setRho(15.0)
+ .endStep()
+ .beginStep()
+ .setR(39.78474)
+ .setX(39.784726)
+ .setG(0.0)
+ .setB(0.0)
+ .setRho(15.0)
+ .endStep()
+ .beginStep()
+ .setR(39.78473)
+ .setX(39.784725)
+ .setG(0.0)
+ .setB(0.0)
+ .setRho(15.0)
+ .endStep()
+ .beginStep()
+ .setR(39.78474)
+ .setX(39.784726)
+ .setG(0.0)
+ .setB(0.0)
+ .setRho(15.0)
+ .endStep()
+ .beginStep()
+ .setR(39.78473)
+ .setX(39.784725)
+ .setG(0.0)
+ .setB(0.0)
+ .setRho(5.0)
+ .endStep()
+ .beginStep()
+ .setR(39.78474)
+ .setX(39.784726)
+ .setG(0.0)
+ .setB(0.0)
+ .setRho(15.0)
+ .endStep()
+ .add();
+ }
+
+ private void addPhaseTapChangerSteps(PhaseTapChangerAdder phaseTapChangerAdder) {
+ phaseTapChangerAdder.beginStep()
+ .setR(39.78473)
+ .setX(39.784725)
+ .setG(0.0)
+ .setB(0.0)
+ .setRho(15.0)
+ .setAlpha(1.)
+ .endStep()
+ .beginStep()
+ .setR(39.78475)
+ .setX(39.784727)
+ .setG(0.0)
+ .setB(0.0)
+ .setRho(15.0)
+ .setAlpha(1.1)
+ .endStep()
+ .beginStep()
+ .setR(39.78473)
+ .setX(39.784725)
+ .setG(0.0)
+ .setB(0.0)
+ .setRho(15.0)
+ .setAlpha(1.)
+ .endStep()
+ .beginStep()
+ .setR(39.78475)
+ .setX(39.784727)
+ .setG(0.0)
+ .setB(0.0)
+ .setRho(15.0)
+ .setAlpha(1.1)
+ .endStep()
+ .beginStep()
+ .setR(39.78473)
+ .setX(39.784725)
+ .setG(0.0)
+ .setB(0.0)
+ .setRho(15.0)
+ .setAlpha(1.)
+ .endStep()
+ .beginStep()
+ .setR(39.78475)
+ .setX(39.784727)
+ .setG(0.0)
+ .setB(0.0)
+ .setRho(15.0)
+ .setAlpha(1.1)
+ .endStep()
+ .add();
+ }
+}
diff --git a/src/test/java/org/gridsuite/modification/server/modifications/tabularmodifications/TabularVoltageLevelModificationsTest.java b/src/test/java/org/gridsuite/modification/server/modifications/tabularmodifications/TabularVoltageLevelModificationsTest.java
new file mode 100644
index 000000000..4851d64d5
--- /dev/null
+++ b/src/test/java/org/gridsuite/modification/server/modifications/tabularmodifications/TabularVoltageLevelModificationsTest.java
@@ -0,0 +1,96 @@
+/**
+ * Copyright (c) 2023, RTE (http://www.rte-france.com)
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+package org.gridsuite.modification.server.modifications.tabularmodifications;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.powsybl.iidm.network.Network;
+import lombok.SneakyThrows;
+import org.gridsuite.modification.server.dto.*;
+import org.gridsuite.modification.server.modifications.AbstractNetworkModificationTest;
+import org.gridsuite.modification.server.utils.NetworkCreation;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Tag;
+
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author AJELLAL Ali
+ */
+@Tag("IntegrationTest")
+public class TabularVoltageLevelModificationsTest extends AbstractNetworkModificationTest {
+ @Override
+ protected Network createNetwork(UUID networkUuid) {
+ return NetworkCreation.create(networkUuid, true);
+ }
+
+ @Override
+ protected ModificationInfos buildModification() {
+ List modifications = List.of(
+ VoltageLevelModificationInfos.builder().equipmentId("v1").nominalVoltage(new AttributeModification<>(300., OperationType.SET)).highVoltageLimit(new AttributeModification<>(400., OperationType.SET)).lowVoltageLimit(new AttributeModification<>(299., OperationType.SET)).build(),
+ VoltageLevelModificationInfos.builder().equipmentId("v2").nominalVoltage(new AttributeModification<>(300., OperationType.SET)).highVoltageLimit(new AttributeModification<>(400., OperationType.SET)).lowVoltageLimit(new AttributeModification<>(299., OperationType.SET)).build()
+ );
+ return TabularModificationInfos.builder()
+ .modificationType("VOLTAGE_LEVEL_MODIFICATION")
+ .modifications(modifications)
+ .stashed(false)
+ .build();
+ }
+
+ @Override
+ protected ModificationInfos buildModificationUpdate() {
+ List modifications = List.of(
+ VoltageLevelModificationInfos.builder().equipmentId("v1").nominalVoltage(new AttributeModification<>(500., OperationType.SET)).highVoltageLimit(new AttributeModification<>(502., OperationType.SET)).lowVoltageLimit(new AttributeModification<>(499., OperationType.SET)).build(),
+ VoltageLevelModificationInfos.builder().equipmentId("v2").nominalVoltage(new AttributeModification<>(500., OperationType.SET)).highVoltageLimit(new AttributeModification<>(502., OperationType.SET)).lowVoltageLimit(new AttributeModification<>(499., OperationType.SET)).build()
+ );
+ return TabularModificationInfos.builder()
+ .modificationType("VOLTAGE_LEVEL_MODIFICATION")
+ .modifications(modifications)
+ .stashed(false)
+ .build();
+ }
+
+ @Override
+ protected void assertAfterNetworkModificationCreation() {
+ assertEquals(300., getNetwork().getVoltageLevel("v1").getNominalV(), 0.001);
+ assertEquals(299., getNetwork().getVoltageLevel("v1").getLowVoltageLimit(), 0.001);
+ assertEquals(400., getNetwork().getVoltageLevel("v1").getHighVoltageLimit(), 0.001);
+ assertEquals(300., getNetwork().getVoltageLevel("v2").getNominalV(), 0.001);
+ assertEquals(299., getNetwork().getVoltageLevel("v2").getLowVoltageLimit(), 0.001);
+ assertEquals(400., getNetwork().getVoltageLevel("v2").getHighVoltageLimit(), 0.001);
+ }
+
+ @Override
+ protected void assertAfterNetworkModificationDeletion() {
+ assertEquals(380.0, getNetwork().getVoltageLevel("v1").getNominalV(), 0.001);
+ assertEquals(Double.NaN, getNetwork().getVoltageLevel("v1").getLowVoltageLimit(), 0.001);
+ assertEquals(Double.NaN, getNetwork().getVoltageLevel("v1").getHighVoltageLimit(), 0.001);
+ assertEquals(225.0, getNetwork().getVoltageLevel("v2").getNominalV(), 0.001);
+ assertEquals(Double.NaN, getNetwork().getVoltageLevel("v2").getLowVoltageLimit(), 0.001);
+ assertEquals(Double.NaN, getNetwork().getVoltageLevel("v2").getHighVoltageLimit(), 0.001);
+ }
+
+ @Override
+ @SneakyThrows
+ protected void testCreationModificationMessage(ModificationInfos modificationInfos) {
+ assertEquals("TABULAR_MODIFICATION", modificationInfos.getMessageType());
+ Map createdValues = mapper.readValue(modificationInfos.getMessageValues(), new TypeReference<>() { });
+ Assertions.assertEquals("VOLTAGE_LEVEL_MODIFICATION", createdValues.get("tabularModificationType"));
+ }
+
+ @Override
+ @SneakyThrows
+ protected void testUpdateModificationMessage(ModificationInfos modificationInfos) {
+ assertEquals("TABULAR_MODIFICATION", modificationInfos.getMessageType());
+ Map updatedValues = mapper.readValue(modificationInfos.getMessageValues(), new TypeReference<>() { });
+ Assertions.assertEquals("VOLTAGE_LEVEL_MODIFICATION", updatedValues.get("tabularModificationType"));
+ }
+}
diff --git a/src/test/java/org/gridsuite/modification/server/service/ModificationElasticsearchTest.java b/src/test/java/org/gridsuite/modification/server/service/ModificationElasticsearchTest.java
new file mode 100644
index 000000000..100265029
--- /dev/null
+++ b/src/test/java/org/gridsuite/modification/server/service/ModificationElasticsearchTest.java
@@ -0,0 +1,147 @@
+package org.gridsuite.modification.server.service;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.powsybl.iidm.network.LoadType;
+import com.powsybl.iidm.network.Network;
+import com.powsybl.iidm.network.VariantManagerConstants;
+import com.powsybl.network.store.client.NetworkStoreService;
+import com.powsybl.network.store.client.PreloadingStrategy;
+import org.gridsuite.modification.server.dto.LoadCreationInfos;
+import org.gridsuite.modification.server.dto.LoadModificationInfos;
+import org.gridsuite.modification.server.dto.VoltageLevelModificationInfos;
+import org.gridsuite.modification.server.elasticsearch.EquipmentInfosRepository;
+import org.gridsuite.modification.server.elasticsearch.EquipmentInfosService;
+import org.gridsuite.modification.server.repositories.ModificationRepository;
+import org.gridsuite.modification.server.utils.ModificationCreation;
+import org.gridsuite.modification.server.utils.NetworkCreation;
+import org.junit.Before;
+import org.junit.jupiter.api.Tag;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.stubbing.Answer;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+
+import java.util.List;
+import java.util.UUID;
+
+import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@RunWith(SpringRunner.class)
+@AutoConfigureMockMvc
+@SpringBootTest
+@Tag("IntegrationTest")
+public class ModificationElasticsearchTest {
+ private static UUID NETWORK_UUID = UUID.randomUUID();
+ private static final UUID TEST_GROUP_ID = UUID.randomUUID();
+ private static final UUID TEST_REPORT_ID = UUID.randomUUID();
+ private static final String URI_NETWORK_MODIF_BASE = "/v1/network-modifications";
+ private static final String URI_NETWORK_MODIF_PARAMS = "&groupUuid=" + TEST_GROUP_ID + "&reportUuid=" + TEST_REPORT_ID + "&reporterId=" + UUID.randomUUID();
+ private static final String URI_NETWORK_MODIF = URI_NETWORK_MODIF_BASE + "?networkUuid=" + NETWORK_UUID + URI_NETWORK_MODIF_PARAMS;
+
+ private static final String NEW_VARIANT = "NewVariant";
+ private static final String NEW_VARIANT_2 = "NewVariant2";
+
+ @Autowired
+ MockMvc mockMvc;
+
+ @Autowired
+ private ObjectMapper mapper;
+
+ @Autowired
+ EquipmentInfosService equipmentInfosService;
+
+ @Autowired
+ ModificationRepository modificationRepository;
+
+ @MockBean
+ NetworkStoreService networkStoreService;
+
+ @MockBean
+ ReportService reportService;
+
+ @Autowired
+ private EquipmentInfosRepository equipmentInfosRepository;
+
+ Network network;
+
+ @Before
+ public void setUp() {
+ network = NetworkCreation.create(NETWORK_UUID, true);
+ when(networkStoreService.getNetwork(eq(NETWORK_UUID), nullable(PreloadingStrategy.class))).then((Answer) invocation -> network);
+
+ // clean DB
+ modificationRepository.deleteAll();
+ equipmentInfosService.deleteAll();
+ }
+
+ @Test
+ public void testModificationsToImpactElasticsearch() throws Exception {
+ network.getVariantManager().cloneVariant(VariantManagerConstants.INITIAL_VARIANT_ID, NEW_VARIANT);
+ network.getVariantManager().setWorkingVariant(NEW_VARIANT);
+
+ // load creation - assert name and vl name values
+ LoadCreationInfos loadCreationInfos = ModificationCreation.getCreationLoad("v1", "v1Load", "v1load_name", "1.1", LoadType.UNDEFINED);
+ String loadCreationJson = mapper.writeValueAsString(loadCreationInfos);
+ mockMvc.perform(post(URI_NETWORK_MODIF).content(loadCreationJson).contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andReturn();
+ assertEquals("v1load_name", equipmentInfosRepository.findByIdInAndNetworkUuidAndVariantId(List.of("v1Load"), NETWORK_UUID, NEW_VARIANT).get(0).getName());
+ assertTrue(equipmentInfosRepository.findByIdInAndNetworkUuidAndVariantId(List.of("v1Load"), NETWORK_UUID, NEW_VARIANT).get(0).getVoltageLevels().stream().anyMatch(vl -> vl.getName().equals("v1")));
+
+ // load modification - assert name modification
+ LoadModificationInfos loadModification = ModificationCreation.getModificationLoad("v1Load", null, "v1load_newname", null, null, null, null);
+ String loadModificationJson = mapper.writeValueAsString(loadModification);
+ mockMvc.perform(post(URI_NETWORK_MODIF).content(loadModificationJson).contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andReturn();
+ assertEquals("v1load_newname", equipmentInfosRepository.findByIdInAndNetworkUuidAndVariantId(List.of("v1Load"), NETWORK_UUID, NEW_VARIANT).get(0).getName());
+ }
+
+ @Test
+ public void testVLModificationsToImpactElasticsearch() throws Exception {
+ network.getVariantManager().cloneVariant(VariantManagerConstants.INITIAL_VARIANT_ID, NEW_VARIANT);
+ network.getVariantManager().setWorkingVariant(NEW_VARIANT);
+
+ // vl modification - assert vl name modification, linked load modification and parent subsation modification
+ VoltageLevelModificationInfos vlModification = ModificationCreation.getModificationVoltageLevel("v1", "v1_newname");
+ String vlModificationJson = mapper.writeValueAsString(vlModification);
+ mockMvc.perform(post(URI_NETWORK_MODIF).content(vlModificationJson).contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andReturn();
+
+ checkSomeEquipmentsVoltageLevel(NETWORK_UUID, NEW_VARIANT, "v1_newname");
+
+ // in a new variant, load modification - assert name modification - assert old data are still here
+ network.getVariantManager().cloneVariant(NEW_VARIANT, NEW_VARIANT_2);
+ network.getVariantManager().setWorkingVariant(NEW_VARIANT_2);
+ // vl modification - assert vl name modification, linked load modification and parent subsation modification
+ VoltageLevelModificationInfos vlModification2 = ModificationCreation.getModificationVoltageLevel("v1", "v1_newname_2");
+ String vlModification2Json = mapper.writeValueAsString(vlModification2);
+ mockMvc.perform(post(URI_NETWORK_MODIF).content(vlModification2Json).contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andReturn();
+
+ checkSomeEquipmentsVoltageLevel(NETWORK_UUID, NEW_VARIANT, "v1_newname");
+ checkSomeEquipmentsVoltageLevel(NETWORK_UUID, NEW_VARIANT_2, "v1_newname_2");
+ }
+
+ private void checkSomeEquipmentsVoltageLevel(UUID networkUuid, String variantId, String voltageLevelName) {
+ // assert targeted voltage level has been updated
+ assertEquals(voltageLevelName, equipmentInfosRepository.findByIdInAndNetworkUuidAndVariantId(List.of("v1"), networkUuid, variantId).get(0).getName());
+
+ // assert linked load has been updated (linked connectable)
+ assertTrue(checkEquipmentHasVoltageLevelWithName(networkUuid, variantId, "v1Load", voltageLevelName));
+
+ // assert linked switch has been updated (linked equipment which is not a connectable)
+ assertTrue(checkEquipmentHasVoltageLevelWithName(networkUuid, variantId, "v1dlcc", voltageLevelName));
+
+ // assert parent substation has been updated
+ assertTrue(checkEquipmentHasVoltageLevelWithName(networkUuid, variantId, "s1", voltageLevelName));
+ }
+
+ private boolean checkEquipmentHasVoltageLevelWithName(UUID networkUuid, String variantId, String equipmentId, String voltageLevelName) {
+ return equipmentInfosRepository.findByIdInAndNetworkUuidAndVariantId(List.of(equipmentId), networkUuid, variantId).get(0).getVoltageLevels().stream().anyMatch(vl -> vl.getName().equals(voltageLevelName));
+ }
+}
diff --git a/src/test/java/org/gridsuite/modification/server/utils/ModificationCreation.java b/src/test/java/org/gridsuite/modification/server/utils/ModificationCreation.java
index ca7b82248..76f661ec4 100644
--- a/src/test/java/org/gridsuite/modification/server/utils/ModificationCreation.java
+++ b/src/test/java/org/gridsuite/modification/server/utils/ModificationCreation.java
@@ -8,6 +8,7 @@
package org.gridsuite.modification.server.utils;
import com.powsybl.iidm.network.EnergySource;
+import com.powsybl.iidm.network.LoadType;
import com.powsybl.iidm.network.SwitchKind;
import com.powsybl.iidm.network.extensions.ConnectablePosition;
import org.gridsuite.modification.server.dto.*;
@@ -94,4 +95,61 @@ public static GeneratorCreationInfos getCreationGenerator(String vlId, String ge
.connectionDirection(ConnectablePosition.Direction.TOP)
.build();
}
+
+ public static LoadCreationInfos getCreationLoad(String vlId, String loadId, String loadName, String busOrBusBarSectionId, LoadType loadType) {
+ return LoadCreationInfos.builder()
+ .stashed(false)
+ .equipmentId(loadId)
+ .equipmentName(loadName)
+ .voltageLevelId(vlId)
+ .busOrBusbarSectionId(busOrBusBarSectionId)
+ .loadType(loadType)
+ .activePower(100.0)
+ .reactivePower(20.0)
+ .connectionName("top")
+ .connectionDirection(ConnectablePosition.Direction.TOP)
+ .build();
+ }
+
+ public static LoadModificationInfos getModificationLoad(String loadId, String vlId, String loadName, String busOrBusbarSectionId, LoadType loadType, Long activePower, Long reactivePower) {
+ LoadModificationInfos.LoadModificationInfosBuilder builder = LoadModificationInfos.builder()
+ .stashed(false)
+ .equipmentId(loadId);
+
+ if (loadName != null) {
+ builder.equipmentName(AttributeModification.toAttributeModification(loadName, OperationType.SET));
+ }
+
+ if (vlId != null) {
+ builder.voltageLevelId(AttributeModification.toAttributeModification(vlId, OperationType.SET));
+ }
+
+ if (busOrBusbarSectionId != null) {
+ builder.busOrBusbarSectionId(AttributeModification.toAttributeModification(busOrBusbarSectionId, OperationType.SET));
+ }
+
+ if (loadType != null) {
+ builder.loadType(AttributeModification.toAttributeModification(LoadType.UNDEFINED, OperationType.SET));
+ }
+
+ if (activePower != null) {
+ builder.activePower(AttributeModification.toAttributeModification(activePower, OperationType.SET));
+ }
+
+ if (reactivePower != null) {
+ builder.reactivePower(AttributeModification.toAttributeModification(reactivePower, OperationType.SET));
+ }
+
+ return builder.build();
+ }
+
+ public static VoltageLevelModificationInfos getModificationVoltageLevel(String vlId, String vlName) {
+ VoltageLevelModificationInfos.VoltageLevelModificationInfosBuilder builder = VoltageLevelModificationInfos.builder()
+ .stashed(false)
+ .equipmentId(vlId);
+
+ builder.equipmentName(AttributeModification.toAttributeModification(vlName, OperationType.SET));
+
+ return builder.build();
+ }
}
diff --git a/src/test/resources/reports_voltage_init_modification_ok.json b/src/test/resources/reports_voltage_init_modification_ok.json
index 9b310afa4..5c988de58 100644
--- a/src/test/resources/reports_voltage_init_modification_ok.json
+++ b/src/test/resources/reports_voltage_init_modification_ok.json
@@ -4,8 +4,7 @@
"taskKey" : "99999999-9999-9999-9999-999999999999@NetworkModification",
"subReporters" : [ {
"taskKey" : "VOLTAGE_INIT_MODIFICATION",
- "reports" : [
- {
+ "reports" : [ {
"reportKey" : "generatorModificationsResume",
"values" : {
"reportSeverity" : {
@@ -62,14 +61,8 @@
}
} ],
"subReporters" : [ {
- "taskKey" : "GeneratorModifications",
- "taskValues" : {
- "generatorId" : {
- "value" : "GTH2"
- }
- },
- "reports" : [
- {
+ "taskKey" : "GeneratorsModifications",
+ "reports" : [ {
"reportKey" : "generatorModification",
"values" : {
"reportSeverity" : {
@@ -99,14 +92,8 @@
}
} ]
}, {
- "taskKey" : "2WindingsTransformerModifications",
- "taskValues" : {
- "transformerId" : {
- "value" : "TWT2"
- }
- },
- "reports" : [
- {
+ "taskKey" : "2WindingsTransformersModifications",
+ "reports" : [ {
"reportKey" : "2WindingsTransformerModification",
"values" : {
"reportSeverity" : {
@@ -136,12 +123,7 @@
}
} ]
}, {
- "taskKey" : "StaticVarCompensatorModifications",
- "taskValues" : {
- "compensatorId" : {
- "value" : "SVC"
- }
- },
+ "taskKey" : "StaticVarCompensatorsModifications",
"reports" : [ {
"reportKey" : "staticVarCompensatorModification",
"values" : {
@@ -172,12 +154,7 @@
}
} ]
}, {
- "taskKey" : "ShuntCompensatorModifications",
- "taskValues" : {
- "compensatorId" : {
- "value" : "SHUNT3"
- }
- },
+ "taskKey" : "ShuntCompensatorsModifications",
"reports" : [ {
"reportKey" : "shuntCompensatorModification",
"values" : {
@@ -216,12 +193,7 @@
}
} ]
}, {
- "taskKey" : "VscConverterStationModifications",
- "taskValues" : {
- "converterId" : {
- "value" : "VSC2"
- }
- },
+ "taskKey" : "VscConverterStationsModifications",
"reports" : [ {
"reportKey" : "vscConverterStationModification",
"values" : {
@@ -259,22 +231,22 @@
"99999999-9999-9999-9999-999999999999@NetworkModification" : "99999999-9999-9999-9999-999999999999@NetworkModification",
"VOLTAGE_INIT_MODIFICATION" : "Voltage init modification",
"modification-indent1" : "\t${fieldName} : ${oldValue} → ${newValue}",
- "GeneratorModifications" : "Generator ${generatorId}",
+ "GeneratorsModifications" : "Generators",
"generatorModification" : "Generator with id=${id} modified :",
"generatorModificationsResume" : "${count} generator(s) have been modified.",
- "2WindingsTransformerModifications" : "2 windings transformer ${transformerId}",
+ "2WindingsTransformersModifications" : "2 windings transformers",
"2WindingsTransformerModification" : "2 windings transformer with id=${id} modified :",
"windingsTransformerModificationsResume" : "${count} transformer(s) have been modified.",
- "VscConverterStationModifications" : "Vsc converter station ${converterId}",
+ "VscConverterStationsModifications" : "Vsc converter stations",
"vscConverterStationModification" : "Vsc converter station with id=${id} modified :",
"vscModificationsResume" : "${count} vsc converter station(s) have been modified.",
- "StaticVarCompensatorModifications" : "Static var compensator ${compensatorId}",
+ "StaticVarCompensatorsModifications" : "Static var compensators",
"staticVarCompensatorModification" : "Static var compensator with id=${id} modified :",
"svcModificationsResume" : "${count} static var compensator(s) have been modified.",
- "ShuntCompensatorModifications" : "Shunt compensator ${compensatorId}",
+ "ShuntCompensatorsModifications" : "Shunt compensators",
"shuntCompensatorModification" : "Shunt compensator with id=${id} modified :",
"shuntCompensatorDisconnected" : "\tShunt compensator disconnected",
"shuntCompensatorModificationsResume" : "${count} shunt compensator(s) have been modified."
}
}
-}
\ No newline at end of file
+}
diff --git a/src/test/resources/reports_voltage_init_modification_warnings.json b/src/test/resources/reports_voltage_init_modification_warnings.json
index 0bec6b04d..eb34fd432 100644
--- a/src/test/resources/reports_voltage_init_modification_warnings.json
+++ b/src/test/resources/reports_voltage_init_modification_warnings.json
@@ -28,12 +28,7 @@
}
} ],
"subReporters" : [ {
- "taskKey" : "GeneratorModifications",
- "taskValues" : {
- "generatorId" : {
- "value" : "G1"
- }
- },
+ "taskKey" : "GeneratorsModifications",
"reports" : [ {
"reportKey" : "generatorNotFound",
"values" : {
@@ -45,15 +40,7 @@
"value" : "G1"
}
}
- } ]
- }, {
- "taskKey" : "GeneratorModifications",
- "taskValues" : {
- "generatorId" : {
- "value" : "G2"
- }
- },
- "reports" : [ {
+ }, {
"reportKey" : "generatorNotFound",
"values" : {
"reportSeverity" : {
@@ -66,12 +53,7 @@
}
} ]
}, {
- "taskKey" : "2WindingsTransformerModifications",
- "taskValues" : {
- "transformerId" : {
- "value" : "2WT1"
- }
- },
+ "taskKey" : "2WindingsTransformersModifications",
"reports" : [ {
"reportKey" : "2WindingsTransformerNotFound",
"values" : {
@@ -85,12 +67,7 @@
}
} ]
}, {
- "taskKey" : "3WindingsTransformerModifications",
- "taskValues" : {
- "transformerId" : {
- "value" : "3WT1"
- }
- },
+ "taskKey" : "3WindingsTransformersModifications",
"reports" : [ {
"reportKey" : "3WindingsTransformerNotFound",
"values" : {
@@ -104,12 +81,7 @@
}
} ]
}, {
- "taskKey" : "StaticVarCompensatorModifications",
- "taskValues" : {
- "compensatorId" : {
- "value" : "SVC1"
- }
- },
+ "taskKey" : "StaticVarCompensatorsModifications",
"reports" : [ {
"reportKey" : "staticVarCompensatorNotFound",
"values" : {
@@ -121,15 +93,7 @@
"value" : "SVC1"
}
}
- } ]
- }, {
- "taskKey" : "StaticVarCompensatorModifications",
- "taskValues" : {
- "compensatorId" : {
- "value" : "SVC2"
- }
- },
- "reports" : [ {
+ }, {
"reportKey" : "staticVarCompensatorNotFound",
"values" : {
"reportSeverity" : {
@@ -142,12 +106,7 @@
}
} ]
}, {
- "taskKey" : "ShuntCompensatorModifications",
- "taskValues" : {
- "compensatorId" : {
- "value" : "v2shunt"
- }
- },
+ "taskKey" : "ShuntCompensatorsModifications",
"reports" : [ {
"reportKey" : "shuntCompensatorNotFound",
"values" : {
@@ -159,15 +118,7 @@
"value" : "v2shunt"
}
}
- } ]
- }, {
- "taskKey" : "ShuntCompensatorModifications",
- "taskValues" : {
- "compensatorId" : {
- "value" : "v5shunt"
- }
- },
- "reports" : [ {
+ }, {
"reportKey" : "shuntCompensatorNotFound",
"values" : {
"reportSeverity" : {
@@ -178,15 +129,7 @@
"value" : "v5shunt"
}
}
- } ]
- }, {
- "taskKey" : "ShuntCompensatorModifications",
- "taskValues" : {
- "compensatorId" : {
- "value" : "v6shunt"
- }
- },
- "reports" : [ {
+ }, {
"reportKey" : "shuntCompensatorNotFound",
"values" : {
"reportSeverity" : {
@@ -199,12 +142,7 @@
}
} ]
}, {
- "taskKey" : "VscConverterStationModifications",
- "taskValues" : {
- "converterId" : {
- "value" : "VSC1"
- }
- },
+ "taskKey" : "VscConverterStationsModifications",
"reports" : [ {
"reportKey" : "vscConverterStationModification",
"values" : {
@@ -233,15 +171,7 @@
"value" : "500.0"
}
}
- } ]
- }, {
- "taskKey" : "VscConverterStationModifications",
- "taskValues" : {
- "converterId" : {
- "value" : "VSC2"
- }
- },
- "reports" : [ {
+ }, {
"reportKey" : "vscConverterStationModification",
"values" : {
"reportSeverity" : {
@@ -278,20 +208,20 @@
"99999999-9999-9999-9999-999999999999@NetworkModification" : "99999999-9999-9999-9999-999999999999@NetworkModification",
"VOLTAGE_INIT_MODIFICATION" : "Voltage init modification",
"modification-indent1" : "\t${fieldName} : ${oldValue} → ${newValue}",
- "GeneratorModifications" : "Generator ${generatorId}",
+ "GeneratorsModifications" : "Generators",
"generatorNotFound" : "Generator with id=${id} not found",
- "2WindingsTransformerModifications" : "2 windings transformer ${transformerId}",
+ "2WindingsTransformersModifications" : "2 windings transformers",
"2WindingsTransformerNotFound" : "2 windings transformer with id=${id} not found",
- "3WindingsTransformerModifications" : "3 windings transformer ${transformerId}",
+ "3WindingsTransformersModifications" : "3 windings transformers",
"3WindingsTransformerNotFound" : "3 windings transformer with id=${id} not found",
"windingsTransformerModificationsResume" : "${count} transformer(s) have been modified.",
- "VscConverterStationModifications" : "Vsc converter station ${converterId}",
+ "VscConverterStationsModifications" : "Vsc converter stations",
"vscConverterStationModification" : "Vsc converter station with id=${id} modified :",
"vscModificationsResume" : "${count} vsc converter station(s) have been modified.",
- "StaticVarCompensatorModifications" : "Static var compensator ${compensatorId}",
+ "StaticVarCompensatorsModifications" : "Static var compensators",
"staticVarCompensatorNotFound" : "Static var compensator with id=${id} not found",
- "ShuntCompensatorModifications" : "Shunt compensator ${compensatorId}",
+ "ShuntCompensatorsModifications" : "Shunt compensators",
"shuntCompensatorNotFound" : "Shunt compensator with id=${id} not found"
}
}
-}
\ No newline at end of file
+}
diff --git a/src/test/resources/testGenerationDispatchWithBatteries.xiidm b/src/test/resources/testGenerationDispatchWithBatteries.xiidm
new file mode 100644
index 000000000..15a155c09
--- /dev/null
+++ b/src/test/resources/testGenerationDispatchWithBatteries.xiidm
@@ -0,0 +1,314 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/resources/testGenerationDispatchWithMultipleEnergySource.xiidm b/src/test/resources/testGenerationDispatchWithMultipleEnergySource.xiidm
new file mode 100644
index 000000000..c2d6075b0
--- /dev/null
+++ b/src/test/resources/testGenerationDispatchWithMultipleEnergySource.xiidm
@@ -0,0 +1,320 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file