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

Complete the nodebreaker/busbreaker/bus views/topology APIs #3107

Open
jonenst opened this issue Jul 23, 2024 · 7 comments
Open

Complete the nodebreaker/busbreaker/bus views/topology APIs #3107

jonenst opened this issue Jul 23, 2024 · 7 comments

Comments

@jonenst
Copy link
Contributor

jonenst commented Jul 23, 2024

Describe the current behavior

powysbl has many methods to associate objects between the different views depending on the different topology.
For example, voltageLevel.getBusView().getMergedBus( string id ) gives the bus from the busview from either an id of busbarsection (nodebreaker topology) or from the id of a configured bus (busbreaker topology)

Similarly, vl.getBusBreakerView().getBusesFromBusViewBusId() gives buses of the busbreakerview for a bus of the busview

Networks.getNodes gives the nodes for a bus of the busview (kind of like getConnectedTerminals ..?)

Unless I'm mistaken, the system is not complete, you can't get from busbreakerbuses to their busviewbuses
Another case, when a busbreakerbus doesn't have a busbar section, because a switch is open between the equipment and its busbar sections, you can't easily find the busbar section (that would be connected to after a call to connect() ). Something like getConnectableBusbarSection() is missing ? It would need the same predicate as connect()

Describe the expected behavior

Maybe add documentation on the modeling differences and commonalities between nodebreaker/busbreaker topology. Explain more how you can go from one view to another, etc. This should put some light on what is currently missing.

Describe the motivation

Have a homogeneous and simple and complete system

Extra Information

No response

@jonenst
Copy link
Contributor Author

jonenst commented Jul 24, 2024

we should improve the drawing of https://javadoc.io/static/com.powsybl/powsybl-core/6.4.1/com/powsybl/iidm/network/doc-files/nodeBreakerTopologyGraph.svg to have the pink edge more closely associated with the coupler, it's far to the right and not obvious that this is what the pink edge represent (it's hard to draw something nice though, I guess that's why the pink edge was drawn directly between the nodes)

@jonenst
Copy link
Contributor Author

jonenst commented Jul 24, 2024

We should add more voltage level examples to https://javadoc.io/doc/com.powsybl/powsybl-core/latest/com/powsybl/iidm/network/VoltageLevel.html (keep the existing simple and standard one, but add more to show what is possible)

  • a case with some busbars that are aggregated to buses in the busbreakerview, some that are not (to insist on the effect of retained vs non retained switch)
  • an equipment with an open switch to a busbar which creates its own bus in the busbreakerview
  • things that are not kept in the bus view (busbar with no equipments, equipments not connected to any busbar)

@jonenst
Copy link
Contributor Author

jonenst commented Jul 24, 2024

We should highlight the differences/possibilities between a busbreakerview of a nodebreakertopology voltagelevel and an equivalent voltagelevel described directly in busbreaker topology. For example, when an equipment has an open switch to a busbar, in the busbreakerview it gets its own bus. To model this in busbreaker topology, you need to create this configured bus, but this is contrary to the docs that say

bus/breaker model: this is an aggregated form of the topology made of buses and breakers. A bus is the aggregation of busbar sections and closed switches.

here the bus does not aggregate busbars. So we need to explain more the differences between a computed busbreakerview and a modeled busbreakertopology, are you always supposed to be able to create equivalent ones or are there cases where it's not possible ?

Another example, in the busbreaker topology, an equipement is connectable only to one bus, whereas in the nodebreakertopology you can connect to any number of busbar. So you need to create more configured bus in the busbreakertopology to model this, but is it what you are supposed to do ?

@jonenst
Copy link
Contributor Author

jonenst commented Jul 24, 2024

We should mention that in the busbreakertopology, the busbars from the nodebreakerview are still visible as equipments, it's a bit counterintutive (or maybe a feature ?)

@jonenst
Copy link
Contributor Author

jonenst commented Jul 24, 2024

sample code to improve:

      System.out.println();
        System.out.println(s1vl1.getTopologyKind());

        if (s1vl1.getTopologyKind() == TopologyKind.NODE_BREAKER) {
            System.out.println("busbars: " + s1vl1.getNodeBreakerView().getBusbarSectionStream().toList());
        }
        System.out.println("busbreakerviewbuses: " + s1vl1.getBusBreakerView().getBusStream().toList());
        System.out.println("busviewbuses: " + s1vl1.getBusView().getBusStream().toList());

        System.out.println("busviewbus -> busbreakerviewbus:" + s1vl1.getBusView().getBusStream().map(Bus::getId)
                .collect(Collectors.toMap(Function.identity(), s1vl1.getBusBreakerView()::getBusesFromBusViewBusId)));

        if (s1vl1.getTopologyKind() == TopologyKind.NODE_BREAKER) {
            System.out.println("busviewbus -> busbars:" + s1vl1.getBusView().getBusStream().map(Bus::getId)
                    .collect(Collectors.toMap(Function.identity(),
                    // can it be simpler than getNodes and then filter for busbar?
                            busid -> Networks.getNodes(busid, s1vl1, t -> t.getBusView().getBus())
                                    .mapToObj(node -> s1vl1.getNodeBreakerView().getTerminal(node))
                                    .map(Terminal::getConnectable)
                                    .filter(x -> x.getType() == IdentifiableType.BUSBAR_SECTION).toList())));

            System.out.println("busviewbus -> busbars:" + s1vl1.getBusView().getBusStream()
                    .collect(Collectors.toMap(Bus::getId,
                    // what's the difference with getNodes ?
                            bus -> bus.getConnectedTerminalStream()
                            .map(Terminal::getConnectable)
                            .filter(x -> x.getType() == IdentifiableType.BUSBAR_SECTION).toList())));

            
            System.out
                    .println("busbreakerviewbus -> busbars:" + s1vl1.getBusBreakerView().getBusStream().map(Bus::getId)
                            .collect(Collectors.toMap(Function.identity(),
                                    busid -> Networks.getNodes(busid, s1vl1, t -> t.getBusBreakerView().getBus())
                                            .mapToObj(node -> s1vl1.getNodeBreakerView().getTerminal(node))
                                            .map(Terminal::getConnectable)
                                            .filter(x -> x.getType() == IdentifiableType.BUSBAR_SECTION).toList())));

            System.out.println("busbars -> bus: " + s1vl1.getNodeBreakerView().getBusbarSectionStream()
                    .map(BusbarSection::getId).collect(Collectors.toMap(Function.identity(),
                            busid -> Optional.ofNullable(s1vl1.getBusView().getMergedBus(busid)))));

            System.out.println("busbreakerbus -> bus: not possible");
            System.out.println("busbreakerbus -> busbar: not possible for "disconnected equipment buses");
            System.out.println("bus -> connectable: "
                    + s1vl1.getBusBreakerView().getBusStream().collect(Collectors.toMap(Bus::getId,
                            bus -> bus.getConnectedTerminalStream().map(Terminal::getConnectable).toList())));

        }

        if (s1vl1.getTopologyKind() == TopologyKind.BUS_BREAKER) {
            System.out.println("busbreakerbus -> bus: " + s1vl1.getBusBreakerView().getBusStream().map(Bus::getId)
                    .collect(Collectors.toMap(Function.identity(),
                            busid -> Optional.ofNullable(s1vl1.getBusView().getMergedBus(busid)))));

            System.out.println("bus -> connectable: " + s1vl1.getBusView().getBusStream()
                    .collect(Collectors.toMap(Bus::getId,
                            bus -> bus.getConnectedTerminalStream().map(Terminal::getConnectable).toList())));
        }
NODE_BREAKER
busbars: [S1BBS1, S1BBS2, S1BBS3, S1BBS4, S1BBS5]
busbreakerviewbuses: [S1VL1_0, S1VL1_1, S1VL1_3, S1VL1_9, S1VL1_5]
busviewbuses: [S1VL1_0, S1VL1_3]
busviewbus -> busbreakerviewbus:{S1VL1_3=[S1VL1_3], S1VL1_0=[S1VL1_1, S1VL1_0]}
busviewbus -> busbars:{S1VL1_3=[S1BBS4], S1VL1_0=[S1BBS1, S1BBS2, S1BBS3]}
busviewbus -> busbars:{S1VL1_3=[S1BBS4], S1VL1_0=[S1BBS1, S1BBS2, S1BBS3]}
# notice empty list for S1VL1_5 the dangling load 
busbreakerviewbus -> busbars:{S1VL1_3=[S1BBS4], S1VL1_5=[], S1VL1_9=[S1BBS5], S1VL1_1=[S1BBS2], S1VL1_0=[S1BBS1, S1BBS3]}
# notice dangling busbar S1BBS5 removed from busview
busbars -> bus: {S1BBS5=Optional.empty, S1BBS4=Optional[S1VL1_3], S1BBS3=Optional[S1VL1_0], S1BBS2=Optional[S1VL1_0], S1BBS1=Optional[S1VL1_0]}
busbreakerbus -> bus: not possible
busbreakerbus -> busbar: not possible for 'disconnected equipment buses'
bus -> connectable: {S1VL1_3=[S1BBS4, load5], S1VL1_5=[load2], S1VL1_9=[S1BBS5], S1VL1_1=[S1BBS2, load3], S1VL1_0=[S1BBS1, S1BBS3, load4, load1]}

BUS_BREAKER
busbreakerviewbuses: [bus1]
busviewbuses: [S1VL2_0]
busviewbus -> busbreakerviewbus:{S1VL2_0=[bus1]}
busbreakerbus -> bus: {bus1=Optional[S1VL2_0]}
bus -> connectable: {S1VL2_0=[load12]}
S1VL1_0
``

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant