All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.powsybl.cgmes.conversion.elements.transformers.TapChangerConversion Maven / Gradle / Ivy

There is a newer version: 6.6.0
Show newest version
/**
 * Copyright (c) 2020, 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/.
 */

package com.powsybl.cgmes.conversion.elements.transformers;

import com.powsybl.cgmes.conversion.Context;
import com.powsybl.cgmes.conversion.elements.transformers.TapChanger.Step;
import com.powsybl.cgmes.model.CgmesModelException;
import org.apache.commons.math3.complex.Complex;

import java.util.Objects;

/**
 * TapChangerTypes
 * 

* TapChangers are classified into four categories: NULL, FIXED, NON_REGULATING and REGULATING
* NULL: TapChanger does not exist
* FIXED: TapChanger has only one step
* NON_REGULATING: TapChanger is not regulating. It has several steps
* REGULATING: TapChanger is regulating and has several steps *

* These categories are used to establish a priority ranking when two tapChangers are combined to only one. * The tapChanger with lower priority is fixed at the current tap position and the tapChanger with higher priority * is preserved. NULL is the lowest priority and REGULATING the highest one.
* If both tapChangers are regulating tapChanger at end2 is fixed. *

* The combineTapChanger method does a Cartesian product of two tapChangers getting as result a new tapChanger with * steps1 x steps2 steps. The combined tapChanger will not be useful for network analysis and it is not possible to * map back to the original one.
* To avoid this, one of the tapChangers must be fixed. To do that the tapChangerFixPosition method is used. *

* A warning message is logged when a tapChanger is fixed. *

* When structural ratio is moved from one side to the other a correction is applied to transmission impedance (r, x) and shunt admittance (g and b).
* When tapChanger is moved the transmission impedance and shunt admittance corrections are managed as step correction * expressed as percentage deviation of nominal value. *

* @author Luma Zamarreño {@literal } * @author José Antonio Marqués {@literal } */ public class TapChangerConversion { protected final Context context; TapChangerConversion(Context context) { Objects.requireNonNull(context); this.context = context; } private enum TapChangerType { NULL, FIXED, NON_REGULATING, REGULATING } protected TapChanger combineTapChangers(TapChanger tc1, TapChanger tc2) { switch (tapChangerType(tc1)) { case NULL: return combineTapChangerNull(tc2); case FIXED: return combineTapChangerFixed(tc1, tc2); case NON_REGULATING: return combineTapChangerNonRegulating(tc1, tc2); case REGULATING: return combineTapChangerRegulating(tc1, tc2); } return null; } private static TapChanger combineTapChangerNull(TapChanger tc) { switch (tapChangerType(tc)) { case NULL: return null; case FIXED: case NON_REGULATING: case REGULATING: return tc; } return null; } private static TapChanger combineTapChangerFixed(TapChanger fixTc, TapChanger tc2) { switch (tapChangerType(tc2)) { case NULL: return fixTc; case FIXED: case NON_REGULATING: case REGULATING: return combineTapChanger(tc2, fixTc); } return null; } private TapChanger combineTapChangerNonRegulating(TapChanger tcNonRegulating, TapChanger tc2) { switch (tapChangerType(tc2)) { case NULL: return tcNonRegulating; case FIXED: return combineTapChanger(tcNonRegulating, tc2); case NON_REGULATING: TapChanger ntc2 = tapChangerFixPosition(tc2); return combineTapChanger(tcNonRegulating, ntc2); case REGULATING: TapChanger ntcNonRegulating = tapChangerFixPosition(tcNonRegulating); return combineTapChanger(tc2, ntcNonRegulating); } return null; } private TapChanger combineTapChangerRegulating(TapChanger tcRegulating, TapChanger tc2) { switch (tapChangerType(tc2)) { case NULL: return tcRegulating; case FIXED: return combineTapChanger(tcRegulating, tc2); case NON_REGULATING: case REGULATING: TapChanger ntc2 = tapChangerFixPosition(tc2); return combineTapChanger(tcRegulating, ntc2); } return null; } private static TapChanger combineTapChanger(TapChanger tc1, TapChanger tc2) { TapChanger tapChanger = baseCloneTapChanger(tc1); combineTapChangerSteps(tapChanger, tc1, tc2); tapChanger.setHiddenCombinedTapChanger(tc2); return tapChanger; } /** * A new tapChanger is created with only one step, the current tap position. */ private TapChanger tapChangerFixPosition(TapChanger tc) { if (tc.getLowTapPosition() != tc.getHighTapPosition()) { context.fixed("TapChanger", () -> String.format("%s fixed tap at position %d ", tc.getId(), tc.getTapPosition())); } TapChanger tapChanger = baseCloneTapChanger(tc); tapChanger.setLowTapPosition(tapChanger.getTapPosition()); Step step = getTapChangerFixedStep(tc); double ratio = step.getRatio(); double angle = step.getAngle(); double r = step.getR(); double x = step.getX(); double g1 = step.getG1(); double b1 = step.getB1(); double g2 = step.getG2(); double b2 = step.getB2(); tapChanger.beginStep() .setRatio(ratio) .setAngle(angle) .setR(r) .setX(x) .setG1(g1) .setB1(b1) .setG2(g2) .setB2(b2) .endStep(); return tapChanger; } /** * A new tapChanger is created as Cartesian product of tc1 and tc2 * One of the tapChangers must be fixed (only one step) */ private static void combineTapChangerSteps(TapChanger tapChanger, TapChanger tc1, TapChanger tc2) { TapChanger fixTc; TapChanger tc; if (tc1 != null && tc2 != null && tc1.getSteps().size() == 1 && tc1.getLowTapPosition() == tc1.getHighTapPosition()) { fixTc = tc1; tc = tc2; } else if (tc1 != null && tc2 != null && tc2.getSteps().size() == 1 && tc2.getLowTapPosition() == tc2.getHighTapPosition()) { fixTc = tc2; tc = tc1; } else if (tc1 != null && tc2 != null) { throw new CgmesModelException( "Unexpected number of steps in tapChangers: " + tc1.getId() + ", " + tc2.getId()); } else { throw new CgmesModelException("Unexpected null tapChanger"); } Step stepFixed = getTapChangerFixedStep(fixTc); double ratioFixed = stepFixed.getRatio(); double angleFixed = stepFixed.getAngle(); double rFixed = stepFixed.getR(); double xFixed = stepFixed.getX(); double g1Fixed = stepFixed.getG1(); double b1Fixed = stepFixed.getB1(); double g2Fixed = stepFixed.getG2(); double b2Fixed = stepFixed.getB2(); Complex aFixed = new Complex(ratioFixed * Math.cos(Math.toRadians(angleFixed)), ratioFixed * Math.sin(Math.toRadians(angleFixed))); tc.getSteps().forEach(step -> { double ratio = step.getRatio(); double angle = step.getAngle(); double r = step.getR(); double x = step.getX(); double g1 = step.getG1(); double b1 = step.getB1(); double g2 = step.getG2(); double b2 = step.getB2(); Complex a = new Complex(ratio * Math.cos(Math.toRadians(angle)), ratio * Math.sin(Math.toRadians(angle))); Complex na = a.multiply(aFixed); tapChanger.beginStep() .setRatio(na.abs()) .setAngle(Math.toDegrees(na.getArgument())) .setR(combineTapChangerCorrection(rFixed, r)) .setX(combineTapChangerCorrection(xFixed, x)) .setG1(combineTapChangerCorrection(g1Fixed, g1)) .setB1(combineTapChangerCorrection(b1Fixed, b1)) .setG2(combineTapChangerCorrection(g2Fixed, g2)) .setB2(combineTapChangerCorrection(b2Fixed, b2)) .endStep(); }); tapChanger.setLowTapPosition(tc.getLowTapPosition()); tapChanger.setTapPosition(tc.getTapPosition()); } /** * To combine the percentage deviations express them as multiplying factors, then combine and * express them again as percentage deviations */ private static double combineTapChangerCorrection(double correction1, double correction2) { if (correction1 != 0.0 && correction2 != 0.0) { return 100 * ((1 + correction1 / 100) * (1 + correction2 / 100) - 1); } else if (correction1 != 0.0) { return correction1; } else if (correction2 != 0.0) { return correction2; } else { return 0.0; } } // not used at the moment protected static TapChanger moveTapChangerFrom1To2(TapChanger tc) { return moveTapChangerFromOneEndToTheOther(tc); } protected static TapChanger moveTapChangerFrom2To1(TapChanger tc) { return moveTapChangerFromOneEndToTheOther(tc); } private static TapChanger moveTapChangerFromOneEndToTheOther(TapChanger tc) { switch (tapChangerType(tc)) { case NULL: return null; case FIXED: case NON_REGULATING: case REGULATING: return moveTapChanger(tc); } return null; } /** * A new equivalent tapChanger located in the other side is created. * When given in RatioTapChangerTablePoint * r, x, g, b of the step are already percentage deviations of nominal values * R = R * (1 + r / 100) * X = X * (1 + x / 100) * G = G * (1 + g / 100) * B = B * (1 + b / 100) * * New tapChanger * Will have the same base attributes, ratio will be the reciprocal and * an impedance/admittance deviations are required by step */ private static TapChanger moveTapChanger(TapChanger tc) { TapChanger tapChanger = baseCloneTapChanger(tc); moveTapChangerSteps(tapChanger, tc); return tapChanger; } private static void moveTapChangerSteps(TapChanger tapChanger, TapChanger tc) { tc.getSteps().forEach(step -> { double ratio = step.getRatio(); double angle = step.getAngle(); double r = step.getR(); double x = step.getX(); double g1 = step.getG1(); double b1 = step.getB1(); double g2 = step.getG2(); double b2 = step.getB2(); TapChangerStepConversion convertedStep = calculateConversionStep(ratio, angle, r, x, g1, b1, g2, b2); tapChanger.beginStep() .setRatio(convertedStep.ratio) .setAngle(convertedStep.angle) .setR(convertedStep.r) .setX(convertedStep.x) .setG1(convertedStep.g1) .setB1(convertedStep.b1) .setG2(convertedStep.g2) .setB2(convertedStep.b2) .endStep(); }); } private static TapChangerStepConversion calculateConversionStep(double a, double angle, double r, double x, double g1, double b1, double g2, double b2) { Complex ratio = new Complex(a * Math.cos(Math.toRadians(angle)), a * Math.sin(Math.toRadians(angle))); return calculateConversionStep(ratio, r, x, g1, b1, g2, b2); } /** * To calculate the step correction express it as multiplying factor, then apply the correction * and express again as percentage deviation */ private static TapChangerStepConversion calculateConversionStep(Complex a, double r, double x, double g1, double b1, double g2, double b2) { TapChangerStepConversion step = new TapChangerStepConversion(); Complex na = a.reciprocal(); step.ratio = na.abs(); step.angle = Math.toDegrees(na.getArgument()); step.r = 100 * (impedanceConversion(1 + r / 100, a) - 1); step.x = 100 * (impedanceConversion(1 + x / 100, a) - 1); step.g1 = 100 * (admittanceConversion(1 + g1 / 100, a) - 1); step.b1 = 100 * (admittanceConversion(1 + b1 / 100, a) - 1); step.g2 = 100 * (admittanceConversion(1 + g2 / 100, a) - 1); step.b2 = 100 * (admittanceConversion(1 + b2 / 100, a) - 1); return step; } protected static RatioConversion identityRatioConversion(double r, double x, double g1, double b1, double g2, double b2) { RatioConversion ratio = new RatioConversion(); ratio.r = r; ratio.x = x; ratio.g1 = g1; ratio.b1 = b1; ratio.g2 = g2; ratio.b2 = b2; return ratio; } protected static RatioConversion moveRatioFrom2To1(double a, double angle, double r, double x, double g1, double b1, double g2, double b2) { return moveRatio(a, angle, r, x, g1, b1, g2, b2); } protected static RatioConversion moveRatioFrom1To2(double a, double angle, double r, double x, double g1, double b1, double g2, double b2) { return moveRatio(a, angle, r, x, g1, b1, g2, b2); } /** * Equivalent impedance / admittance after moving a complex ratio from one end to the other */ private static RatioConversion moveRatio(double a, double angle, double r, double x, double g1, double b1, double g2, double b2) { Complex ratio = new Complex(a * Math.cos(Math.toRadians(angle)), a * Math.sin(Math.toRadians(angle))); return moveRatio(ratio, r, x, g1, b1, g2, b2); } private static RatioConversion moveRatio(Complex a, double r, double x, double g1, double b1, double g2, double b2) { RatioConversion ratio = new RatioConversion(); ratio.r = impedanceConversion(r, a); ratio.x = impedanceConversion(x, a); ratio.g1 = admittanceConversion(g1, a); ratio.b1 = admittanceConversion(b1, a); ratio.g2 = admittanceConversion(g2, a); ratio.b2 = admittanceConversion(b2, a); return ratio; } private static double admittanceConversion(double correction, Complex a) { double a2 = a.abs() * a.abs(); return correction / a2; } private static double impedanceConversion(double correction, Complex a) { double a2 = a.abs() * a.abs(); return correction * a2; } /** * A new tapChanger is created with the same base attributes. Steps are not cloned. */ private static TapChanger baseCloneTapChanger(TapChanger rtc) { TapChanger tapChanger = new TapChanger(); String id = rtc.getId(); boolean isLtcFlag = rtc.isLtcFlag(); boolean isRegulating = rtc.isRegulating(); String regulatingControlId = rtc.getRegulatingControlId(); String tculControlMode = rtc.getTculControlMode(); boolean isTapChangerControlEnabled = rtc.isTapChangerControlEnabled(); int lowStep = rtc.getLowTapPosition(); int position = rtc.getTapPosition(); String type = rtc.getType(); TapChanger hiddenCombinedTapChanger = rtc.getHiddenCombinedTapChanger(); tapChanger.setLowTapPosition(lowStep) .setTapPosition(position) .setLtcFlag(isLtcFlag) .setId(id) .setRegulating(isRegulating) .setRegulatingControlId(regulatingControlId) .setTculControlMode(tculControlMode) .setTapChangerControlEnabled(isTapChangerControlEnabled) .setType(type) .setHiddenCombinedTapChanger(hiddenCombinedTapChanger); return tapChanger; } private static Step getTapChangerFixedStep(TapChanger tc) { if (isTapChangerFixed(tc)) { return tc.getSteps().get(0); } int position = tc.getTapPosition(); int lowPosition = tc.getLowTapPosition(); return tc.getSteps().get(position - lowPosition); } private static TapChangerType tapChangerType(TapChanger tc) { if (isTapChangerNull(tc)) { return TapChangerType.NULL; } if (isTapChangerFixed(tc)) { return TapChangerType.FIXED; } if (!isTapChangerRegulating(tc)) { return TapChangerType.NON_REGULATING; } else { return TapChangerType.REGULATING; } } private static boolean isTapChangerNull(TapChanger tc) { return tc == null; } private static boolean isTapChangerFixed(TapChanger tc) { return tc.getSteps().size() == 1; } private static boolean isTapChangerRegulating(TapChanger tc) { return tc.isRegulating(); } static class InterpretedEnd { final double g; final double b; final TapChanger ratioTapChanger; final TapChanger phaseTapChanger; final double ratedU; final String terminal; InterpretedEnd(double g, double b, TapChanger ratioTapChanger, TapChanger phaseTapChanger, double ratedU, String terminal) { this.g = g; this.b = b; this.ratioTapChanger = ratioTapChanger; this.phaseTapChanger = phaseTapChanger; this.ratedU = ratedU; this.terminal = terminal; } } static class ConvertedEnd1 { final double g; final double b; final TapChanger ratioTapChanger; final TapChanger phaseTapChanger; final double ratedU; final String terminal; ConvertedEnd1(double g, double b, TapChanger ratioTapChanger, TapChanger phaseTapChanger, double ratedU, String terminal) { this.g = g; this.b = b; this.ratioTapChanger = ratioTapChanger; this.phaseTapChanger = phaseTapChanger; this.ratedU = ratedU; this.terminal = terminal; } } static class TapChangerStepConversion { double ratio; double angle; double r; double x; double g1; double b1; double g2; double b2; } static class RatioConversion { double r; double x; double g1; double b1; double g2; double b2; } static class AllTapChanger { TapChanger ratioTapChanger1; TapChanger phaseTapChanger1; TapChanger ratioTapChanger2; TapChanger phaseTapChanger2; } static class AllShunt { double g1; double b1; double g2; double b2; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy