Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/main/java/org/gridsuite/network/map/NetworkMapController.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import lombok.AllArgsConstructor;
import org.gridsuite.network.map.dto.*;
import org.gridsuite.network.map.dto.definition.hvdc.HvdcShuntCompensatorsInfos;
import org.gridsuite.network.map.dto.definition.topology.TopologyInfos;
import org.gridsuite.network.map.services.NetworkMapService;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.bind.annotation.*;
Expand Down Expand Up @@ -98,6 +99,15 @@ public List<SwitchInfos> getVoltageLevelSwitches(@Parameter(description = "Netwo
return networkMapService.getVoltageLevelSwitches(networkUuid, voltageLevelId, variantId);
}

@GetMapping(value = "/networks/{networkUuid}/voltage-levels/{voltageLevelId}/topology", produces = APPLICATION_JSON_VALUE)
@Operation(summary = "Get the voltage level topology description")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Network topology information retrieved")})
public TopologyInfos getVoltageLevelTopology(@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.getVoltageLevelTopology(networkUuid, voltageLevelId, variantId);
}

@GetMapping(value = "/networks/{networkUuid}/voltage-levels/{voltageLevelId}/substation-id", produces = APPLICATION_JSON_VALUE)
@Operation(summary = "Get substation ID for a voltage level")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "substation ID for a voltage level")})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* 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.SwitchKind;
import com.powsybl.iidm.network.TopologyKind;
import lombok.Getter;
import lombok.experimental.SuperBuilder;

import java.util.List;
import java.util.Map;

/**
* @author Etienne Lesot <etienne.lesot at rte-france.com>
*/
@SuperBuilder
@Getter
public class TopologyInfos {
@JsonInclude(JsonInclude.Include.NON_NULL)
private TopologyKind topologyKind;

@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer busbarCount;

@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer sectionCount;

@JsonInclude(JsonInclude.Include.NON_NULL)
private List<SwitchKind> switchKinds;

@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean isSymmetrical;

@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean isBusbarSectionPositionExtensionFound;

@JsonInclude(JsonInclude.Include.NON_NULL)
private Map<String, List<String>> busBarSectionsInfos;

@JsonInclude(JsonInclude.Include.NON_NULL)
private Map<String, List<FeederBayInfos>> feederBaysInfos;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,12 @@
package org.gridsuite.network.map.dto.definition.voltagelevel;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.powsybl.iidm.network.SwitchKind;
import com.powsybl.iidm.network.TopologyKind;
import lombok.Getter;
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;

/**
Expand All @@ -41,25 +38,4 @@ public class VoltageLevelFormInfos extends ElementInfosWithProperties {

@JsonInclude(JsonInclude.Include.NON_ABSENT)
private Optional<IdentifiableShortCircuitInfos> identifiableShortCircuit;

@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer busbarCount;

@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer sectionCount;

@JsonInclude(JsonInclude.Include.NON_NULL)
private List<SwitchKind> switchKinds;

@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean isRetrievedBusbarSections;

@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean isBusbarSectionPositionFound;

@JsonInclude(JsonInclude.Include.NON_NULL)
private Map<String, List<String>> busBarSectionInfos;

@JsonInclude(JsonInclude.Include.NON_NULL)
private Map<String, List<FeederBayInfos>> feederBaysInfos;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,17 @@
*/
package org.gridsuite.network.map.dto.mapper;

import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.BusbarSectionPosition;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import com.powsybl.iidm.network.Identifiable;
import com.powsybl.iidm.network.Substation;
import com.powsybl.iidm.network.VoltageLevel;
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 static com.powsybl.iidm.network.Terminal.getConnectableSide;
import static org.gridsuite.network.map.dto.utils.ElementUtils.*;

/**
Expand All @@ -44,98 +36,19 @@ public static ElementInfos toData(Identifiable<?> identifiable, InfoTypeParamete
};
}

private static VoltageLevelTopologyInfos getTopologyInfos(VoltageLevel voltageLevel) {
Map<Integer, Integer> nbSectionsPerBusbar = new HashMap<>();
List<BusBarSectionFormInfos> 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()
return VoltageLevelFormInfos.builder()
.name(voltageLevel.getOptionalName().orElse(null))
.id(voltageLevel.getId())
.topologyKind(voltageLevel.getTopologyKind())
.substationId(voltageLevel.getSubstation().map(Substation::getId).orElse(null))
.nominalV(voltageLevel.getNominalV())
.lowVoltageLimit(Double.isNaN(voltageLevel.getLowVoltageLimit()) ? null : voltageLevel.getLowVoltageLimit())
.highVoltageLimit(Double.isNaN(voltageLevel.getHighVoltageLimit()) ? null : voltageLevel.getHighVoltageLimit())
.properties(getProperties(voltageLevel));

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));
}

builder.identifiableShortCircuit(ExtensionUtils.toIdentifiableShortCircuit(voltageLevel));

return builder.build();
}

private static Map<String, List<FeederBayInfos>> getFeederBaysInfos(VoltageLevel voltageLevel) {
Map<String, List<FeederBayInfos>> feederBayInfos = new HashMap<>();
String currentVoltageLevelId = voltageLevel.getId();
voltageLevel.getConnectableStream()
.filter(connectable -> !(connectable instanceof BusbarSection))
.forEach(connectable -> {
List<FeederBayInfos> 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;
.properties(getProperties(voltageLevel))
.identifiableShortCircuit(ExtensionUtils.toIdentifiableShortCircuit(voltageLevel))
.build();
}

static VoltageLevelMapInfos toMapInfos(Identifiable<?> identifiable) {
Expand Down Expand Up @@ -165,36 +78,4 @@ 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<BusBarSectionFormInfos> busbarSections;
private boolean isRetrievedBusbarSections; // true if busbar sections are symmetrical
private boolean isBusbarSectionPositionFound;
private int busbarCount;
private int sectionCount;
private List<SwitchKind> switchKinds;

public Map<String, List<String>> 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()
)
));
}
}
}
Loading