diff --git a/src/main/java/org/gridsuite/network/map/NetworkMapController.java b/src/main/java/org/gridsuite/network/map/NetworkMapController.java index b85a6d90..11dc0566 100644 --- a/src/main/java/org/gridsuite/network/map/NetworkMapController.java +++ b/src/main/java/org/gridsuite/network/map/NetworkMapController.java @@ -14,8 +14,14 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.AllArgsConstructor; -import org.gridsuite.network.map.dto.*; +import org.gridsuite.network.map.dto.AllElementsInfos; +import org.gridsuite.network.map.dto.ElementInfos; +import org.gridsuite.network.map.dto.ElementType; +import org.gridsuite.network.map.dto.InfoTypeParameters; import org.gridsuite.network.map.dto.definition.hvdc.HvdcShuntCompensatorsInfos; +import org.gridsuite.network.map.dto.definition.topology.BusBarSectionsInfos; +import org.gridsuite.network.map.dto.definition.topology.FeederBaysBusBarSectionsInfos; +import org.gridsuite.network.map.dto.definition.topology.SwitchInfos; import org.gridsuite.network.map.services.NetworkMapService; import org.springframework.context.annotation.ComponentScan; import org.springframework.web.bind.annotation.*; @@ -89,13 +95,31 @@ public List getVoltageLevelBusesOrBusBarSections(@Parameter(descri return networkMapService.getVoltageLevelBusesOrBusbarSections(networkUuid, voltageLevelId, variantId); } + @GetMapping(value = "/networks/{networkUuid}/voltage-levels/{voltageLevelId}/feeder-bays-and-bus-bar-sections", produces = APPLICATION_JSON_VALUE) + @Operation(summary = "get feeder bays and bus bar sections information") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = " feeder bays and bus bar sections information retrieved")}) + public FeederBaysBusBarSectionsInfos getFeederBaysInfos(@Parameter(description = "Network UUID") @PathVariable("networkUuid") UUID networkUuid, + @Parameter(description = "Voltage level id") @PathVariable("voltageLevelId") String voltageLevelId, + @Parameter(description = "Variant Id") @RequestParam(name = "variantId", required = false) String variantId) { + return networkMapService.getFeederBaysInfos(networkUuid, voltageLevelId, variantId); + } + + @GetMapping(value = "/networks/{networkUuid}/voltage-levels/{voltageLevelId}/bus-bar-sections", produces = APPLICATION_JSON_VALUE) + @Operation(summary = "get bus bar sections information") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "bus bar sections information retrieved")}) + public BusBarSectionsInfos getBusBarSectionsInfos(@Parameter(description = "Network UUID") @PathVariable("networkUuid") UUID networkUuid, + @Parameter(description = "Voltage level id") @PathVariable("voltageLevelId") String voltageLevelId, + @Parameter(description = "Variant Id") @RequestParam(name = "variantId", required = false) String variantId) { + return networkMapService.getBusBarSectionsInfos(networkUuid, voltageLevelId, variantId); + } + @GetMapping(value = "/networks/{networkUuid}/voltage-levels/{voltageLevelId}/switches", produces = APPLICATION_JSON_VALUE) @Operation(summary = "Get switches description for a voltage level") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Switches description")}) public List getVoltageLevelSwitches(@Parameter(description = "Network UUID") @PathVariable("networkUuid") UUID networkUuid, @Parameter(description = "Voltage level id") @PathVariable("voltageLevelId") String voltageLevelId, @Parameter(description = "Variant Id") @RequestParam(name = "variantId", required = false) String variantId) { - return networkMapService.getVoltageLevelSwitches(networkUuid, voltageLevelId, variantId); + return networkMapService.getSwitchInfos(networkUuid, voltageLevelId, variantId); } @GetMapping(value = "/networks/{networkUuid}/voltage-levels/{voltageLevelId}/substation-id", produces = APPLICATION_JSON_VALUE) diff --git a/src/main/java/org/gridsuite/network/map/dto/definition/topology/BusBarSectionsInfos.java b/src/main/java/org/gridsuite/network/map/dto/definition/topology/BusBarSectionsInfos.java new file mode 100644 index 00000000..d1a4c5f0 --- /dev/null +++ b/src/main/java/org/gridsuite/network/map/dto/definition/topology/BusBarSectionsInfos.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2025, 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.network.map.dto.definition.topology; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.powsybl.iidm.network.TopologyKind; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.SuperBuilder; + +import java.util.List; +import java.util.Map; + +/** + * @author Rehili Ghazwa + */ +@SuperBuilder +@Getter +@Setter +public class BusBarSectionsInfos { + + @JsonInclude(JsonInclude.Include.NON_NULL) + private TopologyKind topologyKind; + + @JsonInclude(JsonInclude.Include.NON_NULL) + private Boolean isSymmetrical; + + @JsonInclude(JsonInclude.Include.NON_NULL) + Boolean isBusbarSectionPositionFound; + + @JsonInclude(JsonInclude.Include.NON_NULL) + Map> busBarSections; +} + diff --git a/src/main/java/org/gridsuite/network/map/dto/definition/voltagelevel/FeederBayInfos.java b/src/main/java/org/gridsuite/network/map/dto/definition/topology/FeederBayInfos.java similarity index 90% rename from src/main/java/org/gridsuite/network/map/dto/definition/voltagelevel/FeederBayInfos.java rename to src/main/java/org/gridsuite/network/map/dto/definition/topology/FeederBayInfos.java index 0a22a6ca..b268c116 100644 --- a/src/main/java/org/gridsuite/network/map/dto/definition/voltagelevel/FeederBayInfos.java +++ b/src/main/java/org/gridsuite/network/map/dto/definition/topology/FeederBayInfos.java @@ -4,7 +4,7 @@ * 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.network.map.dto.definition.voltagelevel; +package org.gridsuite.network.map.dto.definition.topology; import com.powsybl.iidm.network.TwoSides; import org.gridsuite.network.map.dto.definition.extension.ConnectablePositionInfos; diff --git a/src/main/java/org/gridsuite/network/map/dto/definition/topology/FeederBaysBusBarSectionsInfos.java b/src/main/java/org/gridsuite/network/map/dto/definition/topology/FeederBaysBusBarSectionsInfos.java new file mode 100644 index 00000000..9ac645c0 --- /dev/null +++ b/src/main/java/org/gridsuite/network/map/dto/definition/topology/FeederBaysBusBarSectionsInfos.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2025, 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.network.map.dto.definition.topology; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.SuperBuilder; + +import java.util.List; +import java.util.Map; + +/** + * @author Etienne Lesot + */ +@SuperBuilder +@Getter +@Setter +public class FeederBaysBusBarSectionsInfos { + + @JsonInclude(JsonInclude.Include.NON_NULL) + private Map> feederBaysInfos; + @JsonInclude(JsonInclude.Include.NON_NULL) + private BusBarSectionsInfos busBarSectionsInfos; +} diff --git a/src/main/java/org/gridsuite/network/map/dto/SwitchInfos.java b/src/main/java/org/gridsuite/network/map/dto/definition/topology/SwitchInfos.java similarity index 81% rename from src/main/java/org/gridsuite/network/map/dto/SwitchInfos.java rename to src/main/java/org/gridsuite/network/map/dto/definition/topology/SwitchInfos.java index 9015b6cd..4afa16eb 100644 --- a/src/main/java/org/gridsuite/network/map/dto/SwitchInfos.java +++ b/src/main/java/org/gridsuite/network/map/dto/definition/topology/SwitchInfos.java @@ -4,10 +4,11 @@ * 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.network.map.dto; +package org.gridsuite.network.map.dto.definition.topology; import lombok.Getter; import lombok.experimental.SuperBuilder; +import org.gridsuite.network.map.dto.ElementInfos; /** * @author Rehili Ghazwa diff --git a/src/main/java/org/gridsuite/network/map/dto/definition/voltagelevel/VoltageLevelFormInfos.java b/src/main/java/org/gridsuite/network/map/dto/definition/voltagelevel/VoltageLevelFormInfos.java index 9ede0d8b..ef7ce9ad 100644 --- a/src/main/java/org/gridsuite/network/map/dto/definition/voltagelevel/VoltageLevelFormInfos.java +++ b/src/main/java/org/gridsuite/network/map/dto/definition/voltagelevel/VoltageLevelFormInfos.java @@ -10,12 +10,12 @@ import com.powsybl.iidm.network.SwitchKind; import com.powsybl.iidm.network.TopologyKind; import lombok.Getter; +import lombok.Setter; import lombok.experimental.SuperBuilder; import org.gridsuite.network.map.dto.ElementInfosWithProperties; import org.gridsuite.network.map.dto.definition.extension.IdentifiableShortCircuitInfos; import java.util.List; -import java.util.Map; import java.util.Optional; /** @@ -23,25 +23,12 @@ */ @SuperBuilder @Getter +@Setter public class VoltageLevelFormInfos extends ElementInfosWithProperties { @JsonInclude(JsonInclude.Include.NON_NULL) private TopologyKind topologyKind; - @JsonInclude(JsonInclude.Include.NON_NULL) - private String substationId; - - private double nominalV; - - @JsonInclude(JsonInclude.Include.NON_NULL) - private Double lowVoltageLimit; - - @JsonInclude(JsonInclude.Include.NON_NULL) - private Double highVoltageLimit; - - @JsonInclude(JsonInclude.Include.NON_ABSENT) - private Optional identifiableShortCircuit; - @JsonInclude(JsonInclude.Include.NON_NULL) private Integer busbarCount; @@ -52,14 +39,19 @@ public class VoltageLevelFormInfos extends ElementInfosWithProperties { private List switchKinds; @JsonInclude(JsonInclude.Include.NON_NULL) - private Boolean isRetrievedBusbarSections; + private Boolean isSymmetrical; @JsonInclude(JsonInclude.Include.NON_NULL) - private Boolean isBusbarSectionPositionFound; + private String substationId; + + private double nominalV; @JsonInclude(JsonInclude.Include.NON_NULL) - private Map> busBarSectionInfos; + private Double lowVoltageLimit; @JsonInclude(JsonInclude.Include.NON_NULL) - private Map> feederBaysInfos; + private Double highVoltageLimit; + + @JsonInclude(JsonInclude.Include.NON_ABSENT) + private Optional identifiableShortCircuit; } diff --git a/src/main/java/org/gridsuite/network/map/dto/mapper/VoltageLevelInfosMapper.java b/src/main/java/org/gridsuite/network/map/dto/mapper/VoltageLevelInfosMapper.java index 76547d09..518104c1 100644 --- a/src/main/java/org/gridsuite/network/map/dto/mapper/VoltageLevelInfosMapper.java +++ b/src/main/java/org/gridsuite/network/map/dto/mapper/VoltageLevelInfosMapper.java @@ -10,21 +10,20 @@ import com.powsybl.iidm.network.extensions.BusbarSectionPosition; import lombok.Builder; import lombok.Getter; -import lombok.Setter; import org.gridsuite.network.map.dto.ElementInfos; import org.gridsuite.network.map.dto.InfoTypeParameters; -import org.gridsuite.network.map.dto.definition.busbarsection.BusBarSectionFormInfos; -import org.gridsuite.network.map.dto.definition.voltagelevel.FeederBayInfos; import org.gridsuite.network.map.dto.definition.voltagelevel.VoltageLevelFormInfos; import org.gridsuite.network.map.dto.definition.voltagelevel.VoltageLevelMapInfos; import org.gridsuite.network.map.dto.definition.voltagelevel.VoltageLevelTabInfos; import org.gridsuite.network.map.dto.utils.ElementUtils; import org.gridsuite.network.map.dto.utils.ExtensionUtils; -import java.util.*; -import java.util.stream.Collectors; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; -import static com.powsybl.iidm.network.Terminal.getConnectableSide; +import static org.gridsuite.network.map.dto.mapper.VoltageLevelInfosMapper.TopologyInfos.setDefaultBuilder; import static org.gridsuite.network.map.dto.utils.ElementUtils.*; /** @@ -44,53 +43,9 @@ public static ElementInfos toData(Identifiable identifiable, InfoTypeParamete }; } - private static VoltageLevelTopologyInfos getTopologyInfos(VoltageLevel voltageLevel) { - Map nbSectionsPerBusbar = new HashMap<>(); - List busbarSectionInfos = new ArrayList<>(); - int maxBusbarIndex = 1; - int maxSectionIndex = 1; - boolean busbarSectionPositionFound = true; - for (BusbarSection bbs : voltageLevel.getNodeBreakerView().getBusbarSections()) { - var extension = bbs.getExtension(BusbarSectionPosition.class); - if (extension == null) { - busbarSectionPositionFound = false; - break; - } - int busbarIndex = extension.getBusbarIndex(); - int sectionIndex = extension.getSectionIndex(); - maxBusbarIndex = Math.max(maxBusbarIndex, busbarIndex); - maxSectionIndex = Math.max(maxSectionIndex, sectionIndex); - nbSectionsPerBusbar.merge(busbarIndex, 1, Integer::sum); - busbarSectionInfos.add(BusBarSectionFormInfos.builder() - .id(bbs.getId()) - .vertPos(sectionIndex) - .horizPos(busbarIndex) - .build()); - } - VoltageLevelTopologyInfos voltageLevelTopologyInfos = createDefaultTopologyInfosBuilder().build(); - if (!busbarSectionPositionFound) { - return voltageLevelTopologyInfos; - } - - voltageLevelTopologyInfos.setBusbarSections(busbarSectionInfos); - voltageLevelTopologyInfos.setBusbarSectionPositionFound(true); - - boolean isSymmetrical = maxBusbarIndex == 1 || - nbSectionsPerBusbar.values().stream().distinct().count() == 1 - && nbSectionsPerBusbar.values().stream().findFirst().orElse(0).equals(maxSectionIndex); - - if (isSymmetrical) { - voltageLevelTopologyInfos.setBusbarCount(maxBusbarIndex); - voltageLevelTopologyInfos.setSectionCount(maxSectionIndex); - voltageLevelTopologyInfos.setRetrievedBusbarSections(true); - voltageLevelTopologyInfos.setSwitchKinds(Collections.nCopies(maxSectionIndex - 1, SwitchKind.DISCONNECTOR)); - } - return voltageLevelTopologyInfos; - } - static VoltageLevelFormInfos toFormInfos(Identifiable identifiable) { VoltageLevel voltageLevel = (VoltageLevel) identifiable; - VoltageLevelFormInfos.VoltageLevelFormInfosBuilder builder = VoltageLevelFormInfos.builder() + VoltageLevelFormInfos voltageLevelFormInfos = VoltageLevelFormInfos.builder() .name(voltageLevel.getOptionalName().orElse(null)) .id(voltageLevel.getId()) .topologyKind(voltageLevel.getTopologyKind()) @@ -98,44 +53,17 @@ static VoltageLevelFormInfos toFormInfos(Identifiable identifiable) { .nominalV(voltageLevel.getNominalV()) .lowVoltageLimit(Double.isNaN(voltageLevel.getLowVoltageLimit()) ? null : voltageLevel.getLowVoltageLimit()) .highVoltageLimit(Double.isNaN(voltageLevel.getHighVoltageLimit()) ? null : voltageLevel.getHighVoltageLimit()) - .properties(getProperties(voltageLevel)); - + .properties(getProperties(voltageLevel)) + .identifiableShortCircuit(ExtensionUtils.toIdentifiableShortCircuit(voltageLevel)) + .build(); if (voltageLevel.getTopologyKind().equals(TopologyKind.NODE_BREAKER)) { - VoltageLevelTopologyInfos vlTopologyInfos = getTopologyInfos(voltageLevel); - builder.busbarCount(vlTopologyInfos.getBusbarCount()); - builder.sectionCount(vlTopologyInfos.getSectionCount()); - builder.switchKinds(vlTopologyInfos.getSwitchKinds()); - builder.isRetrievedBusbarSections(vlTopologyInfos.isRetrievedBusbarSections()); - builder.isBusbarSectionPositionFound(vlTopologyInfos.isBusbarSectionPositionFound()); - builder.busBarSectionInfos(vlTopologyInfos.getBusBarSectionInfosGrouped()); - builder.feederBaysInfos(getFeederBaysInfos(voltageLevel)); + TopologyInfos topologyInfos = getVoltageLevelBusBarSectionsInfos(voltageLevel); + voltageLevelFormInfos.setBusbarCount(topologyInfos.getBusbarCount()); + voltageLevelFormInfos.setSectionCount(topologyInfos.getSectionCount()); + voltageLevelFormInfos.setSwitchKinds(topologyInfos.getSwitchKinds()); + voltageLevelFormInfos.setIsSymmetrical(topologyInfos.getIsSymmetrical()); } - - builder.identifiableShortCircuit(ExtensionUtils.toIdentifiableShortCircuit(voltageLevel)); - - return builder.build(); - } - - private static Map> getFeederBaysInfos(VoltageLevel voltageLevel) { - Map> feederBayInfos = new HashMap<>(); - String currentVoltageLevelId = voltageLevel.getId(); - voltageLevel.getConnectableStream() - .filter(connectable -> !(connectable instanceof BusbarSection)) - .forEach(connectable -> { - List connections = new ArrayList<>(); - for (Object obj : connectable.getTerminals()) { - Terminal terminal = (Terminal) obj; - if (terminal.getVoltageLevel().getId().equals(currentVoltageLevelId)) { - connections.add(new FeederBayInfos( - getBusOrBusbarSection(terminal), - getConnectablePosition(connectable, FeederSide.from(getConnectableSide(terminal))), - getConnectableSide(terminal).map(ThreeSides::toTwoSides).orElse(null) - )); - } - } - feederBayInfos.put(connectable.getId(), connections); - }); - return feederBayInfos; + return voltageLevelFormInfos; } static VoltageLevelMapInfos toMapInfos(Identifiable identifiable) { @@ -151,7 +79,7 @@ static VoltageLevelMapInfos toMapInfos(Identifiable identifiable) { static VoltageLevelTabInfos toTabInfos(Identifiable identifiable) { VoltageLevel voltageLevel = (VoltageLevel) identifiable; - VoltageLevelTabInfos.VoltageLevelTabInfosBuilder builder = VoltageLevelTabInfos.builder() + VoltageLevelTabInfos.VoltageLevelTabInfosBuilder builder = VoltageLevelTabInfos.builder() .id(voltageLevel.getId()) .name(voltageLevel.getOptionalName().orElse(null)) .substationId(voltageLevel.getSubstation().map(Substation::getId).orElse(null)) @@ -166,35 +94,53 @@ static VoltageLevelTabInfos toTabInfos(Identifiable identifiable) { return builder.build(); } - private static VoltageLevelTopologyInfos.VoltageLevelTopologyInfosBuilder createDefaultTopologyInfosBuilder() { - return VoltageLevelTopologyInfos.builder() - .busbarCount(1).sectionCount(1).isRetrievedBusbarSections(false) - .switchKinds(List.of()).busbarSections(List.of()).isBusbarSectionPositionFound(false); - } - @Builder @Getter - @Setter - public static class VoltageLevelTopologyInfos { - private List busbarSections; - private boolean isRetrievedBusbarSections; // true if busbar sections are symmetrical - private boolean isBusbarSectionPositionFound; - private int busbarCount; - private int sectionCount; + public static class TopologyInfos { + private Integer busbarCount; + + private Integer sectionCount; + private List switchKinds; - public Map> getBusBarSectionInfosGrouped() { - return busbarSections.stream() - .collect(Collectors.groupingBy( - section -> String.valueOf(section.getHorizPos()), - Collectors.collectingAndThen( - Collectors.toList(), - list -> list.stream() - .sorted(Comparator.comparing(BusBarSectionFormInfos::getVertPos)) - .map(BusBarSectionFormInfos::getId) - .toList() - ) - )); + private Boolean isSymmetrical; + + public static TopologyInfos.TopologyInfosBuilder setDefaultBuilder() { + return TopologyInfos.builder().busbarCount(1) + .sectionCount(1) + .switchKinds(Collections.emptyList()) + .isSymmetrical(false); + } + } + + public static TopologyInfos getVoltageLevelBusBarSectionsInfos(VoltageLevel voltageLevel) { + Map nbSectionsPerBusbar = new HashMap<>(); + TopologyInfos.TopologyInfosBuilder builder = setDefaultBuilder(); + int maxBusbarIndex = 1; + int maxSectionIndex = 1; + for (BusbarSection bbs : voltageLevel.getNodeBreakerView().getBusbarSections()) { + var extension = bbs.getExtension(BusbarSectionPosition.class); + if (extension == null) { + return builder.build(); + } + int busbarIndex = extension.getBusbarIndex(); + int sectionIndex = extension.getSectionIndex(); + maxBusbarIndex = Math.max(maxBusbarIndex, busbarIndex); + maxSectionIndex = Math.max(maxSectionIndex, sectionIndex); + nbSectionsPerBusbar.merge(busbarIndex, 1, Integer::sum); + } + + boolean isSymmetrical = maxBusbarIndex == 1 || + nbSectionsPerBusbar.values().stream().distinct().count() == 1 + && nbSectionsPerBusbar.values().stream().findFirst().orElse(0).equals(maxSectionIndex); + + if (isSymmetrical) { + return builder.busbarCount(maxBusbarIndex) + .sectionCount(maxSectionIndex) + .switchKinds(Collections.nCopies(maxSectionIndex - 1, SwitchKind.DISCONNECTOR)) + .isSymmetrical(true) + .build(); } + return builder.build(); } } diff --git a/src/main/java/org/gridsuite/network/map/dto/utils/TopologyUtils.java b/src/main/java/org/gridsuite/network/map/dto/utils/TopologyUtils.java new file mode 100644 index 00000000..21ee36c4 --- /dev/null +++ b/src/main/java/org/gridsuite/network/map/dto/utils/TopologyUtils.java @@ -0,0 +1,111 @@ +/** + * Copyright (c) 2025, 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.network.map.dto.utils; + +import com.powsybl.iidm.network.*; +import com.powsybl.iidm.network.extensions.BusbarSectionPosition; +import org.gridsuite.network.map.dto.definition.busbarsection.BusBarSectionFormInfos; +import org.gridsuite.network.map.dto.definition.topology.BusBarSectionsInfos; +import org.gridsuite.network.map.dto.definition.topology.FeederBayInfos; +import org.gridsuite.network.map.dto.definition.topology.SwitchInfos; + +import java.util.*; +import java.util.stream.Collectors; + +import static com.powsybl.iidm.network.Terminal.getConnectableSide; +import static org.gridsuite.network.map.dto.utils.ElementUtils.getBusOrBusbarSection; +import static org.gridsuite.network.map.dto.utils.ElementUtils.getConnectablePosition; + +/** + * @author Etienne Lesot + */ +public final class TopologyUtils { + + private TopologyUtils() { } + + public static BusBarSectionsInfos getBusBarSectionsInfos(VoltageLevel voltageLevel) { + Map nbSectionsPerBusbar = new HashMap<>(); + List busbarSectionInfos = new ArrayList<>(); + BusBarSectionsInfos busBarSectionsInfos = BusBarSectionsInfos.builder() + .isBusbarSectionPositionFound(true) + .isSymmetrical(false) + .build(); + int maxBusbarIndex = 1; + int maxSectionIndex = 1; + for (BusbarSection bbs : voltageLevel.getNodeBreakerView().getBusbarSections()) { + var extension = bbs.getExtension(BusbarSectionPosition.class); + if (extension == null) { + busBarSectionsInfos.setIsBusbarSectionPositionFound(false); + break; + } + int busbarIndex = extension.getBusbarIndex(); + int sectionIndex = extension.getSectionIndex(); + maxBusbarIndex = Math.max(maxBusbarIndex, busbarIndex); + maxSectionIndex = Math.max(maxSectionIndex, sectionIndex); + nbSectionsPerBusbar.merge(busbarIndex, 1, Integer::sum); + busbarSectionInfos.add(BusBarSectionFormInfos.builder() + .id(bbs.getId()) + .vertPos(sectionIndex) + .horizPos(busbarIndex) + .build()); + } + + busBarSectionsInfos.setBusBarSections(busbarSectionInfos.stream() + .collect(Collectors.groupingBy( + section -> String.valueOf(section.getHorizPos()), + Collectors.collectingAndThen( + Collectors.toList(), + list -> list.stream() + .sorted(Comparator.comparing(BusBarSectionFormInfos::getVertPos)) + .map(BusBarSectionFormInfos::getId) + .toList() + ) + ))); + + boolean isSymmetrical = maxBusbarIndex == 1 || + nbSectionsPerBusbar.values().stream().distinct().count() == 1 + && nbSectionsPerBusbar.values().stream().findFirst().orElse(0).equals(maxSectionIndex); + + if (isSymmetrical) { + busBarSectionsInfos.setIsSymmetrical(true); + } + busBarSectionsInfos.setTopologyKind(voltageLevel.getTopologyKind()); + return busBarSectionsInfos; + } + + public static Map> getFeederBaysInfos(VoltageLevel voltageLevel) { + Map> feederBayInfos = new HashMap<>(); + String currentVoltageLevelId = voltageLevel.getId(); + voltageLevel.getConnectableStream() + .filter(connectable -> !(connectable instanceof BusbarSection)) + .forEach(connectable -> { + List connections = new ArrayList<>(); + for (Object obj : connectable.getTerminals()) { + Terminal terminal = (Terminal) obj; + if (terminal.getVoltageLevel().getId().equals(currentVoltageLevelId)) { + connections.add(new FeederBayInfos( + getBusOrBusbarSection(terminal), + getConnectablePosition(connectable, ElementUtils.FeederSide.from(getConnectableSide(terminal))), + getConnectableSide(terminal).map(ThreeSides::toTwoSides).orElse(null) + )); + } + } + feederBayInfos.put(connectable.getId(), connections); + }); + return feederBayInfos; + } + + public static List getSwitchesInfos(String voltageLevelId, Network network) { + List switchInfosList = new ArrayList<>(); + network.getVoltageLevel(voltageLevelId).getSwitches().forEach(sw -> + switchInfosList.add(SwitchInfos.builder() + .id(sw.getId()) + .open(sw.isOpen()) + .build())); + return switchInfosList; + } +} diff --git a/src/main/java/org/gridsuite/network/map/services/NetworkMapService.java b/src/main/java/org/gridsuite/network/map/services/NetworkMapService.java index 95a26f6b..4a19ce11 100644 --- a/src/main/java/org/gridsuite/network/map/services/NetworkMapService.java +++ b/src/main/java/org/gridsuite/network/map/services/NetworkMapService.java @@ -12,10 +12,17 @@ import com.powsybl.network.store.client.NetworkStoreService; import com.powsybl.network.store.client.PreloadingStrategy; import lombok.AllArgsConstructor; -import org.gridsuite.network.map.dto.*; +import org.gridsuite.network.map.dto.AllElementsInfos; +import org.gridsuite.network.map.dto.ElementInfos; +import org.gridsuite.network.map.dto.ElementType; +import org.gridsuite.network.map.dto.InfoTypeParameters; import org.gridsuite.network.map.dto.definition.hvdc.HvdcShuntCompensatorsInfos; +import org.gridsuite.network.map.dto.definition.topology.BusBarSectionsInfos; +import org.gridsuite.network.map.dto.definition.topology.FeederBaysBusBarSectionsInfos; +import org.gridsuite.network.map.dto.definition.topology.SwitchInfos; import org.gridsuite.network.map.dto.mapper.ElementInfosMapper; import org.gridsuite.network.map.dto.mapper.HvdcInfosMapper; +import org.gridsuite.network.map.dto.utils.TopologyUtils; import org.springframework.context.annotation.ComponentScan; import org.springframework.http.HttpStatus; import org.springframework.lang.NonNull; @@ -124,16 +131,25 @@ public List getVoltageLevelBusesOrBusbarSections(UUID networkUuid, }; } - public List getVoltageLevelSwitches(UUID networkUuid, String voltageLevelId, String variantId) { + public BusBarSectionsInfos getBusBarSectionsInfos(UUID networkUuid, String voltageLevelId, String variantId) { Network network = getNetwork(networkUuid, PreloadingStrategy.NONE, variantId); + VoltageLevel voltageLevel = network.getVoltageLevel(voltageLevelId); + return TopologyUtils.getBusBarSectionsInfos(voltageLevel); + } - List switchInfosList = new ArrayList<>(); - network.getVoltageLevel(voltageLevelId).getSwitches().forEach(sw -> - switchInfosList.add(SwitchInfos.builder() - .id(sw.getId()) - .open(sw.isOpen()) - .build())); - return switchInfosList; + public FeederBaysBusBarSectionsInfos getFeederBaysInfos(UUID networkUuid, String voltageLevelId, String variantId) { + Network network = getNetwork(networkUuid, PreloadingStrategy.NONE, variantId); + VoltageLevel voltageLevel = network.getVoltageLevel(voltageLevelId); + FeederBaysBusBarSectionsInfos.FeederBaysBusBarSectionsInfosBuilder builder = FeederBaysBusBarSectionsInfos.builder(); + builder.feederBaysInfos(TopologyUtils.getFeederBaysInfos(voltageLevel)); + builder.busBarSectionsInfos(TopologyUtils.getBusBarSectionsInfos(voltageLevel)); + return builder.build(); + } + + public List getSwitchInfos(UUID networkUuid, String voltageLevelId, String variantId) { + Network network = getNetwork(networkUuid, PreloadingStrategy.NONE, variantId); + VoltageLevel voltageLevel = network.getVoltageLevel(voltageLevelId); + return TopologyUtils.getSwitchesInfos(voltageLevel.getId(), network); } public String getVoltageLevelSubstationID(UUID networkUuid, String voltageLevelId, String variantId) { diff --git a/src/test/java/org/gridsuite/network/map/NetworkMapControllerTest.java b/src/test/java/org/gridsuite/network/map/NetworkMapControllerTest.java index dac6d802..c7d59bb6 100644 --- a/src/test/java/org/gridsuite/network/map/NetworkMapControllerTest.java +++ b/src/test/java/org/gridsuite/network/map/NetworkMapControllerTest.java @@ -18,8 +18,8 @@ import com.powsybl.network.store.iidm.impl.NetworkFactoryImpl; import org.gridsuite.network.map.dto.ElementInfos.InfoType; import org.gridsuite.network.map.dto.ElementType; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -79,6 +79,7 @@ public class NetworkMapControllerTest { public static final String QUERY_PARAM_LOAD_REGULATING_TERMINALS = "loadRegulatingTerminals"; public static final String QUERY_PARAM_LOAD_NETWORK_COMPONENTS = "loadNetworkComponents"; public static final String QUERY_PARAM_NOMINAL_VOLTAGES = "nominalVoltages"; + public static final String QUERY_PARAM_FILTERS = "filters"; @Autowired private MockMvc mvc; @@ -1445,6 +1446,33 @@ private static String resourceToString(String resource) throws IOException { return new String(ByteStreams.toByteArray(NetworkMapControllerTest.class.getResourceAsStream(resource)), StandardCharsets.UTF_8); } + private void succeedingTestGettingFeederBaysAndBusBarSectionsInfos(UUID networkUuid, String variantId, String voltageLevelId, String expectedJson) throws Exception { + MvcResult res = mvc.perform(get("/v1/networks/{networkUuid}/voltage-levels/{voltageLevelId}/feeder-bays-and-bus-bar-sections", networkUuid, voltageLevelId) + .queryParam(QUERY_PARAM_VARIANT_ID, variantId)) + .andExpect(status().isOk()) + .andReturn(); + System.out.println(res.getResponse().getContentAsString()); + JSONAssert.assertEquals(expectedJson, res.getResponse().getContentAsString(), JSONCompareMode.NON_EXTENSIBLE); + } + + private void succeedingTestGettingBusBarSectionsInfos(UUID networkUuid, String variantId, String voltageLevelId, String expectedJson) throws Exception { + MvcResult res = mvc.perform(get("/v1/networks/{networkUuid}/voltage-levels/{voltageLevelId}/bus-bar-sections", networkUuid, voltageLevelId) + .queryParam(QUERY_PARAM_VARIANT_ID, variantId)) + .andExpect(status().isOk()) + .andReturn(); + System.out.println(res.getResponse().getContentAsString()); + JSONAssert.assertEquals(expectedJson, res.getResponse().getContentAsString(), JSONCompareMode.NON_EXTENSIBLE); + } + + private void succeedingTestGettingSwitchesInfos(UUID networkUuid, String variantId, String voltageLevelId, String expectedJson) throws Exception { + MvcResult res = mvc.perform(get("/v1/networks/{networkUuid}/voltage-levels/{voltageLevelId}/switches", networkUuid, voltageLevelId) + .queryParam(QUERY_PARAM_VARIANT_ID, variantId)) + .andExpect(status().isOk()) + .andReturn(); + System.out.println(res.getResponse().getContentAsString()); + JSONAssert.assertEquals(expectedJson, res.getResponse().getContentAsString(), JSONCompareMode.NON_EXTENSIBLE); + } + private void succeedingTestForElementInfosWithElementId(UUID networkUuid, String variantId, ElementType elementType, InfoType infoType, String elementId, String expectedJson) throws Exception { MvcResult res = mvc.perform(get("/v1/networks/{networkUuid}/elements/{elementId}", networkUuid, elementId) .queryParam(QUERY_PARAM_VARIANT_ID, variantId) @@ -1453,7 +1481,6 @@ private void succeedingTestForElementInfosWithElementId(UUID networkUuid, String ) .andExpect(status().isOk()) .andReturn(); - JSONAssert.assertEquals(expectedJson, res.getResponse().getContentAsString(), JSONCompareMode.NON_EXTENSIBLE); } @@ -2343,12 +2370,23 @@ void shouldReturnVoltageLevelFormData() throws Exception { } @Test - void shouldReturnVoltageLevelFormDataWithFeederBaysInfos() throws Exception { - succeedingTestForElementInfosWithElementId(NETWORK_UUID, null, ElementType.VOLTAGE_LEVEL, InfoType.FORM, "VLGEN5", resourceToString("/voltage-level-form-data-feederbays.json")); + void shouldReturnVoltageLevelBusbarSectionsFormInfos() throws Exception { + succeedingTestGettingBusBarSectionsInfos(NETWORK_UUID, null, "VLGEN4", resourceToString("/busbar-sections-all-data.json")); + } + + @Test + void shouldReturnVoltageLevelFeederBaysFormInfos() throws Exception { + succeedingTestGettingFeederBaysAndBusBarSectionsInfos(NETWORK_UUID, null, "VLGEN4", resourceToString("/feeder-bays-data.json")); } @Test - void shouldReturnVotlageLevelNonSymmetricalBusbarsFormData() throws Exception { + void shouldReturnVoltageLevelSwitchesFormInfos() throws Exception { + succeedingTestGettingSwitchesInfos(NETWORK_UUID, null, "VLGEN4", resourceToString("/switches-data.json")); + succeedingTestGettingSwitchesInfos(NETWORK_UUID, VARIANT_ID, "VLGEN4", resourceToString("/switches-data-in-variant.json")); + } + + @Test + void shouldReturnVoltageLevelNonSymmetricalBusbarsFormData() throws Exception { succeedingTestForElementInfosWithElementId(NETWORK_UUID, null, ElementType.VOLTAGE_LEVEL, InfoType.FORM, "VLGEN5", resourceToString("/voltage-level-non-symmetrical-busbars-form-data.json")); succeedingTestForElementInfosWithElementId(NETWORK_UUID, VARIANT_ID, ElementType.VOLTAGE_LEVEL, InfoType.FORM, "VLGEN5", resourceToString("/voltage-level-non-symmetrical-busbars-form-data.json")); } @@ -2385,12 +2423,6 @@ void shouldReturnAnErrorInsteadOfBusbarSectionMapData() throws Exception { failingBusOrBusbarSectionTest("busbar-sections", NETWORK_UUID, "VLGEN4", VARIANT_ID_NOT_FOUND); } - @Test - void shouldReturnSwitchesData() throws Exception { - succeedingEquipmentsTest("switches", NETWORK_UUID, "VLGEN4", null, resourceToString("/switches-data.json")); - succeedingEquipmentsTest("switches", NETWORK_UUID, "VLGEN4", VARIANT_ID, resourceToString("/switches-data-in-variant.json")); - } - @Test void shouldReturnHvdcShuntCompensatorMapData() throws Exception { succeedingHvdcWithShuntCompensatorsTest(NETWORK_UUID, "HVDC1", null, resourceToString("/hvdc-line-with-shunt-compensators-map-data.json")); diff --git a/src/test/resources/busbar-sections-all-data.json b/src/test/resources/busbar-sections-all-data.json new file mode 100644 index 00000000..a9cd3d53 --- /dev/null +++ b/src/test/resources/busbar-sections-all-data.json @@ -0,0 +1,10 @@ +{ + "topologyKind": "NODE_BREAKER", + "isSymmetrical": true, + "isBusbarSectionPositionFound": true, + "busBarSections": { + "1": [ + "NGEN4" + ] + } +} \ No newline at end of file diff --git a/src/test/resources/feeder-bays-data.json b/src/test/resources/feeder-bays-data.json new file mode 100644 index 00000000..8e455f6d --- /dev/null +++ b/src/test/resources/feeder-bays-data.json @@ -0,0 +1,43 @@ +{ + "feederBaysInfos": { + "SHUNT_VLNB": [ + { + "busbarSectionId": "NGEN4", + "connectablePositionInfos": { + "connectionDirection": null + }, + "connectionSide": null + } + ], + "LINE7": [ + { + "busbarSectionId": "NGEN4", + "connectablePositionInfos": { + "connectionDirection": "BOTTOM", + "connectionPosition": 5, + "connectionName": "LINE7_Side_VLGEN4" + }, + "connectionSide": "ONE" + } + ], + "SHUNT_NON_LINEAR": [ + { + "busbarSectionId": "NGEN4", + "connectablePositionInfos": { + "connectionDirection": null + }, + "connectionSide": null + } + ] + }, + "busBarSectionsInfos": { + "topologyKind": "NODE_BREAKER", + "isSymmetrical": true, + "isBusbarSectionPositionFound": true, + "busBarSections": { + "1": [ + "NGEN4" + ] + } + } +} \ No newline at end of file diff --git a/src/test/resources/substations-form-data.json b/src/test/resources/substations-form-data.json index 345e9493..f6e08a97 100644 --- a/src/test/resources/substations-form-data.json +++ b/src/test/resources/substations-form-data.json @@ -101,42 +101,7 @@ "busbarCount": 1, "sectionCount": 2, "switchKinds": ["DISCONNECTOR"], - "isRetrievedBusbarSections": true, - "isBusbarSectionPositionFound": true, - "busBarSectionInfos" : { - "1" : ["NGEN4"] - }, - "feederBaysInfos": { - "SHUNT_VLNB": [ - { - "busbarSectionId": "NGEN4", - "connectablePositionInfos": { - "connectionDirection": null - }, - "connectionSide": null - } - ], - "LINE7": [ - { - "busbarSectionId": "NGEN4", - "connectablePositionInfos": { - "connectionDirection": "BOTTOM", - "connectionPosition": 5, - "connectionName": "LINE7_Side_VLGEN4" - }, - "connectionSide": "ONE" - } - ], - "SHUNT_NON_LINEAR": [ - { - "busbarSectionId": "NGEN4", - "connectablePositionInfos": { - "connectionDirection": null - }, - "connectionSide": null - } - ] - } + "isSymmetrical": true } ] }, @@ -158,22 +123,7 @@ "busbarCount": 1, "sectionCount": 1, "switchKinds": [], - "isRetrievedBusbarSections": false, - "isBusbarSectionPositionFound": true, - "busBarSectionInfos" : { - "1" : [ "NGEN5"], - "2" : [ "NGEN5_2_1", "NGEN5_2_2"] - }, - "busBarSectionInfos": { - "1": [ - "NGEN5" - ], - "2": [ - "NGEN5_2_1", - "NGEN5_2_2" - ] - }, - "feederBaysInfos": {} + "isSymmetrical": false }, { "id": "VLGEN7", @@ -185,22 +135,7 @@ "busbarCount": 1, "sectionCount": 1, "switchKinds": [], - "isRetrievedBusbarSections": false, - "isBusbarSectionPositionFound": false, - "busBarSectionInfos": {}, - "feederBaysInfos": { - "LINE7": [ - { - "busbarSectionId": "NGEN7", - "connectablePositionInfos": { - "connectionDirection": "TOP", - "connectionPosition": 3, - "connectionName": "LINE7_Side_VLGEN8" - }, - "connectionSide": "TWO" - } - ] - } + "isSymmetrical": false } ] } diff --git a/src/test/resources/voltage-level-form-data-feederbays.json b/src/test/resources/voltage-level-form-data-feederbays.json deleted file mode 100644 index 5c2833b7..00000000 --- a/src/test/resources/voltage-level-form-data-feederbays.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "id": "VLGEN5", - "topologyKind": "NODE_BREAKER", - "substationId": "P5", - "nominalV": 24.0, - "lowVoltageLimit": 20.0, - "highVoltageLimit": 30.0, - "identifiableShortCircuit": { - "ipMin": 0.0, - "ipMax": 100.0 - }, - "busbarCount": 1, - "sectionCount": 1, - "switchKinds": [], - "isRetrievedBusbarSections": false, - "isBusbarSectionPositionFound": true, - "busBarSectionInfos": { - "1": [ - "NGEN5" - ], - "2": [ - "NGEN5_2_1", - "NGEN5_2_2" - ] - }, - "feederBaysInfos": {} -} \ No newline at end of file diff --git a/src/test/resources/voltage-level-form-data.json b/src/test/resources/voltage-level-form-data.json index 6d10ba78..94e15227 100644 --- a/src/test/resources/voltage-level-form-data.json +++ b/src/test/resources/voltage-level-form-data.json @@ -6,40 +6,5 @@ "busbarCount": 1, "sectionCount": 2, "switchKinds": ["DISCONNECTOR"], - "isRetrievedBusbarSections": true, - "isBusbarSectionPositionFound": true, - "busBarSectionInfos" : { - "1" : [ "NGEN4"] - }, - "feederBaysInfos": { - "SHUNT_VLNB": [ - { - "busbarSectionId": "NGEN4", - "connectablePositionInfos": { - "connectionDirection": null - }, - "connectionSide": null - } - ], - "LINE7": [ - { - "busbarSectionId": "NGEN4", - "connectablePositionInfos": { - "connectionDirection": "BOTTOM", - "connectionPosition": 5, - "connectionName": "LINE7_Side_VLGEN4" - }, - "connectionSide": "ONE" - } - ], - "SHUNT_NON_LINEAR": [ - { - "busbarSectionId": "NGEN4", - "connectablePositionInfos": { - "connectionDirection": null - }, - "connectionSide": null - } - ] - } -} + "isSymmetrical": true +} \ No newline at end of file diff --git a/src/test/resources/voltage-level-non-symmetrical-busbars-form-data.json b/src/test/resources/voltage-level-non-symmetrical-busbars-form-data.json index 655749e4..e37e3f7a 100644 --- a/src/test/resources/voltage-level-non-symmetrical-busbars-form-data.json +++ b/src/test/resources/voltage-level-non-symmetrical-busbars-form-data.json @@ -12,11 +12,5 @@ "busbarCount": 1, "sectionCount": 1, "switchKinds": [], - "isRetrievedBusbarSections": false, - "isBusbarSectionPositionFound": true, - "busBarSectionInfos" : { - "1" : [ "NGEN5"], - "2" : [ "NGEN5_2_1","NGEN5_2_2"] - }, - "feederBaysInfos": {} -} + "isSymmetrical": false +} \ No newline at end of file diff --git a/src/test/resources/voltage-levels-form-data.json b/src/test/resources/voltage-levels-form-data.json index 1b3f7e25..acb0a9da 100644 --- a/src/test/resources/voltage-levels-form-data.json +++ b/src/test/resources/voltage-levels-form-data.json @@ -62,47 +62,7 @@ "busbarCount": 1, "sectionCount": 2, "switchKinds": ["DISCONNECTOR"], - "isRetrievedBusbarSections": true, - "isBusbarSectionPositionFound": true, - "busBarSectionInfos" : { - "1" : [ "NGEN4" ] - }, - "busBarSectionInfos": { - "1": [ - "NGEN4" - ] - }, - "feederBaysInfos": { - "SHUNT_VLNB": [ - { - "busbarSectionId": "NGEN4", - "connectablePositionInfos": { - "connectionDirection": null - }, - "connectionSide": null - } - ], - "LINE7": [ - { - "busbarSectionId": "NGEN4", - "connectablePositionInfos": { - "connectionDirection": "BOTTOM", - "connectionPosition": 5, - "connectionName": "LINE7_Side_VLGEN4" - }, - "connectionSide": "ONE" - } - ], - "SHUNT_NON_LINEAR": [ - { - "busbarSectionId": "NGEN4", - "connectablePositionInfos": { - "connectionDirection": null - }, - "connectionSide": null - } - ] - } + "isSymmetrical": true }, { "id": "VLGEN5", @@ -118,13 +78,7 @@ "busbarCount": 1, "sectionCount": 1, "switchKinds": [], - "isRetrievedBusbarSections": false, - "isBusbarSectionPositionFound": true, - "busBarSectionInfos" : { - "1" : [ "NGEN5"], - "2" : [ "NGEN5_2_1", "NGEN5_2_2" ] - }, - "feederBaysInfos": {} + "isSymmetrical": false }, { "id": "VLGEN6", @@ -142,21 +96,6 @@ "busbarCount": 1, "sectionCount": 1, "switchKinds": [], - "isRetrievedBusbarSections": false, - "isBusbarSectionPositionFound": false, - "busBarSectionInfos": {}, - "feederBaysInfos": { - "LINE7": [ - { - "busbarSectionId": "NGEN7", - "connectablePositionInfos": { - "connectionDirection": "TOP", - "connectionPosition": 3, - "connectionName": "LINE7_Side_VLGEN8" - }, - "connectionSide": "TWO" - } - ] - } + "isSymmetrical": false } ] \ No newline at end of file