ReferenceTerminalsImpl.java
/**
* Copyright (c) 2023, Coreso SA (https://www.coreso.eu/) and TSCNET Services GmbH (https://www.tscnet.eu/)
* 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.extensions;
import com.google.common.collect.ImmutableSet;
import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.Terminal;
import com.powsybl.iidm.network.extensions.ReferenceTerminals;
import com.powsybl.iidm.network.impl.AbstractMultiVariantIdentifiableExtension;
import com.powsybl.iidm.network.impl.TerminalExt;
import java.util.*;
/**
* @author Damien Jeandemange {@literal <damien.jeandemange at artelys.com>}
*/
class ReferenceTerminalsImpl extends AbstractMultiVariantIdentifiableExtension<Network> implements ReferenceTerminals {
private final ArrayList<Set<Terminal>> terminalsPerVariant;
public ReferenceTerminalsImpl(Network network, Set<Terminal> terminals) {
super(network);
this.terminalsPerVariant = new ArrayList<>(
Collections.nCopies(getVariantManagerHolder().getVariantManager().getVariantArraySize(), new LinkedHashSet<>()));
setReferenceTerminals(terminals);
}
private void unregisterReferencedTerminalIfNeeded(int variantIndex) {
// check there is no more same terminal referenced by any variant, unregister it
Set<Terminal> oldTerminals = terminalsPerVariant.get(variantIndex);
for (Terminal oldTerminal : oldTerminals) {
if (terminalsPerVariant.stream()
.flatMap(Collection::stream)
.filter(t -> t == oldTerminal)
.count() == 1) {
((TerminalExt) oldTerminal).getReferrerManager().unregister(this);
}
}
}
private void registerReferencedTerminalIfNeeded(Set<Terminal> terminals) {
// if terminal was not already referenced by another variant, register it
for (Terminal terminal : terminals) {
if (terminalsPerVariant.stream()
.flatMap(Collection::stream)
.noneMatch(t -> t == terminal)) {
((TerminalExt) terminal).getReferrerManager().register(this);
}
}
}
private void setTerminalsAndUpdateReferences(int variantIndex, Set<Terminal> terminals) {
unregisterReferencedTerminalIfNeeded(variantIndex);
registerReferencedTerminalIfNeeded(terminals);
terminalsPerVariant.set(variantIndex, new LinkedHashSet<>(terminals));
}
private void addTerminalsAndUpdateReferences(Set<Terminal> terminals) {
registerReferencedTerminalIfNeeded(terminals);
terminalsPerVariant.add(new LinkedHashSet<>(terminals));
}
private void updateTerminalsAndUpdateReferences(int variantIndex, Terminal terminal) {
registerReferencedTerminalIfNeeded(Set.of(terminal));
terminalsPerVariant.get(variantIndex).add(terminal);
}
private void removeTerminalsAndUpdateReferences(int variantIndex) {
unregisterReferencedTerminalIfNeeded(variantIndex);
terminalsPerVariant.remove(variantIndex); // remove elements from the top to avoid moves inside the array
}
@Override
public Set<Terminal> getReferenceTerminals() {
return ImmutableSet.copyOf(terminalsPerVariant.get(getVariantIndex()));
}
@Override
public void setReferenceTerminals(Set<Terminal> terminals) {
Objects.requireNonNull(terminals);
terminals.forEach(t -> checkTerminalInNetwork(t, getExtendable()));
setTerminalsAndUpdateReferences(getVariantIndex(), terminals);
}
@Override
public ReferenceTerminals reset() {
setTerminalsAndUpdateReferences(getVariantIndex(), Collections.emptySet());
return this;
}
@Override
public ReferenceTerminals addReferenceTerminal(Terminal terminal) {
Objects.requireNonNull(terminal);
checkTerminalInNetwork(terminal, getExtendable());
updateTerminalsAndUpdateReferences(getVariantIndex(), terminal);
return this;
}
@Override
public void extendVariantArraySize(int initVariantArraySize, int number, int sourceIndex) {
terminalsPerVariant.ensureCapacity(terminalsPerVariant.size() + number);
Set<Terminal> sourceTerminals = terminalsPerVariant.get(sourceIndex);
for (int i = 0; i < number; ++i) {
addTerminalsAndUpdateReferences(sourceTerminals);
}
}
@Override
public void reduceVariantArraySize(int number) {
for (int i = 0; i < number; i++) {
removeTerminalsAndUpdateReferences(terminalsPerVariant.size() - 1); // remove elements from the top to avoid moves inside the array
}
}
@Override
public void deleteVariantArrayElement(int index) {
setTerminalsAndUpdateReferences(index, Collections.emptySet());
}
@Override
public void allocateVariantArrayElement(int[] indexes, int sourceIndex) {
Set<Terminal> sourceTerminals = terminalsPerVariant.get(sourceIndex);
for (int index : indexes) {
setTerminalsAndUpdateReferences(index, sourceTerminals);
}
}
private static void checkTerminalInNetwork(Terminal terminal, Network network) {
final boolean extendableIsRootNetwork = network.getNetwork().equals(network);
if (extendableIsRootNetwork) {
// it is all fine as long as the terminal belongs to the merged network
if (!terminal.getVoltageLevel().getNetwork().equals(network)) {
throw new PowsyblException("Terminal given is not in the right Network ("
+ terminal.getVoltageLevel().getNetwork().getId() + " instead of " + network.getId() + ")");
}
} else {
// subnetwork: the terminal must be in the subnetwork
if (!terminal.getVoltageLevel().getParentNetwork().equals(network)) {
throw new PowsyblException("Terminal given is not in the right Network ("
+ terminal.getVoltageLevel().getParentNetwork().getId() + " instead of " + network.getId() + ")");
}
}
}
@Override
public void onReferencedRemoval(Terminal removedTerminal) {
for (Set<Terminal> terminals : terminalsPerVariant) {
terminals.remove(removedTerminal);
}
}
@Override
public void cleanup() {
for (Set<Terminal> terminals : terminalsPerVariant) {
for (Terminal terminal : terminals) {
((TerminalExt) terminal).getReferrerManager().unregister(this);
}
terminals.clear();
}
}
}