AbstractConnectable.java
/**
* Copyright (c) 2016, All partners of the iTesla project (http://www.itesla-project.eu/consortium)
* 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/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.iidm.network.impl;
import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.ref.Ref;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.util.SwitchPredicates;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.function.Supplier;
import static com.powsybl.iidm.network.TopologyKind.NODE_BREAKER;
/**
*
* @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
*/
abstract class AbstractConnectable<I extends Connectable<I>> extends AbstractIdentifiable<I> implements Connectable<I>, MultiVariantObject {
protected final List<TerminalExt> terminals = new ArrayList<>();
private final Ref<NetworkImpl> networkRef;
protected boolean removed = false;
AbstractConnectable(Ref<NetworkImpl> ref, String id, String name, boolean fictitious) {
super(id, name, fictitious);
this.networkRef = Objects.requireNonNull(ref);
}
void addTerminal(TerminalExt terminal) {
terminals.add(terminal);
terminal.setConnectable(this);
}
public List<TerminalExt> getTerminals() {
return terminals;
}
@Override
public NetworkExt getParentNetwork() {
// the parent network is the network that contains all terminals of the connectable.
List<NetworkExt> subnetworks = terminals.stream().map(t -> t.getVoltageLevel().getParentNetwork()).distinct().toList();
if (subnetworks.size() == 1) {
return subnetworks.get(0);
}
return getNetwork();
}
@Override
public NetworkImpl getNetwork() {
if (removed) {
throw new PowsyblException("Cannot access network of removed equipment " + id);
}
return networkRef.get();
}
@Override
public void remove() {
NetworkImpl network = getNetwork();
network.getListeners().notifyBeforeRemoval(this);
network.getIndex().remove(this);
for (TerminalExt terminal : terminals) {
terminal.getReferrerManager().notifyOfRemoval();
VoltageLevelExt vl = terminal.getVoltageLevel();
vl.getTopologyModel().detach(terminal);
}
network.getListeners().notifyAfterRemoval(id);
removed = true;
terminals.forEach(TerminalExt::remove);
}
protected void notifyUpdate(Supplier<String> attribute, Object oldValue, Object newValue) {
getNetwork().getListeners().notifyUpdate(this, attribute, oldValue, newValue);
}
protected void notifyUpdate(String attribute, Object oldValue, Object newValue) {
getNetwork().getListeners().notifyUpdate(this, attribute, oldValue, newValue);
}
protected void notifyUpdate(Supplier<String> attribute, String variantId, Object oldValue, Object newValue) {
getNetwork().getListeners().notifyUpdate(this, attribute, variantId, oldValue, newValue);
}
protected void notifyUpdate(String attribute, String variantId, Object oldValue, Object newValue) {
getNetwork().getListeners().notifyUpdate(this, attribute, variantId, oldValue, newValue);
}
@Override
public void extendVariantArraySize(int initVariantArraySize, int number, int sourceIndex) {
super.extendVariantArraySize(initVariantArraySize, number, sourceIndex);
for (TerminalExt t : terminals) {
t.extendVariantArraySize(initVariantArraySize, number, sourceIndex);
}
}
@Override
public void reduceVariantArraySize(int number) {
super.reduceVariantArraySize(number);
for (TerminalExt t : terminals) {
t.reduceVariantArraySize(number);
}
}
@Override
public void deleteVariantArrayElement(int index) {
super.deleteVariantArrayElement(index);
for (TerminalExt t : terminals) {
t.deleteVariantArrayElement(index);
}
}
@Override
public void allocateVariantArrayElement(int[] indexes, int sourceIndex) {
super.allocateVariantArrayElement(indexes, sourceIndex);
for (TerminalExt t : terminals) {
t.allocateVariantArrayElement(indexes, sourceIndex);
}
}
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");
}
// check bus topology
if (voltageLevel.getTopologyKind() != NODE_BREAKER) {
String msg = String.format(
"Trying to move connectable %s to node %d of voltage level %s, which is a bus breaker voltage level",
getId(), node, voltageLevel.getId());
throw new PowsyblException(msg);
}
// create the new terminal and attach it to the given voltage level and to the connectable
TerminalExt terminalExt = new TerminalBuilder(voltageLevel.getNetworkRef(), this, oldTerminal.getSide())
.setNode(node)
.build();
// detach the terminal from its previous voltage level
replaceTerminal(oldTerminal, voltageLevel.getTopologyModel(), terminalExt, true);
}
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");
}
// check bus topology
if (bus.getVoltageLevel().getTopologyKind() != TopologyKind.BUS_BREAKER) {
throw new PowsyblException(String.format(
"Trying to move connectable %s to bus %s of voltage level %s, which is a node breaker voltage level",
getId(), bus.getId(), bus.getVoltageLevel().getId()));
}
// create the new terminal and attach it to the voltage level of the given bus and links it to the connectable
TerminalExt terminalExt = new TerminalBuilder(((VoltageLevelExt) bus.getVoltageLevel()).getNetworkRef(), this, oldTerminal.getSide())
.setBus(connected ? bus.getId() : null)
.setConnectableBus(bus.getId())
.build();
// detach the terminal from its previous voltage level
replaceTerminal(oldTerminal, ((VoltageLevelExt) bus.getVoltageLevel()).getTopologyModel(), terminalExt, true);
}
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
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
replaceTerminal(oldTerminal, oldTopologyPoint, newTerminalExt, notify);
// also update terminal referrers
for (Referrer<Terminal> referrer : oldTerminal.getReferrerManager().getReferrers()) {
referrer.onReferencedReplacement(oldTerminal, newTerminalExt);
}
}
@Override
public boolean connect() {
return connect(SwitchPredicates.IS_NONFICTIONAL_BREAKER);
}
@Override
public boolean connect(Predicate<Switch> isTypeSwitchToOperate) {
return connect(isTypeSwitchToOperate, null);
}
@Override
public boolean connect(Predicate<Switch> isTypeSwitchToOperate, ThreeSides side) {
return ConnectDisconnectUtil.connectAllTerminals(
this,
getTerminals(side),
isTypeSwitchToOperate,
getNetwork().getReportNodeContext().getReportNode());
}
@Override
public boolean disconnect() {
return disconnect(SwitchPredicates.IS_CLOSED_BREAKER);
}
@Override
public boolean disconnect(Predicate<Switch> isSwitchOpenable) {
return disconnect(isSwitchOpenable, null);
}
@Override
public boolean disconnect(Predicate<Switch> isSwitchOpenable, ThreeSides side) {
return ConnectDisconnectUtil.disconnectAllTerminals(
this,
getTerminals(side),
isSwitchOpenable,
getNetwork().getReportNodeContext().getReportNode());
}
public List<TerminalExt> getTerminals(ThreeSides side) {
if (side == null) {
return terminals;
} else {
return terminals.stream().filter(terminal -> terminal.getSide().equals(side)).toList();
}
}
}