From c44acea3e5434c62b45d6c04484a1d4c0588259b Mon Sep 17 00:00:00 2001 From: David BRAQUART Date: Wed, 20 Sep 2023 12:31:49 +0200 Subject: [PATCH 1/4] add some logs (incl TRACE level) Signed-off-by: David BRAQUART --- .../modifications/GenerationDispatch.java | 73 +++++++++++++++++-- 1 file changed, 65 insertions(+), 8 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 5146a609a..647c28fd3 100644 --- a/src/main/java/org/gridsuite/modification/server/modifications/GenerationDispatch.java +++ b/src/main/java/org/gridsuite/modification/server/modifications/GenerationDispatch.java @@ -151,9 +151,9 @@ private static Double getGeneratorMarginalCost(Generator generator) { private static List computeAdjustableGenerators(Network network, Component component, List generatorsWithFixedSupply, List substationsGeneratorsOrderingInfos, Reporter reporter) { - List generatorsWithMarginalCost; + List generatorsToReturn = new ArrayList<>(); - // get all generators in the component + // get all connected generators in the component List generators = component.getBusStream().flatMap(Bus::getGeneratorStream).collect(Collectors.toList()); // remove generators with fixed supply @@ -163,15 +163,23 @@ private static List computeAdjustableGenerators(Network network, Comp generators.forEach(generator -> generator.setTargetP(0.)); // get generators with marginal cost - generatorsWithMarginalCost = generators.stream().filter(generator -> { + List generatorsWithMarginalCost = generators.stream().filter(generator -> { Double marginalCost = getGeneratorMarginalCost(generator); if (marginalCost == null) { report(reporter, Integer.toString(component.getNum()), "MissingMarginalCostForGenerator", "The generator ${generator} does not have a marginal cost", - Map.of(GENERATOR, generator.getId()), TypedValue.WARN_SEVERITY); + Map.of(GENERATOR, generator.getId()), TypedValue.TRACE_SEVERITY); } return marginalCost != null; }).collect(Collectors.toList()); + int nbNoCost = generators.size() - generatorsWithMarginalCost.size(); + if (nbNoCost > 0) { + report(reporter, Integer.toString(component.getNum()), "NbGeneratorsWithNoCost", "${nbNoCost} generator${isPlural} been discarded from generation dispatch because of missing marginal cost. Their active power set point has been set to 0", + Map.of("nbNoCost", nbNoCost, + "isPlural", nbNoCost > 1 ? "s have" : " has"), + TypedValue.WARN_SEVERITY); + } + // build map of generators by marginal cost generatorsWithMarginalCost.sort(Comparator.comparing(GenerationDispatch::getGeneratorMarginalCost)); Map> generatorsByMarginalCost = new TreeMap<>(); @@ -181,8 +189,6 @@ private static List computeAdjustableGenerators(Network network, Comp generatorsByMarginalCost.get(marginalCost).add(g.getId()); }); - List generatorsToReturn = new ArrayList<>(); - // log substations not found if (!CollectionUtils.isEmpty(substationsGeneratorsOrderingInfos)) { substationsGeneratorsOrderingInfos.forEach(sInfo -> @@ -257,6 +263,7 @@ private static List computeAdjustableGenerators(Network network, Comp private static class GeneratorTargetPListener extends DefaultNetworkListener { private final Reporter reporter; private final String suffixKey; + private final List updatedGenerators = new ArrayList<>(); GeneratorTargetPListener(Reporter reporter, String suffixKey) { this.reporter = reporter; @@ -268,8 +275,25 @@ public void onUpdate(Identifiable identifiable, String attribute, String variant if (identifiable.getType() == IdentifiableType.GENERATOR && attribute.equals("targetP") && Double.compare((double) oldValue, (double) newValue) != 0) { - report(reporter, suffixKey, "GeneratorSetTargetP", "Generator ${generator} targetP : ${oldValue} MW --> ${newValue} MW", - Map.of(GENERATOR, identifiable.getId(), "oldValue", oldValue, "newValue", newValue), TypedValue.INFO_SEVERITY); + report(reporter, suffixKey, "GeneratorSetTargetP", "The active power set point of generator ${generator} has been set to ${newValue} MW", + Map.of(GENERATOR, identifiable.getId(), "newValue", newValue), TypedValue.TRACE_SEVERITY); + updatedGenerators.add(identifiable.getId()); + } + } + + 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(), "isPlural", updatedGenerators.size() > 1 ? "s" : ""), TypedValue.INFO_SEVERITY); + // what are unchanged generators ? + adjustableGenerators.stream() + .filter(g -> !updatedGenerators.contains(g.getId())) + .forEach(g -> report(reporter, suffixKey, "GeneratorUnchangedTargetP", "Generator ${generator} has not been selected by the merit order algorithm. Its active power set point has been set to 0", + Map.of(GENERATOR, g.getId()), TypedValue.TRACE_SEVERITY)); + int nbUnchangedGenerators = adjustableGenerators.size() - updatedGenerators.size(); + if (nbUnchangedGenerators > 0) { + report(reporter, suffixKey, "TotalGeneratorUnchangedTargetP", "${nbUnchangedGenerator} eligible generator${isPlural} not been selected by the merit order algorithm. Their active power set point has been set to 0", + Map.of("nbUnchangedGenerator", nbUnchangedGenerators, + "isPlural", nbUnchangedGenerators > 1 ? "s have" : " has"), TypedValue.INFO_SEVERITY); } } } @@ -379,6 +403,24 @@ private double reduceGeneratorMaxPValue(Generator generator, return Math.max(generator.getMinP(), res * (1. - genFrequencyReserve / 100.)); } + private void reportDisconnectedGenerators(List disconnectedGenerators, int componentNum, Reporter reporter) { + AtomicInteger disconnectedGeneratorCounter = new AtomicInteger(0); + disconnectedGenerators.stream() + .filter(g -> g.getTerminal().getBusView() != null && g.getTerminal().getBusView().getConnectableBus() != null && + g.getTerminal().getBusView().getConnectableBus().getSynchronousComponent().getNum() == componentNum) + .forEach(g -> { + report(reporter, Integer.toString(componentNum), "DisconnectedGenerator", "Generator ${generator} has been discarded from generation dispatch because it is disconnected. Its active power set point remains unchanged", + Map.of(GENERATOR, g.getId()), TypedValue.TRACE_SEVERITY); + disconnectedGeneratorCounter.getAndIncrement(); + }); + if (disconnectedGeneratorCounter.get() > 0) { + report(reporter, Integer.toString(componentNum), "TotalDisconnectedGenerator", "${nbDisconnectedGenerator} generator${isPlural} been discarded from generation dispatch because their are disconnected. Their active power set point remains unchanged", + Map.of("nbDisconnectedGenerator", disconnectedGeneratorCounter.get(), + "isPlural", disconnectedGeneratorCounter.get() > 1 ? "s have" : " has"), + TypedValue.INFO_SEVERITY); + } + } + @Override public void apply(Network network, Reporter subReporter) { Collection synchronousComponents = network.getBusView().getBusStream() @@ -386,6 +428,17 @@ public void apply(Network network, Reporter subReporter) { .map(Bus::getSynchronousComponent) .collect(collectingAndThen(toCollection(() -> new TreeSet<>(comparingInt(Component::getNum))), ArrayList::new)); + report(subReporter, "", "NbSynchronousComponents", "Network has ${scNumber} synchronous component${isPlural}: ${scList}", + Map.of("scNumber", synchronousComponents.size(), + "isPlural", synchronousComponents.size() > 1 ? "s" : "", + "scList", synchronousComponents.stream().map(sc -> "SC" + sc.getNum()).collect(Collectors.joining(", "))), + TypedValue.INFO_SEVERITY); + + // all disconnected generators at network level (for report purpose) + List disconnectedGenerators = network.getGeneratorStream() + .filter(g -> !g.getTerminal().isConnected()) + .toList(); + // get generators for which there will be no reduction of maximal power List generatorsWithoutOutage = collectGeneratorsWithoutOutage(network, subReporter); @@ -402,6 +455,9 @@ public void apply(Network network, Reporter subReporter) { Reporter powerToDispatchReporter = componentReporter.createSubReporter(POWER_TO_DISPATCH, POWER_TO_DISPATCH); + // log disconnected generators attached to this synchronous component + reportDisconnectedGenerators(disconnectedGenerators, componentNum, powerToDispatchReporter); + // 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", @@ -449,6 +505,7 @@ public void apply(Network network, Reporter subReporter) { Scalable scalable = Scalable.stack(generatorsScalable.toArray(Scalable[]::new)); realized = scalable.scale(network, totalAmountSupplyToBeDispatched, new ScalingParameters().setAllowsGeneratorOutOfActivePowerLimits(true)); + listener.endReport(adjustableGenerators); network.removeListener(listener); } From c92855e075ec0b30bfb29de03017c3c83806af65 Mon Sep 17 00:00:00 2001 From: David BRAQUART Date: Wed, 20 Sep 2023 13:13:13 +0200 Subject: [PATCH 2/4] refactor a bit to reduce functions size/complexity Signed-off-by: David BRAQUART --- .../modifications/GenerationDispatch.java | 57 +++++++++++-------- 1 file changed, 34 insertions(+), 23 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 647c28fd3..abb52b5ee 100644 --- a/src/main/java/org/gridsuite/modification/server/modifications/GenerationDispatch.java +++ b/src/main/java/org/gridsuite/modification/server/modifications/GenerationDispatch.java @@ -148,16 +148,8 @@ private static Double getGeneratorMarginalCost(Generator generator) { return null; } - private static List computeAdjustableGenerators(Network network, Component component, List generatorsWithFixedSupply, - List substationsGeneratorsOrderingInfos, - Reporter reporter) { - List generatorsToReturn = new ArrayList<>(); - - // get all connected generators in the component - List generators = component.getBusStream().flatMap(Bus::getGeneratorStream).collect(Collectors.toList()); - - // remove generators with fixed supply - generators.removeIf(generator -> generatorsWithFixedSupply.contains(generator.getId())); + private static Map> getGeneratorsByMarginalCost(List generators, Reporter reporter, String reporterSuffixKey) { + Map> generatorsByMarginalCost = new TreeMap<>(); // set targetP to 0 generators.forEach(generator -> generator.setTargetP(0.)); @@ -166,15 +158,15 @@ private static List computeAdjustableGenerators(Network network, Comp List generatorsWithMarginalCost = generators.stream().filter(generator -> { Double marginalCost = getGeneratorMarginalCost(generator); if (marginalCost == null) { - report(reporter, Integer.toString(component.getNum()), "MissingMarginalCostForGenerator", "The generator ${generator} does not have a marginal cost", - Map.of(GENERATOR, generator.getId()), TypedValue.TRACE_SEVERITY); + report(reporter, reporterSuffixKey, "MissingMarginalCostForGenerator", "The generator ${generator} does not have a marginal cost", + Map.of(GENERATOR, generator.getId()), TypedValue.TRACE_SEVERITY); } return marginalCost != null; }).collect(Collectors.toList()); int nbNoCost = generators.size() - generatorsWithMarginalCost.size(); if (nbNoCost > 0) { - report(reporter, Integer.toString(component.getNum()), "NbGeneratorsWithNoCost", "${nbNoCost} generator${isPlural} been discarded from generation dispatch because of missing marginal cost. Their active power set point has been set to 0", + report(reporter, reporterSuffixKey, "NbGeneratorsWithNoCost", "${nbNoCost} generator${isPlural} been discarded from generation dispatch because of missing marginal cost. Their active power set point has been set to 0", Map.of("nbNoCost", nbNoCost, "isPlural", nbNoCost > 1 ? "s have" : " has"), TypedValue.WARN_SEVERITY); @@ -182,25 +174,44 @@ private static List computeAdjustableGenerators(Network network, Comp // build map of generators by marginal cost generatorsWithMarginalCost.sort(Comparator.comparing(GenerationDispatch::getGeneratorMarginalCost)); - Map> generatorsByMarginalCost = new TreeMap<>(); generatorsWithMarginalCost.forEach(g -> { Double marginalCost = getGeneratorMarginalCost(g); generatorsByMarginalCost.computeIfAbsent(marginalCost, k -> new ArrayList<>()); generatorsByMarginalCost.get(marginalCost).add(g.getId()); }); - // log substations not found + return generatorsByMarginalCost; + } + + private static void reportUnknownSubstations(Network network, List substationsGeneratorsOrderingInfos, Reporter reporter, String reporterSuffixKey) { if (!CollectionUtils.isEmpty(substationsGeneratorsOrderingInfos)) { substationsGeneratorsOrderingInfos.forEach(sInfo -> - sInfo.getSubstationIds().forEach(sId -> { - Substation substation = network.getSubstation(sId); - if (substation == null) { - report(reporter, Integer.toString(component.getNum()), "SubstationNotFound", "Substation ${substation} not found", - Map.of(SUBSTATION, sId), TypedValue.WARN_SEVERITY); - } - })); + sInfo.getSubstationIds().forEach(sId -> { + Substation substation = network.getSubstation(sId); + if (substation == null) { + report(reporter, reporterSuffixKey, "SubstationNotFound", "Substation ${substation} not found", + Map.of(SUBSTATION, sId), TypedValue.WARN_SEVERITY); + } + })); } + } + + private static List computeAdjustableGenerators(Network network, Component component, List generatorsWithFixedSupply, + List substationsGeneratorsOrderingInfos, + Reporter reporter) { + List generatorsToReturn = new ArrayList<>(); + String reporterSuffixKey = Integer.toString(component.getNum()); + + // log substations not found + reportUnknownSubstations(network, substationsGeneratorsOrderingInfos, reporter, reporterSuffixKey); + + // get all connected generators in the component + List generators = component.getBusStream().flatMap(Bus::getGeneratorStream).collect(Collectors.toList()); + + // remove generators with fixed supply + generators.removeIf(generator -> generatorsWithFixedSupply.contains(generator.getId())); + Map> generatorsByMarginalCost = getGeneratorsByMarginalCost(generators, reporter, reporterSuffixKey); generatorsByMarginalCost.forEach((mCost, gList) -> { // loop on generators of same cost if (!CollectionUtils.isEmpty(substationsGeneratorsOrderingInfos)) { // substations hierarchy provided // build mapGeneratorsBySubstationsList, that will contain all the generators with the same marginal cost as mCost contained in each list of substations @@ -253,7 +264,7 @@ private static List computeAdjustableGenerators(Network network, Comp }); if (generatorsToReturn.isEmpty()) { - report(reporter, Integer.toString(component.getNum()), "NoAvailableAdjustableGenerator", "There is no adjustable generator", + report(reporter, reporterSuffixKey, "NoAvailableAdjustableGenerator", "There is no adjustable generator", Map.of(), TypedValue.WARN_SEVERITY); } From 79ac1b7fc04aeba49cb46d8fb79885f4e76922cc Mon Sep 17 00:00:00 2001 From: David BRAQUART Date: Wed, 20 Sep 2023 14:41:36 +0200 Subject: [PATCH 3/4] update unit test Signed-off-by: David BRAQUART --- .../modifications/GenerationDispatchTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) 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 9f2c3d776..455bb8c0d 100644 --- a/src/test/java/org/gridsuite/modification/server/modifications/GenerationDispatchTest.java +++ b/src/test/java/org/gridsuite/modification/server/modifications/GenerationDispatchTest.java @@ -537,19 +537,19 @@ 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("Generator TEST1 targetP : 0.0 MW --> 40.375 MW", "GeneratorSetTargetP" + firstSynchronousComponentNum, reportService, 1); - assertLogNthMessage("Generator GTH1 targetP : 0.0 MW --> 80.0 MW", "GeneratorSetTargetP" + firstSynchronousComponentNum, reportService, 2); - assertLogNthMessage("Generator GTH2 targetP : 0.0 MW --> 146.0 MW", "GeneratorSetTargetP" + firstSynchronousComponentNum, reportService, 3); + 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 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); 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); - assertLogNthMessage("Generator GH1 targetP : 0.0 MW --> 80.0 MW", "GeneratorSetTargetP" + secondSynchronousComponentNum, reportService, 1); - assertLogNthMessage("Generator GH2 targetP : 0.0 MW --> 60.0 MW", "GeneratorSetTargetP" + secondSynchronousComponentNum, reportService, 2); - assertLogNthMessage("Generator GH3 targetP : 0.0 MW --> 126.1 MW", "GeneratorSetTargetP" + secondSynchronousComponentNum, reportService, 3); - assertLogNthMessage("Generator ABC targetP : 0.0 MW --> 63.900000000000006 MW", "GeneratorSetTargetP" + secondSynchronousComponentNum, reportService, 4); + 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); assertLogMessage("The supply-demand balance could be met", "SupplyDemandBalanceCouldBeMet" + secondSynchronousComponentNum, reportService); wireMockUtils.verifyGetRequest(stubIdForPmaxReduction, PATH, handleQueryParams(getNetworkUuid(), getGeneratorsWithoutOutageFilters123().stream().map(FilterEquipments::getFilterId).collect(Collectors.toList())), false); From 75566ee2a23095fb5b2899691fb351326e920643 Mon Sep 17 00:00:00 2001 From: David BRAQUART Date: Mon, 25 Sep 2023 13:08:16 +0200 Subject: [PATCH 4/4] review remarks Signed-off-by: David BRAQUART --- .../modifications/GenerationDispatch.java | 63 +++++++++---------- 1 file changed, 31 insertions(+), 32 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 abb52b5ee..d55a9aef6 100644 --- a/src/main/java/org/gridsuite/modification/server/modifications/GenerationDispatch.java +++ b/src/main/java/org/gridsuite/modification/server/modifications/GenerationDispatch.java @@ -155,15 +155,9 @@ private static Map> getGeneratorsByMarginalCost(List generator.setTargetP(0.)); // get generators with marginal cost - List generatorsWithMarginalCost = generators.stream().filter(generator -> { - Double marginalCost = getGeneratorMarginalCost(generator); - if (marginalCost == null) { - report(reporter, reporterSuffixKey, "MissingMarginalCostForGenerator", "The generator ${generator} does not have a marginal cost", - Map.of(GENERATOR, generator.getId()), TypedValue.TRACE_SEVERITY); - } - return marginalCost != null; - }).collect(Collectors.toList()); - + List generatorsWithMarginalCost = generators.stream() + .filter(generator -> getGeneratorMarginalCost(generator) != null) + .collect(Collectors.toList()); int nbNoCost = generators.size() - generatorsWithMarginalCost.size(); if (nbNoCost > 0) { report(reporter, reporterSuffixKey, "NbGeneratorsWithNoCost", "${nbNoCost} generator${isPlural} been discarded from generation dispatch because of missing marginal cost. Their active power set point has been set to 0", @@ -171,6 +165,11 @@ private static Map> getGeneratorsByMarginalCost(List 1 ? "s have" : " has"), TypedValue.WARN_SEVERITY); } + generators.stream() + .filter(generator -> getGeneratorMarginalCost(generator) == null) + .forEach(g -> report(reporter, reporterSuffixKey, "MissingMarginalCostForGenerator", "The generator ${generator} does not have a marginal cost", + Map.of(GENERATOR, g.getId()), TypedValue.TRACE_SEVERITY) + ); // build map of generators by marginal cost generatorsWithMarginalCost.sort(Comparator.comparing(GenerationDispatch::getGeneratorMarginalCost)); @@ -274,7 +273,7 @@ private static List computeAdjustableGenerators(Network network, Comp private static class GeneratorTargetPListener extends DefaultNetworkListener { private final Reporter reporter; private final String suffixKey; - private final List updatedGenerators = new ArrayList<>(); + private final List updatedGenerators = new ArrayList<>(); GeneratorTargetPListener(Reporter reporter, String suffixKey) { this.reporter = reporter; @@ -283,28 +282,29 @@ private static class GeneratorTargetPListener extends DefaultNetworkListener { @Override public void onUpdate(Identifiable identifiable, String attribute, String variantId, Object oldValue, Object newValue) { - if (identifiable.getType() == IdentifiableType.GENERATOR && - attribute.equals("targetP") && - Double.compare((double) oldValue, (double) newValue) != 0) { - report(reporter, suffixKey, "GeneratorSetTargetP", "The active power set point of generator ${generator} has been set to ${newValue} MW", - Map.of(GENERATOR, identifiable.getId(), "newValue", newValue), TypedValue.TRACE_SEVERITY); - updatedGenerators.add(identifiable.getId()); + if (identifiable.getType() == IdentifiableType.GENERATOR && attribute.equals("targetP") && Double.compare((double) oldValue, (double) newValue) != 0) { + updatedGenerators.add((Generator) identifiable); } } public void endReport(List adjustableGenerators) { + // report updated generators 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(), "isPlural", updatedGenerators.size() > 1 ? "s" : ""), TypedValue.INFO_SEVERITY); - // what are unchanged generators ? - adjustableGenerators.stream() - .filter(g -> !updatedGenerators.contains(g.getId())) - .forEach(g -> report(reporter, suffixKey, "GeneratorUnchangedTargetP", "Generator ${generator} has not been selected by the merit order algorithm. Its active power set point has been set to 0", - Map.of(GENERATOR, g.getId()), TypedValue.TRACE_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)); + + // report unchanged generators int nbUnchangedGenerators = adjustableGenerators.size() - updatedGenerators.size(); if (nbUnchangedGenerators > 0) { + List updatedGeneratorsIds = updatedGenerators.stream().map(Identifiable::getId).toList(); report(reporter, suffixKey, "TotalGeneratorUnchangedTargetP", "${nbUnchangedGenerator} eligible generator${isPlural} not been selected by the merit order algorithm. Their active power set point has been set to 0", Map.of("nbUnchangedGenerator", nbUnchangedGenerators, "isPlural", nbUnchangedGenerators > 1 ? "s have" : " has"), TypedValue.INFO_SEVERITY); + adjustableGenerators.stream() + .filter(g -> !updatedGeneratorsIds.contains(g.getId())) + .forEach(g -> report(reporter, suffixKey, "GeneratorUnchangedTargetP", "Generator ${generator} has not been selected by the merit order algorithm. Its active power set point has been set to 0", + Map.of(GENERATOR, g.getId()), TypedValue.TRACE_SEVERITY)); } } } @@ -414,21 +414,20 @@ private double reduceGeneratorMaxPValue(Generator generator, return Math.max(generator.getMinP(), res * (1. - genFrequencyReserve / 100.)); } - private void reportDisconnectedGenerators(List disconnectedGenerators, int componentNum, Reporter reporter) { - AtomicInteger disconnectedGeneratorCounter = new AtomicInteger(0); - disconnectedGenerators.stream() + private void reportDisconnectedGenerators(List globalDisconnectedGenerators, int componentNum, Reporter reporter) { + List componentDisconnectedGenerators = globalDisconnectedGenerators.stream() .filter(g -> g.getTerminal().getBusView() != null && g.getTerminal().getBusView().getConnectableBus() != null && g.getTerminal().getBusView().getConnectableBus().getSynchronousComponent().getNum() == componentNum) - .forEach(g -> { - report(reporter, Integer.toString(componentNum), "DisconnectedGenerator", "Generator ${generator} has been discarded from generation dispatch because it is disconnected. Its active power set point remains unchanged", - Map.of(GENERATOR, g.getId()), TypedValue.TRACE_SEVERITY); - disconnectedGeneratorCounter.getAndIncrement(); - }); - if (disconnectedGeneratorCounter.get() > 0) { + .toList(); + if (!componentDisconnectedGenerators.isEmpty()) { report(reporter, Integer.toString(componentNum), "TotalDisconnectedGenerator", "${nbDisconnectedGenerator} generator${isPlural} been discarded from generation dispatch because their are disconnected. Their active power set point remains unchanged", - Map.of("nbDisconnectedGenerator", disconnectedGeneratorCounter.get(), - "isPlural", disconnectedGeneratorCounter.get() > 1 ? "s have" : " has"), + Map.of("nbDisconnectedGenerator", componentDisconnectedGenerators.size(), + "isPlural", componentDisconnectedGenerators.size() > 1 ? "s have" : " has"), TypedValue.INFO_SEVERITY); + componentDisconnectedGenerators.forEach(g -> + report(reporter, Integer.toString(componentNum), "DisconnectedGenerator", "Generator ${generator} has been discarded from generation dispatch because it is disconnected. Its active power set point remains unchanged", + Map.of(GENERATOR, g.getId()), TypedValue.TRACE_SEVERITY) + ); } }