ThreeWindingsTransformerImpl.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.LimitViolationUtils;
import java.util.*;
import java.util.stream.Stream;
/**
* @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
*/
class ThreeWindingsTransformerImpl extends AbstractConnectable<ThreeWindingsTransformer>
implements ThreeWindingsTransformer {
static class LegImpl
implements Validable, Leg, RatioTapChangerParent, PhaseTapChangerParent {
protected ThreeWindingsTransformerImpl transformer;
private double r;
private double x;
private double g;
private double b;
private double ratedU;
private double ratedS;
private OperationalLimitsGroupsImpl operationalLimitsHolder;
private RatioTapChangerImpl ratioTapChanger;
private PhaseTapChangerImpl phaseTapChanger;
private final ThreeSides side;
LegImpl(double r, double x, double g, double b, double ratedU, double ratedS, ThreeSides side) {
this.r = r;
this.x = x;
this.g = g;
this.b = b;
this.ratedU = ratedU;
this.side = Objects.requireNonNull(side);
this.ratedS = ratedS;
}
void setTransformer(ThreeWindingsTransformerImpl transformer) {
this.transformer = transformer;
operationalLimitsHolder = new OperationalLimitsGroupsImpl(transformer, "limits" + side.getNum());
}
public TerminalExt getTerminal() {
return transformer.terminals.get(side.getNum() - 1);
}
public double getR() {
return r;
}
public Leg setR(double r) {
ValidationUtil.checkR(this, r);
double oldValue = this.r;
this.r = r;
transformer.notifyUpdate(() -> getLegAttribute() + ".r", oldValue, r);
return this;
}
public double getX() {
return x;
}
public Leg setX(double x) {
ValidationUtil.checkX(this, x);
double oldValue = this.x;
this.x = x;
transformer.notifyUpdate(() -> getLegAttribute() + ".x", oldValue, x);
return this;
}
public double getG() {
return g;
}
public Leg setG(double g) {
ValidationUtil.checkG(this, g);
double oldValue = this.g;
this.g = g;
transformer.notifyUpdate(() -> getLegAttribute() + ".g", oldValue, g);
return this;
}
public double getB() {
return b;
}
public Leg setB(double b) {
ValidationUtil.checkB(this, b);
double oldValue = this.b;
this.b = b;
transformer.notifyUpdate(() -> getLegAttribute() + ".b", oldValue, b);
return this;
}
public double getRatedU() {
return ratedU;
}
public Leg setRatedU(double ratedU) {
ValidationUtil.checkRatedU(this, ratedU, "");
double oldValue = this.ratedU;
this.ratedU = ratedU;
transformer.notifyUpdate(() -> getLegAttribute() + ".ratedU", oldValue, ratedU);
return this;
}
public RatioTapChangerAdderImpl newRatioTapChanger() {
return new RatioTapChangerAdderImpl(this);
}
public RatioTapChangerImpl getRatioTapChanger() {
return ratioTapChanger;
}
public PhaseTapChangerAdderImpl newPhaseTapChanger() {
return new PhaseTapChangerAdderImpl(this);
}
public PhaseTapChangerImpl getPhaseTapChanger() {
return phaseTapChanger;
}
@Override
public NetworkImpl getNetwork() {
return transformer.getNetwork();
}
@Override
public NetworkExt getParentNetwork() {
return transformer.getParentNetwork();
}
@Override
public void setRatioTapChanger(RatioTapChangerImpl ratioTapChanger) {
RatioTapChangerImpl oldValue = this.ratioTapChanger;
this.ratioTapChanger = ratioTapChanger;
transformer.notifyUpdate(() -> getLegAttribute() + "." + getTapChangerAttribute(), oldValue,
ratioTapChanger);
}
@Override
public void setPhaseTapChanger(PhaseTapChangerImpl phaseTapChanger) {
PhaseTapChangerImpl oldValue = this.phaseTapChanger;
this.phaseTapChanger = phaseTapChanger;
transformer.notifyUpdate(() -> getLegAttribute() + "." + getTapChangerAttribute(), oldValue,
phaseTapChanger);
}
@Override
public Collection<OperationalLimitsGroup> getOperationalLimitsGroups() {
return operationalLimitsHolder.getOperationalLimitsGroups();
}
@Override
public Optional<String> getSelectedOperationalLimitsGroupId() {
return operationalLimitsHolder.getSelectedOperationalLimitsGroupId();
}
@Override
public Optional<OperationalLimitsGroup> getOperationalLimitsGroup(String id) {
return operationalLimitsHolder.getOperationalLimitsGroup(id);
}
@Override
public Optional<OperationalLimitsGroup> getSelectedOperationalLimitsGroup() {
return operationalLimitsHolder.getSelectedOperationalLimitsGroup();
}
@Override
public OperationalLimitsGroup newOperationalLimitsGroup(String id) {
return operationalLimitsHolder.newOperationalLimitsGroup(id);
}
@Override
public void setSelectedOperationalLimitsGroup(String id) {
operationalLimitsHolder.setSelectedOperationalLimitsGroup(id);
}
@Override
public void removeOperationalLimitsGroup(String id) {
operationalLimitsHolder.removeOperationalLimitsGroup(id);
}
@Override
public void cancelSelectedOperationalLimitsGroup() {
operationalLimitsHolder.cancelSelectedOperationalLimitsGroup();
}
@Override
public CurrentLimitsAdder newCurrentLimits() {
return operationalLimitsHolder.newCurrentLimits();
}
@Override
public ActivePowerLimitsAdder newActivePowerLimits() {
return operationalLimitsHolder.newActivePowerLimits();
}
@Override
public ApparentPowerLimitsAdder newApparentPowerLimits() {
return operationalLimitsHolder.newApparentPowerLimits();
}
protected String getTypeDescription() {
return "3 windings transformer " + getLegAttribute();
}
@Override
public String toString() {
return transformer.getId() + " " + getLegAttribute();
}
public ThreeWindingsTransformer getTransformer() {
return transformer;
}
@Override
public String getMessageHeader() {
return getTypeDescription() + " '" + transformer.getId() + "': ";
}
public String getTapChangerAttribute() {
return String.format("TapChanger%d", side.getNum());
}
protected String getLegAttribute() {
return String.format("leg%d", side.getNum());
}
@Override
public Set<TapChanger<?, ?, ?, ?>> getAllTapChangers() {
Set<TapChanger<?, ?, ?, ?>> tapChangers = new HashSet<>();
transformer.leg1.getOptionalRatioTapChanger().ifPresent(tapChangers::add);
transformer.leg1.getOptionalPhaseTapChanger().ifPresent(tapChangers::add);
transformer.leg2.getOptionalRatioTapChanger().ifPresent(tapChangers::add);
transformer.leg2.getOptionalPhaseTapChanger().ifPresent(tapChangers::add);
transformer.leg3.getOptionalRatioTapChanger().ifPresent(tapChangers::add);
transformer.leg3.getOptionalPhaseTapChanger().ifPresent(tapChangers::add);
return tapChangers;
}
@Override
public boolean hasRatioTapChanger() {
return ratioTapChanger != null;
}
@Override
public boolean hasPhaseTapChanger() {
return phaseTapChanger != null;
}
@Override
public double getRatedS() {
return ratedS;
}
@Override
public LegImpl setRatedS(double ratedS) {
ValidationUtil.checkRatedS(this, ratedS);
double oldValue = this.ratedS;
this.ratedS = ratedS;
transformer.notifyUpdate(() -> getLegAttribute() + ".ratedS", oldValue, ratedS);
return this;
}
@Override
public ThreeSides getSide() {
return side;
}
@Override
public Optional<? extends LoadingLimits> getLimits(LimitType type) {
return switch (type) {
case CURRENT -> getCurrentLimits();
case ACTIVE_POWER -> getActivePowerLimits();
case APPARENT_POWER -> getApparentPowerLimits();
default ->
throw new UnsupportedOperationException(String.format("Getting %s limits is not supported.", type.name()));
};
}
}
private final LegImpl leg1;
private final LegImpl leg2;
private final LegImpl leg3;
private double ratedU0;
ThreeWindingsTransformerImpl(Ref<NetworkImpl> network, String id, String name, boolean fictitious, LegImpl leg1, LegImpl leg2, LegImpl leg3, double ratedU0) {
super(network, id, name, fictitious);
this.leg1 = Objects.requireNonNull(leg1);
this.leg2 = Objects.requireNonNull(leg2);
this.leg3 = Objects.requireNonNull(leg3);
this.ratedU0 = ratedU0;
}
@Override
public Optional<Substation> getSubstation() {
return getLegStream()
.map(leg -> leg.getTerminal().getVoltageLevel().getSubstation())
.filter(Optional::isPresent)
.findFirst()
.orElseGet(Optional::empty);
}
@Override
public Substation getNullableSubstation() {
return getLegStream()
.map(leg -> leg.getTerminal().getVoltageLevel().getNullableSubstation())
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
}
@Override
public LegImpl getLeg1() {
return leg1;
}
@Override
public LegImpl getLeg2() {
return leg2;
}
@Override
public LegImpl getLeg3() {
return leg3;
}
@Override
public Stream<Leg> getLegStream() {
return Stream.of(leg1, leg2, leg3);
}
@Override
public List<Leg> getLegs() {
return Arrays.asList(leg1, leg2, leg3);
}
@Override
public ThreeWindingsTransformer setRatedU0(double ratedU0) {
ValidationUtil.checkRatedU(this, ratedU0, "");
double oldValue = this.ratedU0;
this.ratedU0 = ratedU0;
notifyUpdate("ratedU0", oldValue, ratedU0);
return this;
}
@Override
public double getRatedU0() {
return ratedU0;
}
@Override
public Terminal getTerminal(ThreeSides side) {
return switch (side) {
case ONE -> getLeg1().getTerminal();
case TWO -> getLeg2().getTerminal();
case THREE -> getLeg3().getTerminal();
};
}
@Override
public Terminal getTerminal(String voltageLevelId) {
Objects.requireNonNull(voltageLevelId);
boolean isLeg1ConnectedToVoltageLevel = isLegConnectedToVoltageLevel(getLeg1(), voltageLevelId);
boolean isLeg2ConnectedToVoltageLevel = isLegConnectedToVoltageLevel(getLeg2(), voltageLevelId);
boolean isLeg3ConnectedToVoltageLevel = isLegConnectedToVoltageLevel(getLeg3(), voltageLevelId);
if (isLeg1ConnectedToVoltageLevel
&& isLeg2ConnectedToVoltageLevel
&& isLeg3ConnectedToVoltageLevel) {
throw new PowsyblException("The three terminals are connected to the same voltage level " + voltageLevelId);
} else if (isLeg1ConnectedToVoltageLevel && isLeg2ConnectedToVoltageLevel
|| isLeg3ConnectedToVoltageLevel && isLeg1ConnectedToVoltageLevel
|| isLeg2ConnectedToVoltageLevel && isLeg3ConnectedToVoltageLevel) {
throw new PowsyblException("Two of the three terminals are connected to the same voltage level " + voltageLevelId);
} else if (isLeg1ConnectedToVoltageLevel) {
return getLeg1().getTerminal();
} else if (isLeg2ConnectedToVoltageLevel) {
return getLeg2().getTerminal();
} else if (isLeg3ConnectedToVoltageLevel) {
return getLeg3().getTerminal();
} else {
throw new PowsyblException("No terminal connected to voltage level " + voltageLevelId);
}
}
private boolean isLegConnectedToVoltageLevel(ThreeWindingsTransformer.Leg leg, String voltageLevelId) {
return Optional.ofNullable(leg.getTerminal().getVoltageLevel())
.map(vl -> voltageLevelId.equals(vl.getId()))
.orElse(Boolean.FALSE);
}
@Override
public ThreeSides getSide(Terminal terminal) {
Objects.requireNonNull(terminal);
if (getLeg1().getTerminal() == terminal) {
return ThreeSides.ONE;
} else if (getLeg2().getTerminal() == terminal) {
return ThreeSides.TWO;
} else if (getLeg3().getTerminal() == terminal) {
return ThreeSides.THREE;
} else {
throw new IllegalStateException("The terminal is not connected to this three windings transformer");
}
}
@Override
public void extendVariantArraySize(int initVariantArraySize, int number, int sourceIndex) {
super.extendVariantArraySize(initVariantArraySize, number, sourceIndex);
leg1.getOptionalRatioTapChanger().ifPresent(rtc -> ((RatioTapChangerImpl) rtc).extendVariantArraySize(initVariantArraySize, number, sourceIndex));
leg1.getOptionalPhaseTapChanger().ifPresent(ptc -> ((PhaseTapChangerImpl) ptc).extendVariantArraySize(initVariantArraySize, number, sourceIndex));
leg2.getOptionalRatioTapChanger().ifPresent(rtc -> ((RatioTapChangerImpl) rtc).extendVariantArraySize(initVariantArraySize, number, sourceIndex));
leg2.getOptionalPhaseTapChanger().ifPresent(ptc -> ((PhaseTapChangerImpl) ptc).extendVariantArraySize(initVariantArraySize, number, sourceIndex));
leg3.getOptionalRatioTapChanger().ifPresent(rtc -> ((RatioTapChangerImpl) rtc).extendVariantArraySize(initVariantArraySize, number, sourceIndex));
leg3.getOptionalPhaseTapChanger().ifPresent(ptc -> ((PhaseTapChangerImpl) ptc).extendVariantArraySize(initVariantArraySize, number, sourceIndex));
}
@Override
public void reduceVariantArraySize(int number) {
super.reduceVariantArraySize(number);
leg1.getOptionalRatioTapChanger().ifPresent(rtc -> ((RatioTapChangerImpl) rtc).reduceVariantArraySize(number));
leg1.getOptionalPhaseTapChanger().ifPresent(ptc -> ((PhaseTapChangerImpl) ptc).reduceVariantArraySize(number));
leg2.getOptionalRatioTapChanger().ifPresent(rtc -> ((RatioTapChangerImpl) rtc).reduceVariantArraySize(number));
leg2.getOptionalPhaseTapChanger().ifPresent(ptc -> ((PhaseTapChangerImpl) ptc).reduceVariantArraySize(number));
leg3.getOptionalRatioTapChanger().ifPresent(rtc -> ((RatioTapChangerImpl) rtc).reduceVariantArraySize(number));
leg3.getOptionalPhaseTapChanger().ifPresent(ptc -> ((PhaseTapChangerImpl) ptc).reduceVariantArraySize(number));
}
@Override
public void deleteVariantArrayElement(int index) {
super.deleteVariantArrayElement(index);
leg1.getOptionalRatioTapChanger().ifPresent(rtc -> ((RatioTapChangerImpl) rtc).deleteVariantArrayElement(index));
leg1.getOptionalPhaseTapChanger().ifPresent(ptc -> ((PhaseTapChangerImpl) ptc).deleteVariantArrayElement(index));
leg2.getOptionalRatioTapChanger().ifPresent(rtc -> ((RatioTapChangerImpl) rtc).deleteVariantArrayElement(index));
leg2.getOptionalPhaseTapChanger().ifPresent(ptc -> ((PhaseTapChangerImpl) ptc).deleteVariantArrayElement(index));
leg3.getOptionalRatioTapChanger().ifPresent(rtc -> ((RatioTapChangerImpl) rtc).deleteVariantArrayElement(index));
leg3.getOptionalPhaseTapChanger().ifPresent(ptc -> ((PhaseTapChangerImpl) ptc).deleteVariantArrayElement(index));
}
@Override
public void allocateVariantArrayElement(int[] indexes, int sourceIndex) {
super.allocateVariantArrayElement(indexes, sourceIndex);
leg1.getOptionalRatioTapChanger().ifPresent(rtc -> ((RatioTapChangerImpl) rtc).allocateVariantArrayElement(indexes, sourceIndex));
leg1.getOptionalPhaseTapChanger().ifPresent(ptc -> ((PhaseTapChangerImpl) ptc).allocateVariantArrayElement(indexes, sourceIndex));
leg2.getOptionalRatioTapChanger().ifPresent(rtc -> ((RatioTapChangerImpl) rtc).allocateVariantArrayElement(indexes, sourceIndex));
leg2.getOptionalPhaseTapChanger().ifPresent(ptc -> ((PhaseTapChangerImpl) ptc).allocateVariantArrayElement(indexes, sourceIndex));
leg3.getOptionalRatioTapChanger().ifPresent(rtc -> ((RatioTapChangerImpl) rtc).allocateVariantArrayElement(indexes, sourceIndex));
leg3.getOptionalPhaseTapChanger().ifPresent(ptc -> ((PhaseTapChangerImpl) ptc).allocateVariantArrayElement(indexes, sourceIndex));
}
@Override
protected String getTypeDescription() {
return "3 windings transformer";
}
@Override
public boolean isOverloaded() {
return isOverloaded(1.0f);
}
@Override
public boolean isOverloaded(double limitReductionValue) {
return checkPermanentLimit1(limitReductionValue, LimitType.CURRENT)
|| checkPermanentLimit2(limitReductionValue, LimitType.CURRENT)
|| checkPermanentLimit3(limitReductionValue, LimitType.CURRENT);
}
@Override
public int getOverloadDuration() {
Overload o1 = checkTemporaryLimits1(LimitType.CURRENT);
Overload o2 = checkTemporaryLimits2(LimitType.CURRENT);
Overload o3 = checkTemporaryLimits3(LimitType.CURRENT);
int duration1 = o1 != null ? o1.getTemporaryLimit().getAcceptableDuration() : Integer.MAX_VALUE;
int duration2 = o2 != null ? o2.getTemporaryLimit().getAcceptableDuration() : Integer.MAX_VALUE;
int duration3 = o3 != null ? o3.getTemporaryLimit().getAcceptableDuration() : Integer.MAX_VALUE;
return Math.min(Math.min(duration1, duration2), duration3);
}
@Override
public boolean checkPermanentLimit(ThreeSides side, double limitReductionValue, LimitType type) {
return LimitViolationUtils.checkPermanentLimit(this, side, limitReductionValue, type);
}
@Override
public boolean checkPermanentLimit(ThreeSides side, LimitType type) {
return checkPermanentLimit(side, 1f, type);
}
@Override
public boolean checkPermanentLimit1(double limitReductionValue, LimitType type) {
return checkPermanentLimit(ThreeSides.ONE, limitReductionValue, type);
}
@Override
public boolean checkPermanentLimit1(LimitType type) {
return checkPermanentLimit1(1f, type);
}
@Override
public boolean checkPermanentLimit2(double limitReductionValue, LimitType type) {
return checkPermanentLimit(ThreeSides.TWO, limitReductionValue, type);
}
@Override
public boolean checkPermanentLimit2(LimitType type) {
return checkPermanentLimit2(1f, type);
}
@Override
public boolean checkPermanentLimit3(double limitReductionValue, LimitType type) {
return checkPermanentLimit(ThreeSides.THREE, limitReductionValue, type);
}
@Override
public boolean checkPermanentLimit3(LimitType type) {
return checkPermanentLimit3(1f, type);
}
@Override
public Overload checkTemporaryLimits(ThreeSides side, double limitReductionValue, LimitType type) {
return LimitViolationUtils.checkTemporaryLimits(this, side, limitReductionValue, type);
}
@Override
public Overload checkTemporaryLimits(ThreeSides side, LimitType type) {
return checkTemporaryLimits(side, 1f, type);
}
@Override
public Overload checkTemporaryLimits1(double limitReductionValue, LimitType type) {
return checkTemporaryLimits(ThreeSides.ONE, limitReductionValue, type);
}
@Override
public Overload checkTemporaryLimits1(LimitType type) {
return checkTemporaryLimits1(1f, type);
}
@Override
public Overload checkTemporaryLimits2(double limitReductionValue, LimitType type) {
return checkTemporaryLimits(ThreeSides.TWO, limitReductionValue, type);
}
@Override
public Overload checkTemporaryLimits2(LimitType type) {
return checkTemporaryLimits2(1f, type);
}
@Override
public Overload checkTemporaryLimits3(double limitReductionValue, LimitType type) {
return checkTemporaryLimits(ThreeSides.THREE, limitReductionValue, type);
}
@Override
public Overload checkTemporaryLimits3(LimitType type) {
return checkTemporaryLimits3(1f, type);
}
}