Skip to content

Commit

Permalink
Voltage level topology model conversion (#3199)
Browse files Browse the repository at this point in the history
Signed-off-by: Geoffroy Jamgotchian <[email protected]>
  • Loading branch information
geofjamg authored Dec 4, 2024
1 parent 218eb50 commit d66b8cc
Show file tree
Hide file tree
Showing 16 changed files with 427 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1355,6 +1355,15 @@ default void remove() {
*/
BusView getBusView();

/**
* Convert the topology model to another one. Notice that when converting from a
* node/breaker model to a bus/breaker model, we definitely lost some information as
* we are converting to a simpler topology model.
*
* @param newTopologyKind the new topology model kind
*/
void convertToTopology(TopologyKind newTopologyKind);

/**
* Print an ASCII representation of the topology on the standard ouput.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public void allocateVariantArrayElement(int[] indexes, int sourceIndex) {
}
}

protected void move(TerminalExt oldTerminal, TopologyPoint oldTopologyPoint, int node, String voltageLevelId) {
protected void move(TerminalExt oldTerminal, int node, String voltageLevelId) {
VoltageLevelExt voltageLevel = getNetwork().getVoltageLevel(voltageLevelId);
if (voltageLevel == null) {
throw new PowsyblException("Voltage level '" + voltageLevelId + "' not found");
Expand All @@ -152,10 +152,10 @@ protected void move(TerminalExt oldTerminal, TopologyPoint oldTopologyPoint, int
.build();

// detach the terminal from its previous voltage level
attachTerminal(oldTerminal, oldTopologyPoint, voltageLevel, terminalExt);
replaceTerminal(oldTerminal, voltageLevel.getTopologyModel(), terminalExt, true);
}

protected void move(TerminalExt oldTerminal, TopologyPoint oldTopologyPoint, String busId, boolean connected) {
protected void move(TerminalExt oldTerminal, String busId, boolean connected) {
Bus bus = getNetwork().getBusBreakerView().getBus(busId);
if (bus == null) {
throw new PowsyblException("Bus '" + busId + "' not found");
Expand All @@ -175,22 +175,43 @@ protected void move(TerminalExt oldTerminal, TopologyPoint oldTopologyPoint, Str
.build();

// detach the terminal from its previous voltage level
attachTerminal(oldTerminal, oldTopologyPoint, (VoltageLevelExt) bus.getVoltageLevel(), terminalExt);
replaceTerminal(oldTerminal, ((VoltageLevelExt) bus.getVoltageLevel()).getTopologyModel(), terminalExt, true);
}

private void attachTerminal(TerminalExt oldTerminal, TopologyPoint oldTopologyPoint, VoltageLevelExt voltageLevel, TerminalExt terminalExt) {
void replaceTerminal(TerminalExt oldTerminal, TopologyPoint oldTopologyPoint, TerminalExt newTerminalExt, boolean notify) {
Objects.requireNonNull(oldTerminal);
Objects.requireNonNull(newTerminalExt);
int iSide = terminals.indexOf(oldTerminal);
if (iSide == -1) {
throw new PowsyblException("Terminal to replace not found");
}
terminals.set(iSide, newTerminalExt);

if (notify) {
notifyUpdate("terminal" + (iSide + 1), oldTopologyPoint, newTerminalExt.getTopologyPoint());
}
}

void replaceTerminal(TerminalExt oldTerminal, TopologyModel newTopologyModel, TerminalExt newTerminalExt, boolean notify) {
Objects.requireNonNull(oldTerminal);
Objects.requireNonNull(newTopologyModel);
Objects.requireNonNull(newTerminalExt);

// first, attach new terminal to connectable and to voltage level of destination, to ensure that the new terminal is valid
terminalExt.setConnectable(this);
voltageLevel.getTopologyModel().attach(terminalExt, false);
newTerminalExt.setConnectable(this);
newTopologyModel.attach(newTerminalExt, false);

// then we can detach the old terminal, as we now know that the new terminal is valid
TopologyPoint oldTopologyPoint = oldTerminal.getTopologyPoint();
oldTerminal.getVoltageLevel().getTopologyModel().detach(oldTerminal);

// replace the old terminal by the new terminal in the connectable
int iSide = terminals.indexOf(oldTerminal);
terminals.set(iSide, terminalExt);
replaceTerminal(oldTerminal, oldTopologyPoint, newTerminalExt, notify);

notifyUpdate("terminal" + (iSide + 1), oldTopologyPoint, terminalExt.getTopologyPoint());
// also update terminal referrers
for (Referrer<Terminal> referrer : oldTerminal.getReferrerManager().getReferrers()) {
referrer.onReferencedReplacement(oldTerminal, newTerminalExt);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,9 @@ public void onReferencedRemoval(Terminal removedTerminal) {
// nothing by default
// this is the place for terminal reference cleanup
}

@Override
public void onReferencedReplacement(Terminal oldReferenced, Terminal newReferenced) {
// nothing by default
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@

public class AreaBoundaryImpl implements AreaBoundary {

final Area area;
private final Area area;

final Terminal terminal;
private Terminal terminal;

final Boundary boundary;
private final Boundary boundary;

final boolean ac;
private final boolean ac;

AreaBoundaryImpl(Area area, Terminal terminal, boolean ac) {
this.area = Objects.requireNonNull(area);
Expand Down Expand Up @@ -68,4 +68,12 @@ public double getP() {
public double getQ() {
return boundary != null ? boundary.getQ() : terminal.getQ();
}

void replaceTerminal(Terminal oldTerminal, Terminal newTerminal) {
Objects.requireNonNull(oldTerminal);
Objects.requireNonNull(newTerminal);
if (terminal == oldTerminal) {
terminal = newTerminal;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,31 @@ public class AreaImpl extends AbstractIdentifiable<Area> implements Area {

private final TDoubleArrayList interchangeTarget;

private final Referrer<Terminal> terminalReferrer = this::removeAreaBoundary;
private final Referrer<Terminal> terminalReferrer = new Referrer<>() {
@Override
public void onReferencedRemoval(Terminal terminal) {
removeAreaBoundary(terminal);
}

@Override
public void onReferencedReplacement(Terminal oldTerminal, Terminal newTerminal) {
for (AreaBoundary areaBoundary : areaBoundaries) {
((AreaBoundaryImpl) areaBoundary).replaceTerminal(oldTerminal, newTerminal);
}
}
};

private final Referrer<Boundary> boundaryReferrer = this::removeAreaBoundary;
private final Referrer<Boundary> boundaryReferrer = new Referrer<>() {
@Override
public void onReferencedRemoval(Boundary boundary) {
removeAreaBoundary(boundary);
}

@Override
public void onReferencedReplacement(Boundary oldBoundary, Boundary newBoundary) {
// cannot happen
}
};

AreaImpl(Ref<NetworkImpl> ref, Ref<SubnetworkImpl> subnetworkRef, String id, String name, boolean fictitious, String areaType,
double interchangeTarget) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ public Switch add() {
}

SwitchImpl aSwitch = new SwitchImpl(voltageLevel, id, getName(), isFictitious(), SwitchKind.BREAKER, open, true);
addSwitch(aSwitch, busId1, busId2);
getNetwork().getIndex().checkAndAdd(aSwitch);
addSwitchToTopology(aSwitch, busId1, busId2);
getNetwork().getListeners().notifyCreation(aSwitch);
return aSwitch;
}
Expand Down Expand Up @@ -797,10 +798,9 @@ private void removeAllBuses() {
removedBusesIds.forEach(id -> network.getListeners().notifyAfterRemoval(id));
}

private void addSwitch(SwitchImpl aSwitch, String busId1, String busId2) {
void addSwitchToTopology(SwitchImpl aSwitch, String busId1, String busId2) {
int v1 = getVertex(busId1, true);
int v2 = getVertex(busId2, true);
getNetwork().getIndex().checkAndAdd(aSwitch);
int e = graph.addEdge(v1, v2, aSwitch);
switches.put(aSwitch.getId(), e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public void moveConnectable(int node, String voltageLevelId) {
if (removed) {
throw new PowsyblException(UNMODIFIABLE_REMOVED_EQUIPMENT + connectable.id);
}
getConnectable().move(BusTerminal.this, getTopologyPoint(), node, voltageLevelId);
getConnectable().move(BusTerminal.this, node, voltageLevelId);
}
};

Expand Down Expand Up @@ -87,7 +87,7 @@ public void moveConnectable(String busId, boolean connected) {
if (removed) {
throw new PowsyblException(UNMODIFIABLE_REMOVED_EQUIPMENT + connectable.id);
}
getConnectable().move(BusTerminal.this, getTopologyPoint(), busId, connected);
getConnectable().move(BusTerminal.this, busId, connected);
}

};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,16 @@ CalculatedBusTopology getCalculatedBusTopology() {
return variants.get().calculatedBusTopology;
}

void removeSwitchFromTopology(String switchId, boolean notify) {
Integer e = switches.get(switchId);
if (e == null) {
throw new PowsyblException("Switch '" + switchId
+ "' not found in voltage level '" + voltageLevel.getId() + "'");
}
graph.removeEdge(e, notify);
graph.removeIsolatedVertices(notify);
}

private final VoltageLevelExt.NodeBreakerViewExt nodeBreakerView = new VoltageLevelExt.NodeBreakerViewExt() {

private final TIntObjectMap<TDoubleArrayList> fictitiousP0ByNode = TCollections.synchronizedMap(new TIntObjectHashMap<>());
Expand Down Expand Up @@ -873,13 +883,7 @@ public int getSwitchCount() {

@Override
public void removeSwitch(String switchId) {
Integer e = switches.get(switchId);
if (e == null) {
throw new PowsyblException("Switch '" + switchId
+ "' not found in voltage level '" + voltageLevel.getId() + "'");
}
graph.removeEdge(e);
graph.removeIsolatedVertices();
NodeBreakerTopologyModel.this.removeSwitchFromTopology(switchId, true);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public void moveConnectable(int node, String voltageLevelId) {
if (removed) {
throw new PowsyblException(UNMODIFIABLE_REMOVED_EQUIPMENT + connectable.id);
}
getConnectable().move(NodeTerminal.this, getTopologyPoint(), node, voltageLevelId);
getConnectable().move(NodeTerminal.this, node, voltageLevelId);
}
};

Expand Down Expand Up @@ -89,7 +89,7 @@ public void moveConnectable(String busId, boolean connected) {
if (removed) {
throw new PowsyblException(UNMODIFIABLE_REMOVED_EQUIPMENT + connectable.id);
}
getConnectable().move(NodeTerminal.this, getTopologyPoint(), busId, connected);
getConnectable().move(NodeTerminal.this, busId, connected);
}

};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,14 @@ public interface Referrer<T> {
* @param removedReferenced The referenced that has been removed from the network.
*/
void onReferencedRemoval(T removedReferenced);

/**
* Called when a referenced object is replaced with another one. Implementations of this method
* should handle any required updates or transfers necessary when the referenced object is
* replaced.
*
* @param oldReferenced The original referenced object that is being replaced.
* @param newReferenced The new referenced object that is taking the place of the old one.
*/
void onReferencedReplacement(T oldReferenced, T newReferenced);
}
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,11 @@ public void onReferencedRemoval(Terminal removedTerminal) {
regulationMode.fill(0, regulationMode.size(), StaticVarCompensator.RegulationMode.OFF.ordinal());
}
}

@Override
public void onReferencedReplacement(Terminal oldReferenced, Terminal newReferenced) {
if (regulatingTerminal == oldReferenced) {
regulatingTerminal = (TerminalExt) newReferenced;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.*;
import com.powsybl.commons.ref.Ref;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.util.ShortIdDictionary;

import java.io.IOException;
Expand Down Expand Up @@ -39,7 +39,7 @@ class VoltageLevelImpl extends AbstractIdentifiable<VoltageLevel> implements Vol

private double highVoltageLimit;

private final AbstractTopologyModel topologyModel;
private AbstractTopologyModel topologyModel;

/** Areas associated to this VoltageLevel, with at most one area for each area type */
private final Set<Area> areas = new LinkedHashSet<>();
Expand Down Expand Up @@ -618,4 +618,83 @@ public void allocateVariantArrayElement(int[] indexes, int sourceIndex) {
super.allocateVariantArrayElement(indexes, sourceIndex);
topologyModel.allocateVariantArrayElement(indexes, sourceIndex);
}

private void convertToBusBreakerModel() {
BusBreakerTopologyModel newTopologyModel = new BusBreakerTopologyModel(this);

// remove busbar sections because not needed in a bus/breaker topology
for (BusbarSection bbs : topologyModel.getNodeBreakerView().getBusbarSections()) {
bbs.remove();
}

for (Bus bus : topologyModel.getBusBreakerView().getBuses()) {
// no notification, this is just a mutation of a calculation bus to a configured bus
ConfiguredBusImpl configuredBus = new ConfiguredBusImpl(bus.getId(), bus.getOptionalName().orElse(null), bus.isFictitious(), this);
newTopologyModel.addBus(configuredBus);
}

// transfer retained switches
for (Switch sw : topologyModel.getBusBreakerView().getSwitchStream().toList()) {
String busId1 = topologyModel.getBusBreakerView().getBus1(sw.getId()).getId();
String busId2 = topologyModel.getBusBreakerView().getBus2(sw.getId()).getId();
// no notification, this is just a transfer
((NodeBreakerTopologyModel) topologyModel).removeSwitchFromTopology(sw.getId(), false);
newTopologyModel.addSwitchToTopology((SwitchImpl) sw, busId1, busId2);
}

// reconnect all connectable to new topology model
// first store all bus/breaker topological infos associated to this terminal because we will start moving
// terminal from old mode to new one, it will modify the old topology model
record TopologyModelInfos(TerminalExt terminal, String connectableBusId, boolean connected) {
}
List<TopologyModelInfos> oldTopologyModelInfos = new ArrayList<>();
for (Terminal oldTerminal : topologyModel.getTerminals()) {
Bus connectableBus = oldTerminal.getBusBreakerView().getConnectableBus();
String connectableBusId = connectableBus == null ? null : connectableBus.getId();
boolean connected = oldTerminal.isConnected();
oldTopologyModelInfos.add(new TopologyModelInfos((TerminalExt) oldTerminal, connectableBusId, connected));
}

for (var infos : oldTopologyModelInfos) {
TerminalExt oldTerminalExt = infos.terminal();

// if there is no way to find a connectable bus, remove the connectable
// an alternative would be to connect them all to a new trash configured bus
if (infos.connectableBusId() == null) {
// here keep the removal notification
oldTerminalExt.getConnectable().remove();
continue;
}

AbstractConnectable<?> connectable = oldTerminalExt.getConnectable();

// create the new terminal with new type
TerminalExt newTerminalExt = new TerminalBuilder(networkRef, this, oldTerminalExt.getSide())
.setBus(infos.connected ? infos.connectableBusId() : null)
.setConnectableBus(infos.connectableBusId())
.build();

connectable.replaceTerminal(oldTerminalExt, newTopologyModel, newTerminalExt, false);
}

// also here keep the notification for remaining switches removal
topologyModel.removeTopology();

TopologyKind oldTopologyKind = topologyModel.getTopologyKind();
topologyModel = newTopologyModel;

notifyUpdate("topologyKind", oldTopologyKind, TopologyKind.BUS_BREAKER);
}

@Override
public void convertToTopology(TopologyKind newTopologyKind) {
Objects.requireNonNull(newTopologyKind);
if (newTopologyKind != topologyModel.getTopologyKind()) {
if (newTopologyKind == TopologyKind.NODE_BREAKER) {
throw new PowsyblException("Topology model conversion from bus/breaker to node/breaker not yet supported");
} else if (newTopologyKind == TopologyKind.BUS_BREAKER) {
convertToBusBreakerModel();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@ public void onReferencedRemoval(Terminal removedTerminal) {
getExtendable().removeExtension(RemoteReactivePowerControl.class);
}

@Override
public void onReferencedReplacement(Terminal oldReferenced, Terminal newReferenced) {
if (regulatingTerminal == oldReferenced) {
regulatingTerminal = newReferenced;
}
}

@Override
public void cleanup() {
if (regulatingTerminal != null) {
Expand Down
Loading

0 comments on commit d66b8cc

Please sign in to comment.