ExtendedAmplExporter.java
/**
* Copyright (c) 2023, 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.ampl.converter.version;
import com.powsybl.ampl.converter.AmplConstants;
import com.powsybl.ampl.converter.AmplExportConfig;
import com.powsybl.ampl.converter.AmplSubset;
import com.powsybl.ampl.converter.AmplUtil;
import com.powsybl.ampl.converter.util.NetworkUtil;
import com.powsybl.commons.io.table.Column;
import com.powsybl.commons.io.table.TableFormatter;
import com.powsybl.commons.io.table.TableFormatterHelper;
import com.powsybl.commons.util.StringToIntMapper;
import com.powsybl.iidm.network.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static com.powsybl.ampl.converter.AmplConstants.*;
/**
* 1st extension of BasicAmplExporter, associated with AMPL version 1.1 (exporter id).
* The extension adds:
* - A synchronous component number in the bus tables.
* - A slack bus boolean in the bus table.
* - R, G and B characteristics in tap tables.
* - The regulated bus in generator and static var compensator tables.
*
* @author Nicolas PIERRE {@literal <nicolas.pierre at artelys.com>}
* @author Pierre ARVY {@literal <pierre.arvy at artelys.com>}
*/
public class ExtendedAmplExporter extends BasicAmplExporter {
private static final int SYNCHRONOUS_COMPONENT_COLUMN_INDEX = 4;
private static final int SLACK_BUS_COLUMN_INDEX = 9;
private static final int TAP_CHANGER_R_COLUMN_INDEX = 4;
private static final int TAP_CHANGER_G_COLUMN_INDEX = 6;
private static final int TAP_CHANGER_B_COLUMN_INDEX = 7;
private static final int GENERATOR_V_REGUL_BUS_COLUMN_INDEX = 14;
private static final int STATIC_VAR_COMPENSATOR_V_REGUL_BUS_COLUMN_INDEX = 8;
private int otherScNum = Integer.MAX_VALUE;
public ExtendedAmplExporter(AmplExportConfig config,
Network network,
StringToIntMapper<AmplSubset> mapper,
int variantIndex, int faultNum, int actionNum) {
super(config, network, mapper, variantIndex, faultNum, actionNum);
}
private record ImpedanceAndAdmittance(double r, double x, double g, double b) { }
@Override
public List<Column> getBusesColumns() {
List<Column> busesColumns = new ArrayList<>(super.getBusesColumns());
// add synchronous component column
busesColumns.add(SYNCHRONOUS_COMPONENT_COLUMN_INDEX, new Column("sc"));
// add slack bus column
busesColumns.add(SLACK_BUS_COLUMN_INDEX, new Column("slack bus"));
return busesColumns;
}
@Override
public List<Column> getTapChangerTableColumns() {
List<Column> tapChangerTableColumns = new ArrayList<>(super.getTapChangerTableColumns());
// add r, g and b columns
tapChangerTableColumns.add(TAP_CHANGER_R_COLUMN_INDEX, new Column("r (pu)"));
tapChangerTableColumns.add(TAP_CHANGER_G_COLUMN_INDEX, new Column("g (pu)"));
tapChangerTableColumns.add(TAP_CHANGER_B_COLUMN_INDEX, new Column("b (pu)"));
return tapChangerTableColumns;
}
@Override
public List<Column> getGeneratorsColumns() {
List<Column> generatorsColumns = new ArrayList<>(super.getGeneratorsColumns());
// add column for voltage regulated bus
generatorsColumns.add(GENERATOR_V_REGUL_BUS_COLUMN_INDEX, new Column(V_REGUL_BUS));
return generatorsColumns;
}
@Override
public List<Column> getStaticVarCompensatorColumns() {
List<Column> svcColumns = new ArrayList<>(super.getStaticVarCompensatorColumns());
// add column for voltage regulated bus
svcColumns.add(STATIC_VAR_COMPENSATOR_V_REGUL_BUS_COLUMN_INDEX, new Column(V_REGUL_BUS));
return svcColumns;
}
@Override
public void addAdditionalCellsBusesColumns(TableFormatterHelper formatterHelper, Bus b) {
formatterHelper.addCell(b.getSynchronousComponent().getNum(), SYNCHRONOUS_COMPONENT_COLUMN_INDEX);
formatterHelper.addCell(NetworkUtil.isSlackBus(b), SLACK_BUS_COLUMN_INDEX);
}
@Override
public void addAdditionalCellsThreeWindingsTranformersMiddleBusesColumns(TableFormatterHelper formatterHelper,
ThreeWindingsTransformer twt,
int middleCcNum) {
formatterHelper.addCell(getThreeWindingsTransformerMiddleBusSCNum(twt), SYNCHRONOUS_COMPONENT_COLUMN_INDEX);
formatterHelper.addCell(false, SLACK_BUS_COLUMN_INDEX);
}
private int getThreeWindingsTransformerMiddleBusSCNum(ThreeWindingsTransformer twt) {
Terminal t1 = twt.getLeg1().getTerminal();
Terminal t2 = twt.getLeg2().getTerminal();
Terminal t3 = twt.getLeg3().getTerminal();
Bus b1 = AmplUtil.getBus(t1);
Bus b2 = AmplUtil.getBus(t2);
Bus b3 = AmplUtil.getBus(t3);
int middleScNum;
if (b1 != null) {
middleScNum = b1.getSynchronousComponent().getNum();
} else if (b2 != null) {
middleScNum = b2.getSynchronousComponent().getNum();
} else if (b3 != null) {
middleScNum = b3.getSynchronousComponent().getNum();
} else {
middleScNum = otherScNum--;
}
return middleScNum;
}
@Override
public void addAdditionalCellsDanglingLineMiddleBuses(TableFormatterHelper formatterHelper, DanglingLine dl,
int middleCcNum) {
formatterHelper.addCell(getDanglingLineMiddleBusSCNum(dl), SYNCHRONOUS_COMPONENT_COLUMN_INDEX);
formatterHelper.addCell(false, SLACK_BUS_COLUMN_INDEX);
}
private int getDanglingLineMiddleBusSCNum(DanglingLine dl) {
Bus b = AmplUtil.getBus(dl.getTerminal());
return b != null ? b.getSynchronousComponent().getNum() : otherScNum--;
}
@Override
public void addAdditionalCellsTieLineMiddleBuses(TableFormatterHelper formatterHelper, TieLine tieLine,
int xNodeCcNum) {
formatterHelper.addCell(getTieLineMiddleBusSCNum(tieLine), SYNCHRONOUS_COMPONENT_COLUMN_INDEX);
formatterHelper.addCell(false, SLACK_BUS_COLUMN_INDEX);
}
private int getTieLineMiddleBusSCNum(TieLine tieLine) {
Terminal t1 = tieLine.getDanglingLine1().getTerminal();
Terminal t2 = tieLine.getDanglingLine2().getTerminal();
Bus b1 = AmplUtil.getBus(t1);
Bus b2 = AmplUtil.getBus(t2);
int xNodeScNum;
if (b1 != null) {
xNodeScNum = b1.getSynchronousComponent().getNum();
} else if (b2 != null) {
xNodeScNum = b2.getSynchronousComponent().getNum();
} else {
xNodeScNum = otherScNum--;
}
return xNodeScNum;
}
@Override
public void writeTwoWindingsTransformerTapChangerTableToFormatter(TableFormatter formatter,
TwoWindingsTransformer twt) throws IOException {
Terminal t2 = twt.getTerminal2();
double vb2 = t2.getVoltageLevel().getNominalV();
double zb2 = vb2 * vb2 / AmplConstants.SB;
ImpedanceAndAdmittance transformer = new ImpedanceAndAdmittance(twt.getR(), twt.getX(),
twt.getG(), twt.getB());
RatioTapChanger rtc = twt.getRatioTapChanger();
if (rtc != null) {
String id = twt.getId() + RATIO_TABLE_SUFFIX;
writeRatioTapChanger(formatter, id, zb2, transformer, rtc);
}
PhaseTapChanger ptc = twt.getPhaseTapChanger();
if (ptc != null) {
String id = twt.getId() + PHASE_TABLE_SUFFIX;
writePhaseTapChanger(formatter, id, zb2, transformer, ptc);
}
}
@Override
public void writeThreeWindingsTransformerTapChangerTableToFormatter(TableFormatter formatter,
ThreeWindingsTransformer twt) throws IOException {
int legNumber = 0;
for (ThreeWindingsTransformer.Leg leg : twt.getLegs()) {
legNumber++;
RatioTapChanger rtc = leg.getRatioTapChanger();
double vb = twt.getRatedU0();
double zb = vb * vb / AmplConstants.SB;
ImpedanceAndAdmittance transformer = new ImpedanceAndAdmittance(leg.getR(), leg.getX(),
leg.getG(), leg.getB());
if (rtc != null) {
String id = twt.getId() + "_leg" + legNumber + RATIO_TABLE_SUFFIX;
writeRatioTapChanger(formatter, id, zb, transformer, rtc);
}
PhaseTapChanger ptc = leg.getPhaseTapChanger();
if (ptc != null) {
String id = twt.getId() + "_leg" + legNumber + PHASE_TABLE_SUFFIX;
writePhaseTapChanger(formatter, id, zb, transformer, ptc);
}
}
}
private void writeRatioTapChanger(TableFormatter formatter, String id, double zb2,
ImpedanceAndAdmittance transformerZandY,
RatioTapChanger rtc) throws IOException {
int num = getMapper().getInt(AmplSubset.TAP_CHANGER_TABLE, id);
for (int position = rtc.getLowTapPosition(); position <= rtc.getHighTapPosition(); position++) {
RatioTapChangerStep step = rtc.getStep(position);
ImpedanceAndAdmittance stepCharacteristics = new ImpedanceAndAdmittance(step.getR(), step.getX(), step.getG(), step.getB());
writeTapChanger(formatter, new TapChangerParametersForWriter(num, position, rtc.getLowTapPosition(), zb2, transformerZandY, stepCharacteristics, step.getRho(), 0));
}
}
private void writePhaseTapChanger(TableFormatter formatter, String id, double zb2,
ImpedanceAndAdmittance transformerZandY,
PhaseTapChanger ptc) throws IOException {
int num = getMapper().getInt(AmplSubset.TAP_CHANGER_TABLE, id);
for (int position = ptc.getLowTapPosition(); position <= ptc.getHighTapPosition(); position++) {
PhaseTapChangerStep step = ptc.getStep(position);
ImpedanceAndAdmittance stepCharacteristics = new ImpedanceAndAdmittance(step.getR(), step.getX(), step.getG(), step.getB());
writeTapChanger(formatter, new TapChangerParametersForWriter(num, position, ptc.getLowTapPosition(), zb2, transformerZandY, stepCharacteristics, step.getRho(), Math.toRadians(step.getAlpha())));
}
}
private record TapChangerParametersForWriter(int num, int stepPosition, int lowTapPosition, double zb2,
ImpedanceAndAdmittance transformer, ImpedanceAndAdmittance step, double rho, double alpha) { }
private void writeTapChanger(TableFormatter formatter, TapChangerParametersForWriter parametersForWriter) throws IOException {
double rNorm = parametersForWriter.transformer.r * (1 + parametersForWriter.step.r / 100) / parametersForWriter.zb2;
double xNorm = parametersForWriter.transformer.x * (1 + parametersForWriter.step.x / 100) / parametersForWriter.zb2;
double gNorm = parametersForWriter.transformer.g * (1 + parametersForWriter.step.g / 100) * parametersForWriter.zb2;
double bNorm = parametersForWriter.transformer.b * (1 + parametersForWriter.step.b / 100) * parametersForWriter.zb2;
formatter.writeCell(getVariantIndex())
.writeCell(parametersForWriter.num)
.writeCell(parametersForWriter.stepPosition - parametersForWriter.lowTapPosition + 1)
.writeCell(parametersForWriter.rho)
.writeCell(rNorm)
.writeCell(xNorm)
.writeCell(gNorm)
.writeCell(bNorm)
.writeCell(parametersForWriter.alpha)
.writeCell(getFaultNum())
.writeCell(getActionNum());
}
@Override
public void addAdditionalCellsGenerator(TableFormatterHelper formatterHelper, Generator gen) {
int regulatingBusNum = gen.isVoltageRegulatorOn() && gen.getRegulatingTerminal().isConnected() ?
getMapper().getInt(AmplSubset.BUS, gen.getRegulatingTerminal().getBusView().getBus().getId()) : -1;
formatterHelper.addCell(regulatingBusNum, GENERATOR_V_REGUL_BUS_COLUMN_INDEX);
}
@Override
public void addAdditionalCellsStaticVarCompensator(TableFormatterHelper formatterHelper,
StaticVarCompensator svc) {
boolean voltageRegulation = svc.getRegulationMode().equals(StaticVarCompensator.RegulationMode.VOLTAGE);
int regulatingBusNum = voltageRegulation && svc.getRegulatingTerminal().isConnected() ?
getMapper().getInt(AmplSubset.BUS, svc.getRegulatingTerminal().getBusView().getBus().getId()) : -1;
// Cell to add
formatterHelper.addCell(regulatingBusNum, STATIC_VAR_COMPENSATOR_V_REGUL_BUS_COLUMN_INDEX);
}
}