Skip to content

Commit

Permalink
Merge branch 'main' into upgrade_to_powsybl_dependencies_2024.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
FranckLecuyer authored Jul 29, 2024
2 parents 1ac73ac + 1df2e93 commit e0d5866
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
* @author Slimane Amar <slimane.amar at rte-france.com>
*/
public abstract class AbstractModification extends AbstractNetworkModification {

public static final String CHARACTERISTICS = "Characteristics";
public static final String SETPOINTS = "Setpoints";

@Override
public void apply(Network network, NamingStrategy namingStrategy, boolean throwException, ComputationManager computationManager, ReportNode reportNode) {
apply(network, reportNode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,13 @@ public <T> void applyElementaryModifications(Consumer<T> setter, Supplier<T> get
}
}

public <T> ReportNode applyAndBuildModificationReport(Consumer<T> setter, Supplier<T> getter, AttributeModification<T> modification, String fieldName) {
T oldValue = getter.get();
T newValue = modification.applyModification(oldValue);
setter.accept(newValue);
return buildModificationReport(oldValue, newValue, fieldName, 1, TypedValue.INFO_SEVERITY);
}

public <T> ReportNode buildModificationReport(T oldValue, T newValue, String fieldName) {
return buildModificationReport(oldValue, newValue, fieldName, 1, TypedValue.INFO_SEVERITY);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@
import com.powsybl.commons.report.TypedValue;
import com.powsybl.iidm.network.Network;
import com.powsybl.network.store.client.NetworkStoreService;
import com.powsybl.network.store.client.PreloadingStrategy;

import jakarta.annotation.PreDestroy;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.tuple.Pair;
import org.gridsuite.modification.server.ModificationType;
import org.gridsuite.modification.server.NetworkModificationException;
import org.gridsuite.modification.server.dto.ModificationInfos;
import org.gridsuite.modification.server.dto.NetworkInfos;
Expand All @@ -33,6 +37,9 @@

import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* @author Slimane Amar <slimane.amar at rte-france.com>
Expand All @@ -51,31 +58,86 @@ public class NetworkModificationApplicator {

@Getter private final FilterService filterService;

private final ExecutorService applicationExecutor;

@Value("${impacts.collection-threshold:50}")
@Setter // TODO REMOVE when VoltageInitReportTest will no longer use NetworkModificationApplicator
private Integer collectionThreshold;

public NetworkModificationApplicator(NetworkStoreService networkStoreService, EquipmentInfosService equipmentInfosService,
ReportService reportService, FilterService filterService) {
ReportService reportService, FilterService filterService,
@Value("${max-large-concurrent-applications}") int maxConcurrentApplications) {
this.networkStoreService = networkStoreService;
this.equipmentInfosService = equipmentInfosService;
this.reportService = reportService;
this.filterService = filterService;
this.applicationExecutor = Executors.newFixedThreadPool(maxConcurrentApplications);
}

/* This method is used when creating, inserting, moving or duplicating modifications
* Since there is no queue for these operations and they can be memory consuming when the preloading strategy is large
* (for example for VOLTAGE_INIT_MODIFICATION),
* we limit the number of concurrent applications of these modifications to avoid out of memory issues.
* We keep the possibility to apply small or medium modifications immediately in parallel without limits.
* And if in the future we also need to limit the memory consumption of medium modifications we can add more code here.
* Note : we currently have 3 sizes of modifications :
* small : preloadingStrategy = NONE
* medium : preloadingStrategy = COLLECTION
* large : preloadingStrategy = ALL_COLLECTIONS_NEEDED_FOR_BUS_VIEW
*/
public NetworkModificationResult applyModifications(List<ModificationInfos> modificationInfosList, NetworkInfos networkInfos, ReportInfos reportInfos) {
PreloadingStrategy preloadingStrategy = modificationInfosList.stream()
.map(ModificationInfos::getType)
.reduce(ModificationType::maxStrategy)
.map(ModificationType::getStrategy)
.orElse(PreloadingStrategy.NONE);
if (preloadingStrategy == PreloadingStrategy.ALL_COLLECTIONS_NEEDED_FOR_BUS_VIEW) {
CompletableFuture<NetworkModificationResult> future = CompletableFuture.supplyAsync(() -> processApplication(modificationInfosList, networkInfos, reportInfos), applicationExecutor);
return future.join();
} else {
return processApplication(modificationInfosList, networkInfos, reportInfos);
}
}

// used for creating, inserting, moving or duplicating modifications
private NetworkModificationResult processApplication(List<ModificationInfos> modificationInfosList, NetworkInfos networkInfos, ReportInfos reportInfos) {
NetworkStoreListener listener = NetworkStoreListener.create(networkInfos.getNetwork(), networkInfos.getNetworkUuuid(), networkStoreService, equipmentInfosService, collectionThreshold);
ApplicationStatus groupApplicationStatus = apply(modificationInfosList, listener.getNetwork(), reportInfos);
List<AbstractBaseImpact> networkImpacts = listener.flushNetworkModifications();
return
NetworkModificationResult.builder()
return NetworkModificationResult.builder()
.applicationStatus(groupApplicationStatus)
.lastGroupApplicationStatus(groupApplicationStatus)
.networkImpacts(networkImpacts)
.build();
}

/* This method is used when building a variant
* building a variant is limited to ${consumer.concurrency} (typically 2) concurrent builds thanks to rabbitmq queue
* but since the other operations (create, insert, move, duplicate) are not inserted in the same rabbitmq queue
* we use the same ExecutorService to globally limit the number of concurrent large modifications in order to avoid out of memory issues
* We keep the possibility to apply small or medium modifications immediately.
* And if in the future we also need to limit the memory consumption of medium modifications we can add more code here.
* Note : it is possible that the rabbitmq consumer threads here will be blocked by modifications applied directly in the other applyModifications method
* and no more builds can go through. If this causes problems we should put them in separate rabbitmq queues.
*/
public NetworkModificationResult applyModifications(List<Pair<String, List<ModificationInfos>>> modificationInfosGroups, NetworkInfos networkInfos, UUID reportUuid) {
PreloadingStrategy preloadingStrategy = modificationInfosGroups.stream()
.map(Pair::getRight)
.flatMap(List::stream)
.map(ModificationInfos::getType)
.reduce(ModificationType::maxStrategy)
.map(ModificationType::getStrategy)
.orElse(PreloadingStrategy.NONE);
if (preloadingStrategy == PreloadingStrategy.ALL_COLLECTIONS_NEEDED_FOR_BUS_VIEW) {
CompletableFuture<NetworkModificationResult> future = CompletableFuture.supplyAsync(() -> processApplication(modificationInfosGroups, networkInfos, reportUuid), applicationExecutor);
return future.join();
} else {
return processApplication(modificationInfosGroups, networkInfos, reportUuid);
}
}

// used for building a variant
private NetworkModificationResult processApplication(List<Pair<String, List<ModificationInfos>>> modificationInfosGroups, NetworkInfos networkInfos, UUID reportUuid) {
NetworkStoreListener listener = NetworkStoreListener.create(networkInfos.getNetwork(), networkInfos.getNetworkUuuid(), networkStoreService, equipmentInfosService, collectionThreshold);
List<ApplicationStatus> groupsApplicationStatuses =
modificationInfosGroups.stream()
Expand Down Expand Up @@ -158,4 +220,9 @@ public static ApplicationStatus getApplicationStatus(ReportNode reportNode) {
throw new IllegalArgumentException(String.format("Report severity '%s' unknown !", severity.getValue()));
}
}

@PreDestroy
public void shutdown() {
applicationExecutor.shutdown();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ private PropertiesUtils() {

public static void applyProperties(Identifiable<?> identifiable, ReportNode subReportNode, @Nullable List<FreePropertyInfos> properties, String propertiesLabelKey) {
List<ReportNode> reportNodes = new ArrayList<>();
ReportNode propertiesReporter = subReportNode.newReportNode().withMessageTemplate(PROPERTIES, PROPERTIES).add();
Optional.ofNullable(properties).ifPresent(props ->
props.forEach(prop ->
Optional.ofNullable(PropertiesUtils.applyProperty(identifiable, prop))
.ifPresent(reportNodes::add)
)
);
ModificationUtils.getInstance().reportModifications(propertiesReporter, reportNodes,
propertiesLabelKey, PROPERTIES, Map.of());
if (!reportNodes.isEmpty()) {
ModificationUtils.getInstance().reportModifications(subReportNode, reportNodes,
propertiesLabelKey, PROPERTIES, Map.of());
}
}

private static ReportNode applyProperty(Identifiable<?> identifiable, FreePropertyInfos prop) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@
*/

public class VscCreation extends AbstractModification {
public static final String CHARACTERISTICS = "Characteristics";
public static final String SETPOINTS = "Setpoints";

public static final String VSC_SETPOINTS = "vscSetPoints";
public static final String VSC_CHARACTERISTICS = "vscCharacteristics";

private final VscCreationInfos modificationInfos;

public VscCreation(VscCreationInfos modificationInfos) {
Expand Down Expand Up @@ -130,24 +132,21 @@ public void apply(Network network, ReportNode subReportNode) {

private void reportHvdcLineInfos(ReportNode subReportNode) {
List<ReportNode> characteristicsReports = new ArrayList<>();
ReportNode characteristicReport = subReportNode.newReportNode().withMessageTemplate("vscCharacteristics", CHARACTERISTICS).add();
characteristicsReports.add(ModificationUtils.getInstance().buildCreationReport(modificationInfos.getNominalV(), "DC nominal voltage"));
characteristicsReports.add(ModificationUtils.getInstance().buildCreationReport(modificationInfos.getR(), "DC resistance"));
characteristicsReports.add(ModificationUtils.getInstance().buildCreationReport(modificationInfos.getMaxP(), "Pmax"));
ModificationUtils.getInstance().reportModifications(characteristicReport, characteristicsReports, "vscCharacteristics", CHARACTERISTICS, Map.of());
ModificationUtils.getInstance().reportModifications(subReportNode, characteristicsReports, VSC_CHARACTERISTICS, CHARACTERISTICS, Map.of());

List<ReportNode> limitsReports = new ArrayList<>();
ReportNode limitsReport = subReportNode.newReportNode().withMessageTemplate("vscLimits", "Limits").add();
limitsReports.add(ModificationUtils.getInstance().buildCreationReport(modificationInfos.getOperatorActivePowerLimitFromSide1ToSide2(), "Operator active power limit (Side1 -> Side 2)"));
limitsReports.add(ModificationUtils.getInstance().buildCreationReport(modificationInfos.getOperatorActivePowerLimitFromSide2ToSide1(), "Operator active power limit (Side2 -> Side 1)"));
ModificationUtils.getInstance().reportModifications(limitsReport, limitsReports, "vscLimits", "Limits", Map.of());
ModificationUtils.getInstance().reportModifications(subReportNode, limitsReports, "vscLimits", "Limits", Map.of());

List<ReportNode> setPointsReports = new ArrayList<>();
ReportNode setPointsReporter = subReportNode.newReportNode().withMessageTemplate("vscSetPoints", SETPOINTS).add();
ReportNode setPointsReporter = subReportNode.newReportNode().withMessageTemplate(VSC_SETPOINTS, SETPOINTS).add();
setPointsReports.add(ModificationUtils.getInstance().buildCreationReport(modificationInfos.getConvertersMode(), "Converters mode"));
setPointsReports.add(ModificationUtils.getInstance().buildCreationReport(modificationInfos.getActivePowerSetpoint(), "Active power"));
setPointsReports.add(ModificationUtils.getInstance().buildCreationReport(modificationInfos.getMaxP(), "Pmax"));
ModificationUtils.getInstance().reportModifications(setPointsReporter, setPointsReports, "vscSetPoints", SETPOINTS, Map.of());
ModificationUtils.getInstance().reportModifications(setPointsReporter, setPointsReports, VSC_SETPOINTS, SETPOINTS, Map.of());

List<ReportNode> angleDroopActivePowerControlReports = new ArrayList<>();
angleDroopActivePowerControlReports.add(ModificationUtils.getInstance()
Expand All @@ -173,7 +172,6 @@ private VscConverterStation createConverterStation(Network network,
VscConverterStation vscConverterStation = voltageLevel.getTopologyKind() == TopologyKind.NODE_BREAKER ?
createConverterStationInNodeBreaker(network, voltageLevel, converterStationCreationInfos, converterStationReporter) :
createConverterStationInBusBreaker(voltageLevel, converterStationCreationInfos, converterStationReporter);

converterStationReporter.newReportNode()
.withMessageTemplate("converterStationCreated" + logFieldName, "New converter station with id=${id} created")
.withUntypedValue("id", converterStationCreationInfos.getEquipmentId())
Expand Down
Loading

0 comments on commit e0d5866

Please sign in to comment.