AbstractNetworkReducer.java
/**
* Copyright (c) 2018, RTE (http://www.rte-france.com)
* 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.reducer;
import com.powsybl.iidm.network.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Mathieu Bague {@literal <mathieu.bague at rte-france.com>}
*/
public abstract class AbstractNetworkReducer implements NetworkReducer {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractNetworkReducer.class);
private final NetworkPredicate predicate;
private final Set<String> vlIds = new HashSet<>();
protected AbstractNetworkReducer(NetworkPredicate predicate) {
this.predicate = Objects.requireNonNull(predicate);
}
public final void reduce(Network network) {
buildVoltageLevelIdSet(network);
// Remove all unwanted lines
List<Line> lines = network.getLineStream()
.filter(l -> !test(l))
.toList();
lines.forEach(this::reduce);
// Remove all unwanted tie lines
List<TieLine> tieLines = network.getTieLineStream()
.filter(l -> !test(l))
.toList();
tieLines.forEach(this::reduce);
// Remove all unwanted two windings transformers
List<TwoWindingsTransformer> twoWindingsTransformers = network.getTwoWindingsTransformerStream()
.filter(t -> !test(t))
.toList();
twoWindingsTransformers.forEach(this::reduce);
// Remove all three windings transformers
List<ThreeWindingsTransformer> threeWindingsTransformers = network.getThreeWindingsTransformerStream()
.filter(t -> !test(t))
.toList();
threeWindingsTransformers.forEach(this::reduce);
// Remove all unwanted HVDC lines
List<HvdcLine> hvdcLines = network.getHvdcLineStream()
.filter(h -> !test(h))
.toList();
hvdcLines.forEach(this::reduce);
// Remove all unwanted voltage levels
List<VoltageLevel> voltageLevels = network.getVoltageLevelStream()
.filter(vl -> !test(vl))
.toList();
voltageLevels.forEach(this::reduce);
// Remove all unwanted substations
List<Substation> substations = network.getSubstationStream()
.filter(s -> !test(s))
.toList();
substations.forEach(this::reduce);
}
protected final NetworkPredicate getPredicate() {
return predicate;
}
protected abstract void reduce(Substation substation);
protected abstract void reduce(VoltageLevel voltageLevel);
protected abstract void reduce(Line line);
protected abstract void reduce(TieLine tieLine);
protected abstract void reduce(TwoWindingsTransformer transformer);
protected abstract void reduce(ThreeWindingsTransformer transformer);
protected abstract void reduce(HvdcLine hvdcLine);
protected boolean test(Substation substation) {
return predicate.test(substation);
}
protected boolean test(VoltageLevel voltageLevel) {
Objects.requireNonNull(voltageLevel);
return vlIds.contains(voltageLevel.getId());
}
/**
* Return true if the given {@link Line} should be kept in the network, false otherwise
*/
protected boolean test(Line line) {
return test((Branch<?>) line);
}
/**
* Return true if the given {@link TieLine} should be kept in the network, false otherwise
*/
protected boolean test(TieLine tieLine) {
return test((Branch<?>) tieLine);
}
/**
* Return true if the given {@link TwoWindingsTransformer} should be kept in the network, false otherwise
*/
protected boolean test(TwoWindingsTransformer transformer) {
return test((Branch<?>) transformer);
}
/**
* Return true if the given {@link Branch} should be kept in the network, false otherwise
*/
private boolean test(Branch<?> branch) {
Objects.requireNonNull(branch);
VoltageLevel vl1 = branch.getTerminal1().getVoltageLevel();
VoltageLevel vl2 = branch.getTerminal2().getVoltageLevel();
return test(vl1) && test(vl2);
}
/**
* Return true if the given {@link ThreeWindingsTransformer} should be kept in the network, false otherwise
*/
protected boolean test(ThreeWindingsTransformer transformer) {
Objects.requireNonNull(transformer);
VoltageLevel vl1 = transformer.getLeg1().getTerminal().getVoltageLevel();
VoltageLevel vl2 = transformer.getLeg2().getTerminal().getVoltageLevel();
VoltageLevel vl3 = transformer.getLeg3().getTerminal().getVoltageLevel();
return test(vl1) && test(vl2) && test(vl3);
}
/**
* Return true if the given {@link HvdcLine} should be kept in the network, false otherwise
*/
protected boolean test(HvdcLine hvdcLine) {
Objects.requireNonNull(hvdcLine);
VoltageLevel vl1 = hvdcLine.getConverterStation1().getTerminal().getVoltageLevel();
VoltageLevel vl2 = hvdcLine.getConverterStation2().getTerminal().getVoltageLevel();
return test(vl1) && test(vl2);
}
protected void buildVoltageLevelIdSet(Network network) {
List<String> voltageLevels = network.getVoltageLevelStream()
.filter(predicate::test)
.map(VoltageLevel::getId)
.toList();
vlIds.addAll(voltageLevels);
//Adding necessary vl for three winding transformers
List<ThreeWindingsTransformer> threeWindingsTransformers = network.getThreeWindingsTransformerStream()
.filter(t -> !test(t))
.collect(Collectors.toList());
checkThreeWindingsTransformersToKeep(threeWindingsTransformers);
}
private void checkThreeWindingsTransformersToKeep(List<ThreeWindingsTransformer> threeWindingsTransformers) {
List<ThreeWindingsTransformer> modifiedTransformers = new ArrayList<>();
threeWindingsTransformers.stream()
.filter(this::mustBeKept)
.forEach(transformer -> {
VoltageLevel vlToAdd = findVoltageLevelToAdd(transformer);
if (vlToAdd != null) {
vlIds.add(vlToAdd.getId());
modifiedTransformers.add(transformer);
LOGGER.info("It is not possible to keep exactly 2 out of 3 voltage levels connected to a three winding transformer (here {}).\n" +
" Adding voltage level {} to the voltage levels kept after the reduction.", transformer.getId(), vlToAdd.getId());
}
});
if (!modifiedTransformers.isEmpty()) {
threeWindingsTransformers.removeAll(modifiedTransformers);
checkThreeWindingsTransformersToKeep(threeWindingsTransformers);
}
}
private boolean mustBeKept(ThreeWindingsTransformer transformer) {
long count = transformer.getLegStream()
.filter(leg -> test(leg.getTerminal().getVoltageLevel()))
.count();
return count == 2;
}
private VoltageLevel findVoltageLevelToAdd(ThreeWindingsTransformer transformer) {
VoltageLevel vl1 = transformer.getLeg1().getTerminal().getVoltageLevel();
VoltageLevel vl2 = transformer.getLeg2().getTerminal().getVoltageLevel();
VoltageLevel vl3 = transformer.getLeg3().getTerminal().getVoltageLevel();
if (!test(vl1)) {
return vl1;
} else if (!test(vl2)) {
return vl2;
} else if (!test(vl3)) {
return vl3;
} else {
return null;
}
}
}