TransformerImpedanceCorrectionTablesData.java
/**
* Copyright (c) 2021, 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.psse.model.pf.io;
import com.powsybl.psse.model.PsseException;
import com.powsybl.psse.model.io.*;
import com.powsybl.psse.model.pf.PsseTransformerImpedanceCorrection;
import com.powsybl.psse.model.pf.PsseTransformerImpedanceCorrectionPoint;
import com.univocity.parsers.annotations.Nested;
import com.univocity.parsers.annotations.Parsed;
import org.apache.commons.lang3.ArrayUtils;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import static com.powsybl.psse.model.PsseVersion.Major.V32;
import static com.powsybl.psse.model.PsseVersion.Major.V33;
import static com.powsybl.psse.model.PsseVersion.Major.V35;
import static com.powsybl.psse.model.pf.io.PowerFlowRecordGroup.TRANSFORMER_IMPEDANCE_CORRECTION_TABLES;
/**
* @author Luma Zamarre��o {@literal <zamarrenolm at aia.es>}
* @author Jos�� Antonio Marqu��s {@literal <marquesja at aia.es>}
*/
class TransformerImpedanceCorrectionTablesData extends AbstractRecordGroup<PsseTransformerImpedanceCorrection> {
TransformerImpedanceCorrectionTablesData() {
super(TRANSFORMER_IMPEDANCE_CORRECTION_TABLES);
withIO(FileFormat.LEGACY_TEXT, V32, new IOLegacyText33(this));
withIO(FileFormat.LEGACY_TEXT, V33, new IOLegacyText33(this));
withIO(FileFormat.LEGACY_TEXT, V35, new IOLegacyText35(this));
withIO(FileFormat.JSON, new IOJson(this));
}
@Override
protected Class<PsseTransformerImpedanceCorrection> psseTypeClass() {
return PsseTransformerImpedanceCorrection.class;
}
/**
* For version 33, RAW format has a single-line record format with these fields:
* I, T1, F1, T2, F2, T3, F3, ... T11, F11
* A static inner class with exactly these fields is used as intermediate step for reading/writing the PSSE model
*/
private static class IOLegacyText33 extends RecordGroupIOLegacyText<PsseTransformerImpedanceCorrection> {
IOLegacyText33(AbstractRecordGroup<PsseTransformerImpedanceCorrection> recordGroup) {
super(recordGroup);
}
@Override
public List<PsseTransformerImpedanceCorrection> read(LegacyTextReader reader, Context context) throws IOException {
List<ZCorr33> list33 = new ZCorr33Data().read(reader, context);
return convertToImpedanceCorrectionList(list33);
}
@Override
public void write(List<PsseTransformerImpedanceCorrection> impedanceCorrectionList, Context context, OutputStream outputStream) {
writeBegin(outputStream);
ZCorr33Data recordData = new ZCorr33Data();
String[] headers = recordData.fieldNames(context.getVersion());
String[] quotedFields = recordData.quotedFields();
impedanceCorrectionList.forEach(impedanceCorrection -> {
ZCorr33 parser33 = convertToTable(impedanceCorrection);
// write only the read points. Each table can have different number of points
String[] writeHeaders = ArrayUtils.subarray(headers, 0, 1 + 2 * impedanceCorrection.getPoints().size());
String record = recordData.buildRecord(parser33, writeHeaders, quotedFields, context);
write(String.format("%s%n", record), outputStream);
});
writeEnd(outputStream);
}
private static List<PsseTransformerImpedanceCorrection> convertToImpedanceCorrectionList(List<ZCorr33> recordList) {
List<PsseTransformerImpedanceCorrection> impedanceCorrectionList = new ArrayList<>();
recordList.forEach(record -> impedanceCorrectionList.add(convertToList(record)));
return impedanceCorrectionList;
}
private static PsseTransformerImpedanceCorrection convertToList(ZCorr33 record) {
PsseTransformerImpedanceCorrection impedanceCorrection = new PsseTransformerImpedanceCorrection(record.getI());
List<Double> list = Arrays.asList(record.getT1(), record.getF1(), record.getT2(), record.getF2(), record.getT3(), record.getF3(),
record.getT4(), record.getF4(), record.getT5(), record.getF5(), record.getT6(), record.getF6(), record.getT7(), record.getF7(),
record.getT8(), record.getF8(), record.getT9(), record.getF9(), record.getT10(), record.getF10(), record.getT11(), record.getF11());
for (int i = 0; i < list.size(); i = i + 2) {
if (validPoint(list.get(i), list.get(i + 1))) {
impedanceCorrection.getPoints().add(new PsseTransformerImpedanceCorrectionPoint(list.get(i), list.get(i + 1)));
}
}
return impedanceCorrection;
}
private static boolean validPoint(double t, double f) {
return t != 0.0 && f != 0.0;
}
private static ZCorr33 convertToTable(PsseTransformerImpedanceCorrection impedanceCorrectionTable) {
ZCorr33 record = new ZCorr33();
record.setI(impedanceCorrectionTable.getI());
for (int i = 0; i < impedanceCorrectionTable.getPoints().size(); i++) {
record.setTF(i + 1, impedanceCorrectionTable.getPoints().get(i).getT(), impedanceCorrectionTable.getPoints().get(i).getF());
}
return record;
}
private static class ZCorr33Data extends AbstractRecordGroup<ZCorr33> {
ZCorr33Data() {
super(TRANSFORMER_IMPEDANCE_CORRECTION_TABLES, "i", "t1", "f1", "t2", "f2", "t3", "f3", "t4", "f4", "t5", "f5", "t6", "f6", "t7", "f7", "t8", "f8", "t9", "f9", "t10", "f10", "t11", "f11");
withQuotedFields();
}
@Override
protected Class<ZCorr33> psseTypeClass() {
return ZCorr33.class;
}
}
public static class ZCorr33 {
@Parsed
private int i;
@Parsed
private double t1 = 0.0;
@Parsed
private double f1 = 0.0;
@Parsed
private double t2 = 0.0;
@Parsed
private double f2 = 0.0;
@Parsed
private double t3 = 0.0;
@Parsed
private double f3 = 0.0;
@Parsed
private double t4 = 0.0;
@Parsed
private double f4 = 0.0;
@Parsed
private double t5 = 0.0;
@Parsed
private double f5 = 0.0;
@Parsed
private double t6 = 0.0;
@Parsed
private double f6 = 0.0;
@Parsed
private double t7 = 0.0;
@Parsed
private double f7 = 0.0;
@Parsed
private double t8 = 0.0;
@Parsed
private double f8 = 0.0;
@Parsed
private double t9 = 0.0;
@Parsed
private double f9 = 0.0;
@Parsed
private double t10 = 0.0;
@Parsed
private double f10 = 0.0;
@Parsed
private double t11 = 0.0;
@Parsed
private double f11 = 0.0;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
public double getT1() {
return t1;
}
public double getF1() {
return f1;
}
public double getT2() {
return t2;
}
public double getF2() {
return f2;
}
public double getT3() {
return t3;
}
public double getF3() {
return f3;
}
public double getT4() {
return t4;
}
public double getF4() {
return f4;
}
public double getT5() {
return t5;
}
public double getF5() {
return f5;
}
public double getT6() {
return t6;
}
public double getF6() {
return f6;
}
public double getT7() {
return t7;
}
public double getF7() {
return f7;
}
public double getT8() {
return t8;
}
public double getF8() {
return f8;
}
public double getT9() {
return t9;
}
public double getF9() {
return f9;
}
public double getT10() {
return t10;
}
public double getF10() {
return f10;
}
public double getT11() {
return t11;
}
public double getF11() {
return f11;
}
public void setTF(int point, double t, double f) {
switch (point) {
case 1:
this.t1 = t;
this.f1 = f;
break;
case 2:
this.t2 = t;
this.f2 = f;
break;
case 3:
this.t3 = t;
this.f3 = f;
break;
case 4:
this.t4 = t;
this.f4 = f;
break;
case 5:
this.t5 = t;
this.f5 = f;
break;
case 6:
this.t6 = t;
this.f6 = f;
break;
case 7:
this.t7 = t;
this.f7 = f;
break;
case 8:
this.t8 = t;
this.f8 = f;
break;
case 9:
this.t9 = t;
this.f9 = f;
break;
case 10:
this.t10 = t;
this.f10 = f;
break;
case 11:
this.t11 = t;
this.f11 = f;
break;
default:
throw new PsseException("Unexpected point " + point);
}
}
}
}
/**
* The RAW record format for Transformer Impedance Correction Tables:
* I, T1, Re(F1), Im(F1), T2, Re(F2), Im(F2), ... T6, Re(F6), Im(F6)
* T7, Re(F7), Im(F7), T8, Re(F8), Im(F8), ... T12, Re(F12), Im(F12)
* .
* .
* Tn, Re(Fn), Im(Fn), 0.0, 0.0, 0.0
*/
private static class IOLegacyText35 extends RecordGroupIOLegacyText<PsseTransformerImpedanceCorrection> {
private static final String[][] FIELD_NAMES = {
{"i", "t1", "ref1", "imf1", "t2", "ref2", "imf2", "t3", "ref3", "imf3", "t4", "ref4", "imf4", "t5", "ref5", "imf5", "t6", "ref6", "imf6"},
{"t1", "ref1", "imf1", "t2", "ref2", "imf2", "t3", "ref3", "imf3", "t4", "ref4", "imf4", "t5", "ref5", "imf5", "t6", "ref6", "imf6"},
};
private static final String[] QUOTED_FIELDS = {};
IOLegacyText35(AbstractRecordGroup<PsseTransformerImpedanceCorrection> recordGroup) {
super(recordGroup);
}
@Override
public List<PsseTransformerImpedanceCorrection> read(LegacyTextReader reader, Context context) throws IOException {
List<String> records = reader.readRecords();
ZCorr35FirstData record1Data = new ZCorr35FirstData();
ZCorr35PointsData record2Data = new ZCorr35PointsData();
List<PsseTransformerImpedanceCorrection> impedanceCorrectionList = new ArrayList<>();
int i = 0;
while (i < records.size()) {
ZCorr35First r1 = record1Data.parseSingleRecord(records.get(i++), FIELD_NAMES[0], context);
PsseTransformerImpedanceCorrection impedanceCorrection = new PsseTransformerImpedanceCorrection(r1.getI());
boolean endPoints = addImpedanceCorrectionPoints(impedanceCorrection, r1.getPoints());
while (i < records.size() && !endPoints) {
ZCorr35Points r2 = record2Data.parseSingleRecord(records.get(i++), FIELD_NAMES[1], context);
endPoints = addImpedanceCorrectionPoints(impedanceCorrection, r2);
}
if (!impedanceCorrection.getPoints().isEmpty()) {
impedanceCorrectionList.add(impedanceCorrection);
}
}
return impedanceCorrectionList;
}
private static boolean addImpedanceCorrectionPoints(PsseTransformerImpedanceCorrection impedanceCorrection,
ZCorr35Points record2) {
Objects.requireNonNull(record2);
List<Double> list = Arrays.asList(record2.getT1(), record2.getRef1(), record2.getImf1(), record2.getT2(), record2.getRef2(), record2.getImf2(),
record2.getT3(), record2.getRef3(), record2.getImf3(), record2.getT4(), record2.getRef4(), record2.getImf4(),
record2.getT5(), record2.getRef5(), record2.getImf5(), record2.getT6(), record2.getRef6(), record2.getImf6());
for (int i = 0; i < list.size(); i = i + 3) {
if (endPoint(list.get(i), list.get(i + 1), list.get(i + 2))) {
return true;
} else {
impedanceCorrection.getPoints().add(new PsseTransformerImpedanceCorrectionPoint(list.get(i), list.get(i + 1), list.get(i + 2)));
}
}
return false;
}
private static boolean endPoint(double t, double ref, double imf) {
return t == 0.0 && ref == 0.0 && imf == 0.0;
}
@Override
public void write(List<PsseTransformerImpedanceCorrection> impedanceCorrectionList, Context context, OutputStream outputStream) {
ZCorr35FirstData record1Data = new ZCorr35FirstData();
ZCorr35PointsData record2Data = new ZCorr35PointsData();
writeBegin(outputStream);
impedanceCorrectionList.forEach(impedanceCorrection -> {
int indexPoints = 0;
ZCorr35First r1 = convertToRecord1(impedanceCorrection, indexPoints);
String[] writeHeaders = ArrayUtils.subarray(FIELD_NAMES[0], 0, 1 + 3 * pointsInsideRecord(indexPoints, impedanceCorrection.getPoints().size()));
String record = record1Data.buildRecord(r1, writeHeaders, QUOTED_FIELDS, context);
write(String.format("%s%n", record), outputStream);
indexPoints = indexPoints + 6;
// A (0.0, 0.0, 0.0) point must be added at the end so <=
while (indexPoints <= impedanceCorrection.getPoints().size()) {
ZCorr35Points r2 = convertToRecord2(impedanceCorrection, indexPoints);
String[] writeHeadersPoints = ArrayUtils.subarray(FIELD_NAMES[1], 0, 3 * pointsInsideRecord(indexPoints, impedanceCorrection.getPoints().size()));
String recordPoints = record2Data.buildRecord(r2, writeHeadersPoints, QUOTED_FIELDS, context);
write(String.format("%s%n", recordPoints), outputStream);
indexPoints = indexPoints + 6;
}
});
writeEnd(outputStream);
}
private static int pointsInsideRecord(int indexPoints, int numPoints) {
int pendingPoints = numPoints - indexPoints;
if (pendingPoints >= 6) {
return 6;
} else {
return pendingPoints + 1;
}
}
private static ZCorr35First convertToRecord1(PsseTransformerImpedanceCorrection impedanceCorrection, int indexPoints) {
ZCorr35First record1 = new ZCorr35First();
record1.setI(impedanceCorrection.getI());
record1.setPoints(convertToRecord2(impedanceCorrection, indexPoints));
return record1;
}
private static ZCorr35Points convertToRecord2(PsseTransformerImpedanceCorrection impedanceCorrection, int indexPoints) {
ZCorr35Points record2 = new ZCorr35Points();
int pointNumber = 0;
int index = indexPoints;
while (index < impedanceCorrection.getPoints().size() && pointNumber < 6) {
pointNumber++;
PsseTransformerImpedanceCorrectionPoint point = impedanceCorrection.getPoints().get(index);
record2.setTF(pointNumber, point.getT(), point.getRef(), point.getImf());
index++;
}
if (pointNumber < 6) {
pointNumber++;
record2.setTF(pointNumber, 0.0, 0.0, 0.0);
}
return record2;
}
private static class ZCorr35FirstData extends AbstractRecordGroup<ZCorr35First> {
ZCorr35FirstData() {
super(TRANSFORMER_IMPEDANCE_CORRECTION_TABLES);
}
@Override
protected Class<ZCorr35First> psseTypeClass() {
return ZCorr35First.class;
}
}
private static class ZCorr35PointsData extends AbstractRecordGroup<ZCorr35Points> {
ZCorr35PointsData() {
super(TRANSFORMER_IMPEDANCE_CORRECTION_TABLES);
}
@Override
protected Class<ZCorr35Points> psseTypeClass() {
return ZCorr35Points.class;
}
}
public static class ZCorr35First {
@Parsed
private int i;
@Nested
private ZCorr35Points points;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
public ZCorr35Points getPoints() {
return points;
}
public void setPoints(ZCorr35Points points) {
this.points = points;
}
}
public static class ZCorr35Points {
@Parsed
private double t1 = 0.0;
@Parsed
private double ref1 = 0.0;
@Parsed
private double imf1 = 0.0;
@Parsed
private double t2 = 0.0;
@Parsed
private double ref2 = 0.0;
@Parsed
private double imf2 = 0.0;
@Parsed
private double t3 = 0.0;
@Parsed
private double ref3 = 0.0;
@Parsed
private double imf3 = 0.0;
@Parsed
private double t4 = 0.0;
@Parsed
private double ref4 = 0.0;
@Parsed
private double imf4 = 0.0;
@Parsed
private double t5 = 0.0;
@Parsed
private double ref5 = 0.0;
@Parsed
private double imf5 = 0.0;
@Parsed
private double t6 = 0.0;
@Parsed
private double ref6 = 0.0;
@Parsed
private double imf6 = 0.0;
public double getT1() {
return t1;
}
public double getRef1() {
return ref1;
}
public double getImf1() {
return imf1;
}
public double getT2() {
return t2;
}
public double getRef2() {
return ref2;
}
public double getImf2() {
return imf2;
}
public double getT3() {
return t3;
}
public double getRef3() {
return ref3;
}
public double getImf3() {
return imf3;
}
public double getT4() {
return t4;
}
public double getRef4() {
return ref4;
}
public double getImf4() {
return imf4;
}
public double getT5() {
return t5;
}
public double getRef5() {
return ref5;
}
public double getImf5() {
return imf5;
}
public double getT6() {
return t6;
}
public double getRef6() {
return ref6;
}
public double getImf6() {
return imf6;
}
public void setTF(int point, double t, double ref, double imf) {
switch (point) {
case 1:
this.t1 = t;
this.ref1 = ref;
this.imf1 = imf;
break;
case 2:
this.t2 = t;
this.ref2 = ref;
this.imf2 = imf;
break;
case 3:
this.t3 = t;
this.ref3 = ref;
this.imf3 = imf;
break;
case 4:
this.t4 = t;
this.ref4 = ref;
this.imf4 = imf;
break;
case 5:
this.t5 = t;
this.ref5 = ref;
this.imf5 = imf;
break;
case 6:
this.t6 = t;
this.ref6 = ref;
this.imf6 = imf;
break;
default:
throw new PsseException("Unexpected point " + point);
}
}
}
public static class ZCorr35X {
public ZCorr35X() {
}
public ZCorr35X(int itable, double tap, double refact, double imfact) {
this.itable = itable;
this.tap = tap;
this.refact = refact;
this.imfact = imfact;
}
@Parsed
private int itable;
@Parsed
private double tap;
@Parsed
private double refact;
@Parsed
private double imfact;
public int getItable() {
return itable;
}
public double getTap() {
return tap;
}
public double getRefact() {
return refact;
}
public double getImfact() {
return imfact;
}
}
}
private static class IOJson extends RecordGroupIOJson<PsseTransformerImpedanceCorrection> {
IOJson(AbstractRecordGroup<PsseTransformerImpedanceCorrection> recordGroup) {
super(recordGroup);
}
@Override
public List<PsseTransformerImpedanceCorrection> read(LegacyTextReader reader, Context context) throws IOException {
if (reader != null) {
throw new PsseException("Unexpected reader. Should be null");
}
List<IOLegacyText35.ZCorr35X> parserRecords = new PsseTransformerImpedanceCorrection35xParserRecordData().read(null, context);
List<PsseTransformerImpedanceCorrection> records = new ArrayList<>();
parserRecords.forEach(parserRecord -> convertToImpedanceCorrection(records, parserRecord));
return records;
}
private static void convertToImpedanceCorrection(List<PsseTransformerImpedanceCorrection> impedanceCorrectionList, IOLegacyText35.ZCorr35X parserRecord) {
if (impedanceCorrectionList.isEmpty()) {
PsseTransformerImpedanceCorrection impedanceCorrection = new PsseTransformerImpedanceCorrection(parserRecord.getItable());
impedanceCorrection.getPoints().add(new PsseTransformerImpedanceCorrectionPoint(parserRecord.getTap(), parserRecord.getRefact(), parserRecord.getImfact()));
impedanceCorrectionList.add(impedanceCorrection);
} else {
PsseTransformerImpedanceCorrection lastImpedanceCorrection = impedanceCorrectionList.get(impedanceCorrectionList.size() - 1);
if (lastImpedanceCorrection.getI() == parserRecord.getItable()) {
lastImpedanceCorrection.getPoints().add(new PsseTransformerImpedanceCorrectionPoint(parserRecord.getTap(), parserRecord.getRefact(), parserRecord.getImfact()));
} else {
PsseTransformerImpedanceCorrection impedanceCorrection = new PsseTransformerImpedanceCorrection(parserRecord.getItable());
impedanceCorrection.getPoints().add(new PsseTransformerImpedanceCorrectionPoint(parserRecord.getTap(), parserRecord.getRefact(), parserRecord.getImfact()));
impedanceCorrectionList.add(impedanceCorrection);
}
}
}
@Override
public void write(List<PsseTransformerImpedanceCorrection> impedanceCorrectionList, Context context, OutputStream outputStream) {
if (outputStream != null) {
throw new PsseException("Unexpected outputStream. Should be null");
}
List<IOLegacyText35.ZCorr35X> parserList = convertToParserList(impedanceCorrectionList);
new PsseTransformerImpedanceCorrection35xParserRecordData().write(parserList, context, null);
}
private static List<IOLegacyText35.ZCorr35X> convertToParserList(List<PsseTransformerImpedanceCorrection> impedanceCorrectionList) {
List<IOLegacyText35.ZCorr35X> parserList = new ArrayList<>();
impedanceCorrectionList.forEach(impedanceCorrection -> impedanceCorrection.getPoints().forEach(point -> {
IOLegacyText35.ZCorr35X parserRecord = new IOLegacyText35.ZCorr35X(
impedanceCorrection.getI(), point.getT(), point.getRef(), point.getImf());
parserList.add(parserRecord);
}));
return parserList;
}
private static class PsseTransformerImpedanceCorrection35xParserRecordData extends AbstractRecordGroup<IOLegacyText35.ZCorr35X> {
PsseTransformerImpedanceCorrection35xParserRecordData() {
super(TRANSFORMER_IMPEDANCE_CORRECTION_TABLES);
withQuotedFields();
}
@Override
protected Class<IOLegacyText35.ZCorr35X> psseTypeClass() {
return IOLegacyText35.ZCorr35X.class;
}
}
}
}