Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Psse: node breaker convert process #2982

Merged
merged 38 commits into from
Dec 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
b0c2d98
copy of the imported PSSE model to make the updates and export (deep …
marqueslanauja Mar 21, 2024
7947a24
Merge branch 'main' into psse_copy
marqueslanauja Mar 27, 2024
3d106ed
Merge branch 'main' into psse_copy
marqueslanauja Apr 10, 2024
362d13f
Import and update substation data
marqueslanauja Apr 11, 2024
5e93847
Remove duplicated code
marqueslanauja Apr 11, 2024
cab4aa1
Fix code smells
marqueslanauja Apr 11, 2024
67ff326
Fix code smells
marqueslanauja Apr 11, 2024
b39afef
nodeBreaker convert
marqueslanauja Apr 17, 2024
b74848e
Fix code smells
marqueslanauja Apr 17, 2024
e896564
Add tests. Last changes
marqueslanauja Apr 22, 2024
b2203bc
Fix code smells
marqueslanauja Apr 22, 2024
cff26cf
Merge branch 'main' into psse_nodeBreaker_convert
marqueslanauja Apr 22, 2024
0162bad
Merge branch 'main' into psse_nodeBreaker_convert
marqueslanauja Apr 23, 2024
57362ce
Merge branch 'main' into psse_nodeBreaker_convert
marqueslanauja Apr 25, 2024
8ad9c73
Merge branch 'main' into psse_nodeBreaker_convert
marqueslanauja May 2, 2024
decd4b8
Merge branch 'main' into psse_nodeBreaker_convert
marqueslanauja Jun 3, 2024
786bc59
Merge branch 'main' into psse_nodeBreaker_convert
marqueslanauja Jun 3, 2024
b8698d6
Merge branch 'main' into psse_nodeBreaker_convert
marqueslanauja Jun 7, 2024
364a2f7
switching device type must be an integer
marqueslanauja Jun 11, 2024
e6900f6
Adjust to full export
marqueslanauja Jun 17, 2024
24711a1
Fix code smells
marqueslanauja Jun 17, 2024
ff611be
Reduce method complexity
marqueslanauja Jun 17, 2024
1afb085
Merge branch 'main' into psse_nodeBreaker_convert
marqueslanauja Jun 17, 2024
34ed5a0
Merge branch 'main' into psse_nodeBreaker_convert
marqueslanauja Jul 12, 2024
916148b
Remove setCont
marqueslanauja Jul 12, 2024
93b063b
Fix unitary results
marqueslanauja Jul 12, 2024
da0621a
Merge branch 'main' into psse_nodeBreaker_convert
marqueslanauja Aug 6, 2024
c560041
Fix typo
marqueslanauja Aug 6, 2024
f740d86
Adjustments after testing a private real case
marqueslanauja Aug 6, 2024
f2e6b48
Adjustments after testing with a private real case
marqueslanauja Aug 9, 2024
6fbd508
Merge branch 'main' into psse_nodeBreaker_convert
marqueslanauja Sep 2, 2024
e180561
Some improvements
marqueslanauja Sep 10, 2024
a8d5696
Typo
marqueslanauja Sep 12, 2024
2755290
Merge branch 'main' into psse_nodeBreaker_convert
marqueslanauja Oct 2, 2024
3f1009b
Merge branch 'main' into psse_nodeBreaker_convert
marqueslanauja Dec 20, 2024
2b555d0
Fix last update
marqueslanauja Dec 20, 2024
e9ece62
Merge branch 'main' into psse_nodeBreaker_convert
geofjamg Dec 30, 2024
3b130b3
Minor clean
geofjamg Dec 30, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public class ContainersMapping {

private final Map<String, String> voltageLevelIdToSubstationId = new HashMap<>();

public Set<Integer> getBusesSet(String voltageLevelId) {
return voltageLevelIdToBusNums.computeIfAbsent(voltageLevelId, k -> new HashSet<>());
}

public String getVoltageLevelId(int num) {
String voltageLevelId = busNumToVoltageLevelId.get(num);
if (voltageLevelId == null) {
Expand Down Expand Up @@ -60,11 +64,21 @@ public static <N, B> ContainersMapping create(List<N> buses, List<B> branches, T
throw new PowsyblException("Deprecated. Not used anymore");
}

public static <N, B> ContainersMapping create(List<N> buses, List<B> branches,
ToIntFunction<N> busToNum, ToIntFunction<B> branchToNum1, ToIntFunction<B> branchToNum2,
Predicate<B> branchToIsZeroImpedance, Predicate<B> branchToIsTransformer,
ToDoubleFunction<Integer> busToNominalVoltage, Function<Set<Integer>, String> busesToVoltageLevelId,
Function<Set<Integer>, String> busesToSubstationId) {

return create(buses, branches, busToNum, branchToNum1, branchToNum2, branchToIsZeroImpedance, branchToIsTransformer, busToNominalVoltage,
null, busesToVoltageLevelId, busesToSubstationId);
}

public static <N, B> ContainersMapping create(List<N> buses, List<B> branches,
ToIntFunction<N> busToNum, ToIntFunction<B> branchToNum1, ToIntFunction<B> branchToNum2,
Predicate<B> branchToIsZeroImpedance, Predicate<B> branchToIsTransformer,
ToDoubleFunction<Integer> busToNominalVoltage, Function<Set<Integer>, String> busesToVoltageLevelId,
Function<Set<Integer>, String> busesToSubstationId) {
ToDoubleFunction<Integer> busToNominalVoltage, ToIntFunction<Integer> busToSubstationNumber,
Function<Set<Integer>, String> busesToVoltageLevelId, Function<Set<Integer>, String> busesToSubstationId) {

Objects.requireNonNull(buses);
Objects.requireNonNull(branches);
Expand Down Expand Up @@ -96,15 +110,16 @@ public static <N, B> ContainersMapping create(List<N> buses, List<B> branches,
for (Set<Integer> busNums : new ConnectivityInspector<>(sGraph).connectedSets()) {

createAndMapSubstationAndVoltageLevelsInside(branchToNum1, branchToNum2, branchToIsZeroImpedance,
busToNominalVoltage, busesToVoltageLevelId, busesToSubstationId, busNums, sGraph, containersMapping);
busToNominalVoltage, busToSubstationNumber, busesToVoltageLevelId, busesToSubstationId, busNums, sGraph, containersMapping);
}

return containersMapping;
}

private static <B> void createAndMapSubstationAndVoltageLevelsInside(ToIntFunction<B> branchToNum1,
ToIntFunction<B> branchToNum2, Predicate<B> branchToIsZeroImpedance,
ToDoubleFunction<Integer> busToNominalVoltage, Function<Set<Integer>, String> busesToVoltageLevelId,
ToDoubleFunction<Integer> busToNominalVoltage, ToIntFunction<Integer> busToSubstationNumber,
Function<Set<Integer>, String> busesToVoltageLevelId,
Function<Set<Integer>, String> busesToSubstationId, Set<Integer> substationBusNums,
Graph<Integer, B> sGraph, ContainersMapping containersMapping) {

Expand All @@ -131,18 +146,21 @@ private static <B> void createAndMapSubstationAndVoltageLevelsInside(ToIntFuncti
Map<String, Set<Integer>> vls = new HashMap<>();

new ConnectivityInspector<>(vlGraph).connectedSets()
.forEach(voltageLevelIds -> vls.merge(getNominalVoltage(voltageLevelIds, busToNominalVoltage), voltageLevelIds, ContainersMapping::unionSet));
.forEach(voltageLevelIds -> vls.merge(getNominalVoltage(voltageLevelIds, busToNominalVoltage, busToSubstationNumber), voltageLevelIds, ContainersMapping::unionSet));

vls.values().forEach(voltageLevelIds -> mapSubstationAndVoltageLevel(busesToVoltageLevelId, substationId, voltageLevelIds, containersMapping));
}
}

private static String getNominalVoltage(Set<Integer> voltageLevelIds, ToDoubleFunction<Integer> busToVoltageLevelNominal) {
// We only consider in the same voltageLevel buses with the same nominal voltage and with the same substationData (only defined in PSSE)
private static String getNominalVoltage(Set<Integer> voltageLevelIds, ToDoubleFunction<Integer> busToVoltageLevelNominal, ToIntFunction<Integer> busToSubstationNumber) {
Objects.requireNonNull(busToVoltageLevelNominal);
if (voltageLevelIds.isEmpty()) { // should never happen
throw new PowsyblException("Unexpected empty connected set");
}
return String.valueOf(busToVoltageLevelNominal.applyAsDouble(voltageLevelIds.iterator().next()));
int bus = voltageLevelIds.iterator().next();
return busToSubstationNumber == null ? String.valueOf(busToVoltageLevelNominal.applyAsDouble(bus)) :
String.valueOf(busToVoltageLevelNominal.applyAsDouble(voltageLevelIds.iterator().next())) + "-" + busToSubstationNumber.applyAsInt(bus);
}

private static Set<Integer> unionSet(Set<Integer> set1, Set<Integer> set2) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,19 @@
*/
package com.powsybl.psse.converter;

import java.util.Objects;
import java.util.*;
import java.util.stream.Stream;

import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.SlackTerminal;
import com.powsybl.iidm.network.util.Identifiables;
import com.powsybl.iidm.network.util.Networks;
import com.powsybl.psse.model.PsseException;
import com.powsybl.psse.model.pf.PsseSubstation;
import com.powsybl.psse.model.pf.PsseTwoTerminalDcConverter;
import com.powsybl.psse.model.pf.PsseTwoTerminalDcTransmissionLine;
import org.apache.commons.math3.complex.Complex;

import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.util.ContainersMapping;

/**
Expand All @@ -20,6 +28,34 @@
*/
public abstract class AbstractConverter {

private static final String FIXED_SHUNT_TAG = "-SH";
private static final String SWITCHED_SHUNT_TAG = "-SwSH";

enum PsseEquipmentType {
PSSE_LOAD("L"),
PSSE_FIXED_SHUNT("F"),
PSSE_GENERATOR("M"),
PSSE_BRANCH("B"),
PSSE_TWO_WINDING("2"),
PSSE_THREE_WINDING("3"),
PSSE_SWITCHED_SHUNT("S"),
PSSE_INDUCTION_MACHINE("I"),
PSSE_TWO_TERMINAL_DC_LINE("D"),
PSSE_VSC_DC_LINE("V"),
PSSE_MULTI_TERMINAL_LINE("N"),
PSSE_FACTS_DEVICE("A");

private final String textCode;

PsseEquipmentType(String textCode) {
this.textCode = textCode;
}

String getTextCode() {
return textCode;
}
}

AbstractConverter(ContainersMapping containersMapping, Network network) {
this.containersMapping = Objects.requireNonNull(containersMapping);
this.network = Objects.requireNonNull(network);
Expand All @@ -33,10 +69,182 @@ Network getNetwork() {
return network;
}

static String getVoltageLevelId(Set<Integer> busNums) {
if (busNums.isEmpty()) {
throw new PsseException("Unexpected empty busNums");
}
List<Integer> sortedBusNums = busNums.stream().sorted().toList();
String voltageLevelId = "VL" + sortedBusNums.get(0);
for (int i = 1; i < sortedBusNums.size(); i++) {
voltageLevelId = voltageLevelId.concat(String.format("-%d", sortedBusNums.get(i)));
}
return voltageLevelId;
}

static List<Integer> extractBusesFromVoltageLevelId(String voltageLevelId) {
List<Integer> buses = new ArrayList<>();
if (voltageLevelId.length() <= 2 || !voltageLevelId.startsWith("VL")) {
return buses;
}
List<String> busesText = Arrays.stream(voltageLevelId.substring(2).split("-")).toList();
if (!busesText.stream().allMatch(busText -> busText.matches("[1-9]\\d*"))) {
return buses;
}
busesText.forEach(busText -> buses.add(Integer.parseInt(busText)));
return buses;
}

static String getBusId(int busNum) {
return "B" + busNum;
}

static OptionalInt extractBusNumber(String configuredBusId) {
if (configuredBusId.length() <= 1 || !configuredBusId.startsWith("B")) {
return OptionalInt.empty();
}
String busNumber = configuredBusId.substring(1);
return busNumber.matches("[1-9]\\d*") ? OptionalInt.of(Integer.parseInt(busNumber)) : OptionalInt.empty();
}

static String getFixedShuntId(int busI, String fixedShuntId) {
return getBusId(busI) + FIXED_SHUNT_TAG + fixedShuntId;
}

static String getGeneratorId(int busI, String generatorId) {
return getBusId(busI) + "-G" + generatorId;
}

static String getLineId(int busI, int busJ, String ckt) {
return "L-" + busI + "-" + busJ + "-" + ckt;
}

static String getLoadId(int busI, String loadId) {
return getBusId(busI) + "-L" + loadId;
}

static String getSwitchedShuntId(int busI, String id) {
return getBusId(busI) + SWITCHED_SHUNT_TAG + id;
}

static String getTransformerId(int busI, int busJ, String ckt) {
return "T-" + busI + "-" + busJ + "-" + ckt;
}

static String getTransformerId(int busI, int busJ, int busK, String ckt) {
return "T-" + busI + "-" + busJ + "-" + busK + "-" + ckt;
}

// we can not use rectifierIp and inverterIp as it is managed with only one end in substationData
// In Psse each two-terminal dc line must have a unique name (up to 12 characters)
static String getTwoTerminalDcId(String name) {
return "TwoTerminalDc-" + name;
}

static String getLccConverterId(Network network, PsseTwoTerminalDcTransmissionLine psseTwoTerminalDc, PsseTwoTerminalDcConverter converter) {
return Identifiables.getUniqueId("LccConverter-" + converter.getIp() + "-" + psseTwoTerminalDc.getName(), id -> network.getLccConverterStation(id) != null);
}

static String getSwitchId(String voltageLevelId, PsseSubstation.PsseSubstationSwitchingDevice switchingDevice) {
return voltageLevelId + "-Sw-" + switchingDevice.getNi() + "-" + switchingDevice.getNj() + "-" + switchingDevice.getCkt();
}

static String busbarSectionId(String voltageLevelId, int node) {
return String.format("%s-Busbar-%d", voltageLevelId, node);
}

static String getNodeId(VoltageLevel voltageLevel, int node) {
return voltageLevel.getId() + "-" + node;
}

static int getStatus(ShuntCompensator shuntCompensator) {
return shuntCompensator.getTerminal().isConnected() && shuntCompensator.getTerminal().getBusBreakerView().getBus() != null ? 1 : 0;
}

static String getNodeBreakerEquipmentIdBus(String equipmentId, int bus) {
return equipmentId + "." + bus;
}

// EquipmentId must be independent of the bus order
static String getNodeBreakerEquipmentId(String type, int busI, int busJ, int busK, String id) {
List<Integer> sortedBuses = Stream.of(busI, busJ, busK).sorted().toList();
int bus1 = sortedBuses.get(0);
int bus2 = sortedBuses.get(1);
int bus3 = sortedBuses.get(2);

// after sorting, zeros will be at the beginning
if (bus1 == 0 && bus2 == 0) {
return type + "." + bus3 + "." + id;
} else if (bus1 == 0) {
return type + "." + bus2 + "." + bus3 + "." + id;
} else {
return type + "." + bus1 + "." + bus2 + "." + bus3 + "." + id;
}
}

static String getNodeBreakerEquipmentId(PsseEquipmentType equipmentType, int busI, String id) {
return equipmentType.getTextCode() + "." + busI + "." + id;
}

static String getNodeBreakerEquipmentId(PsseEquipmentType equipmentType, int busI, int busJ, String id) {
List<Integer> sortedBuses = Stream.of(busI, busJ).sorted().toList();
int bus1 = sortedBuses.get(0);
int bus2 = sortedBuses.get(1);
return equipmentType.getTextCode() + "." + bus1 + "." + bus2 + "." + id;
}

static String getNodeBreakerEquipmentId(PsseEquipmentType equipmentType, int busI, int busJ, int busK, String id) {
List<Integer> sortedBuses = Stream.of(busI, busJ, busK).sorted().toList();
int bus1 = sortedBuses.get(0);
int bus2 = sortedBuses.get(1);
int bus3 = sortedBuses.get(2);
return equipmentType.getTextCode() + "." + bus1 + "." + bus2 + "." + bus3 + "." + id;
}

static Terminal findTerminalNode(Network network, String voltageLevelId, int node) {
VoltageLevel voltageLevel = network.getVoltageLevel(voltageLevelId);
return voltageLevel != null ? findTerminalNode(voltageLevel, node) : null;
}

static Terminal findTerminalNode(VoltageLevel voltageLevel, int node) {
return voltageLevel.getNodeBreakerView().getOptionalTerminal(node)
.orElseGet(() -> Networks.getEquivalentTerminal(voltageLevel, node));
}

static Bus findBusViewNode(VoltageLevel voltageLevel, int node) {
Terminal terminal = findTerminalNode(voltageLevel, node);
return terminal != null ? getTerminalBusView(terminal) : null;
}

static Bus getTerminalBusView(Terminal terminal) {
return terminal.getBusView().getBus() != null ? terminal.getBusView().getBus() : terminal.getBusView().getConnectableBus();
}

static int getStatus(Terminal terminal) {
return terminal.isConnected() && terminal.getBusView().getBus() != null ? 1 : 0;
}

static int findBusViewBusType(VoltageLevel voltageLevel, Bus bus) {
if (!bus.isInMainConnectedComponent()) {
return 4;
}
SlackTerminal slackTerminal = voltageLevel.getExtension(SlackTerminal.class);
if (slackTerminal != null
&& slackTerminal.getTerminal().getBusView().getBus() != null
&& bus.getId().equals(slackTerminal.getTerminal().getBusView().getBus().getId())) {
return 3;
}
return bus.getGeneratorStream().anyMatch(AbstractConverter::withLocalRegulatingControl) ? 2 : 1;
}

private static boolean withLocalRegulatingControl(Generator generator) {
return generator.isVoltageRegulatorOn()
&& generator.getTerminal().getBusView().getBus().equals(generator.getRegulatingTerminal().getBusView().getBus());
}

static boolean exportVoltageLevelAsNodeBreaker(VoltageLevel voltageLevel) {
return voltageLevel.getTopologyKind().equals(TopologyKind.NODE_BREAKER);
}

static Complex impedanceToEngineeringUnits(Complex impedance, double vnom, double sbase) {
return impedance.multiply(vnom * vnom / sbase);
}
Expand Down Expand Up @@ -73,6 +281,18 @@ static double shuntAdmittanceToPower(double shuntAdmittance, double vnom) {
return shuntAdmittance * vnom * vnom;
}

static double getVm(Bus bus) {
return bus != null && Double.isFinite(bus.getV()) && bus.getV() > 0.0 ? bus.getV() / bus.getVoltageLevel().getNominalV() : 1.0;
}

static double getVa(Bus bus) {
return bus != null && Double.isFinite(bus.getAngle()) ? bus.getAngle() : 0.0;
}

static double currentInAmpsToMw(double current, double nominalV) {
return current * nominalV / 1000.0;
}

private final ContainersMapping containersMapping;
private final Network network;
}
Loading
Loading