From bf0bc1a07041617eaf3436b0de0d5d1076107126 Mon Sep 17 00:00:00 2001 From: lilian-houdelet <152176499+lilian-houdelet@users.noreply.github.com> Date: Tue, 12 Dec 2023 15:00:56 +0100 Subject: [PATCH 1/3] Round generation dispatch log values (#388) Signed-off-by: Lilian Houdelet --- .../modifications/GenerationDispatch.java | 27 ++++++++++--------- .../modifications/GenerationDispatchTest.java | 8 +++--- 2 files changed, 19 insertions(+), 16 deletions(-) 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 e616db734..dc4a0270f 100644 --- a/src/main/java/org/gridsuite/modification/server/modifications/GenerationDispatch.java +++ b/src/main/java/org/gridsuite/modification/server/modifications/GenerationDispatch.java @@ -306,7 +306,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,17 +493,17 @@ 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; if (totalAmountSupplyToBeDispatched < 0.) { @@ -512,7 +512,7 @@ public void apply(Network network, Reporter subReporter) { 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 @@ -552,18 +552,18 @@ public void apply(Network network, Reporter subReporter) { 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", activePowerSumByEnergySource.values().stream().reduce(0d, Double::sum), - "nuclearSum", activePowerSumByEnergySource.getOrDefault(EnergySource.NUCLEAR, 0d), - "thermalSum", activePowerSumByEnergySource.getOrDefault(EnergySource.THERMAL, 0d), - "hydroSum", activePowerSumByEnergySource.getOrDefault(EnergySource.HYDRO, 0d), - "windAndSolarSum", activePowerSumByEnergySource.getOrDefault(EnergySource.WIND, 0d) + activePowerSumByEnergySource.getOrDefault(EnergySource.SOLAR, 0d), - "otherSum", activePowerSumByEnergySource.getOrDefault(EnergySource.OTHER, 0d) + "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); } } } @@ -616,4 +616,7 @@ private Map getActivePowerSumByEnergySource(List Date: Tue, 12 Dec 2023 17:21:53 +0100 Subject: [PATCH 2/3] Take into account battery balance in generator dispatch (#392) Signed-off-by: David BRAQUART --- .../modifications/GenerationDispatch.java | 14 +- .../modifications/GenerationDispatchTest.java | 91 +++-- .../testGenerationDispatchWithBatteries.xiidm | 314 ++++++++++++++++++ 3 files changed, 398 insertions(+), 21 deletions(-) create mode 100644 src/test/resources/testGenerationDispatchWithBatteries.xiidm 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 dc4a0270f..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<>(); @@ -505,7 +513,11 @@ public void apply(Network network, Reporter subReporter) { report(powerToDispatchReporter, Integer.toString(componentNum), "TotalOutwardHvdcFlow", "The HVDC balance is : ${hvdcBalance} MW", 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); 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 967e75cf4..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,47 @@ 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 (NUCLEAR: 0.0 MW, THERMAL: 0.0 MW, HYDRO: 330.0 MW, WIND AND SOLAR: 0.0 MW, OTHER: 0.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 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 54c724a8d7aca826acfcaff9a569606f74eaa747 Mon Sep 17 00:00:00 2001 From: Antoine Bouhours <123802855+antoinebhs@users.noreply.github.com> Date: Wed, 13 Dec 2023 13:25:29 +0100 Subject: [PATCH 3/3] Share code for modifications exporting filters (#389) Signed-off-by: BOUHOURS Antoine --- .../server/modifications/AbstractScaling.java | 81 +++++-------------- .../modifications/ByFormulaModification.java | 29 +------ .../modifications/ModificationUtils.java | 45 +++++++++++ 3 files changed, 67 insertions(+), 88 deletions(-) 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/ByFormulaModification.java b/src/main/java/org/gridsuite/modification/server/modifications/ByFormulaModification.java index b12f9fd11..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,30 +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.IdentifiableType; -import com.powsybl.iidm.network.Load; -import com.powsybl.iidm.network.Network; -import com.powsybl.iidm.network.ShuntCompensator; -import com.powsybl.iidm.network.TwoWindingsTransformer; -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.TwoWindingsTransformerField; -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.NotNull; -import org.jetbrains.annotations.Nullable; import org.springframework.util.CollectionUtils; import java.util.ArrayList; @@ -83,7 +69,7 @@ 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() @@ -218,15 +204,6 @@ private void createFormulaReports(List formulaReports, FormulaInfos form } } - @Nullable - private Map getUuidFilterEquipmentsMap(Network network, Reporter subReporter, Map filters) { - // export filters from filter server - Map exportFilters = filterService.getUuidFilterEquipmentsMap(network, filters); - - boolean isValidFilter = ModificationUtils.getInstance().isValidFilter(subReporter, modificationInfos.getErrorType(), exportFilters); - return isValidFilter ? exportFilters : null; - } - private boolean isEquipmentEditable(Identifiable identifiable, FormulaInfos formulaInfos) { if (formulaInfos.getEditedField() == 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 a144a16e8..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.*; @@ -1027,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; + } }