package org.ieee.odm.adapter.opf.matpower;
import java.util.ArrayList;
import java.util.StringTokenizer;
import org.ieee.odm.adapter.AbstractODMAdapter;
import org.ieee.odm.adapter.IODMAdapter;
import org.ieee.odm.common.IFileReader;
import org.ieee.odm.common.ODMException;
import org.ieee.odm.common.ODMLogger;
import org.ieee.odm.model.IODMModelParser;
import org.ieee.odm.model.aclf.AclfDataSetter;
import org.ieee.odm.model.aclf.AclfParserHelper;
import org.ieee.odm.model.base.BaseDataSetter;
import org.ieee.odm.model.opf.OpfDataSetter;
import org.ieee.odm.model.opf.OpfModelParser;
import org.ieee.odm.schema.ActivePowerLimitXmlType;
import org.ieee.odm.schema.ActivePowerPriceEnumType;
import org.ieee.odm.schema.ActivePowerRatingXmlType;
import org.ieee.odm.schema.ActivePowerUnitType;
import org.ieee.odm.schema.AngleUnitType;
import org.ieee.odm.schema.ApparentPowerUnitType;
import org.ieee.odm.schema.ConstraintsXmlType;
import org.ieee.odm.schema.CostModelEnumType;
import org.ieee.odm.schema.IncCostXmlType;
import org.ieee.odm.schema.LFGenCodeEnumType;
import org.ieee.odm.schema.LFLoadCodeEnumType;
import org.ieee.odm.schema.LoadflowBusXmlType;
import org.ieee.odm.schema.LoadflowGenDataXmlType;
import org.ieee.odm.schema.LoadflowNetXmlType;
import org.ieee.odm.schema.ObjectFactory;
import org.ieee.odm.schema.OpfBranchXmlType;
import org.ieee.odm.schema.OpfGenBusXmlType;
import org.ieee.odm.schema.OpfGenOperatingModeEnumType;
import org.ieee.odm.schema.OpfNetworkXmlType;
import org.ieee.odm.schema.OriginalDataFormatEnumType;
import org.ieee.odm.schema.VoltageUnitType;
import org.ieee.odm.schema.YUnitType;
import org.ieee.odm.schema.ZUnitType;
public class OpfMatpowerAdapter extends AbstractODMAdapter {
private static final int BusData = 1;
private static final int BranchData = 2;
private static final int GencostData = 3;
private static final int AreaData = 4;
private static final int GenData = 5;
private ArrayList<OpfGenBusXmlType> opfGenContainer = null;
private ObjectFactory factory = null;
public OpfMatpowerAdapter() {
super();
this.factory = new ObjectFactory();
this.opfGenContainer = new ArrayList<OpfGenBusXmlType>();
}
@Override
protected OpfModelParser parseInputFile(final IFileReader din,
String encoding) throws ODMException {
OpfModelParser parser = new OpfModelParser(encoding);
parser.getStudyCase().setId("ODM_OPF_Studycase");
parser.setOPFTransInfo(OriginalDataFormatEnumType.OPF_MATPOWER);
OpfNetworkXmlType baseCaseNet = parser.getOpfNetwork();
String str = din.readLine();
processTitleData(str, baseCaseNet);
int dataType = 0;
int gencnt = 0;
// Matpower does not specify cirId for parallel lines
// Here cirId is used for this purpose
//int cirId = 1;
do {
str = din.readLine(); // kvaBase
if (str != null) {
try {
// process the data
if (str.startsWith("]")) {
dataType = 0;
} else if (str.startsWith("%")) {
// comment line, do nothing but go to the next line;
} else if (str.startsWith("mpc.baseMVA")) {
processBaseMVAData(str, baseCaseNet);
} else if (str.startsWith("mpc.version")) {
// processBusData(str, parser);
} else if (dataType == BusData) {
processBusData(str, parser);
} else if (dataType == GenData) {
processGenData(str, parser);
} else if (dataType == BranchData) {
processBranchData(str, /*cirId++,*/ parser);
} else if (dataType == AreaData) {
// TODO: Not implemented yet.
// processAreaData(str, parser);
} else if (dataType == GencostData) {
int sizeGen = opfGenContainer.size();
if (gencnt < sizeGen) {
processGencostData(str, gencnt);
gencnt++;
} else
dataType = 0;
} else if (str.startsWith("mpc.bus")) {
dataType = BusData;
ODMLogger.getLogger().fine("load bus data");
} else if (str.trim().split("=")[0].trim().equals(
("mpc.gen"))) {
dataType = GenData;
ODMLogger.getLogger().fine("load branch data");
} else if (str.startsWith("mpc.branch")) {
dataType = BranchData;
// baseCaseNet.addNewLossZoneList();
ODMLogger.getLogger().fine("load loss zone data");
} else if (str.startsWith("mpc.area")) {
dataType = AreaData;
// baseCaseNet.addNewInterchangeList();
ODMLogger.getLogger().fine("load interchange data");
} else if (str.trim().split("=")[0].trim().equals(
("mpc.gencost"))) {
dataType = GencostData;
// baseCaseNet.addNewTieLineList();
ODMLogger.getLogger().fine("load tieline data");
}
} catch (final Exception e) {
ODMLogger.getLogger().severe(e.toString() + "\n" + str);
e.printStackTrace();
}
}
} while (str != null);
return parser;
}
protected IODMModelParser parseInputFile(IODMAdapter.NetType type,
final IFileReader[] din, String encoding) throws ODMException {
throw new ODMException("not implemented yet");
}
private void processTitleData(String str,
final LoadflowNetXmlType baseCaseNet) {
str = str.replace(';', ' ');
final StringTokenizer st = new StringTokenizer(str, " ");
st.nextToken(); // function
st.nextToken(); // mpc
st.nextToken(); // =
final String id = st.nextToken().toString();
ODMLogger.getLogger().fine("fileName: " + id);
baseCaseNet.setId("Opf_from_Matpower_" + id);
}
private void processBaseMVAData(String str,
final LoadflowNetXmlType baseCaseNet) {
str = str.replace(';', ' ');
final StringTokenizer st = new StringTokenizer(str, " ");
st.nextToken(); // mpc.baseMVA
st.nextToken(); // =
final String basemva = st.nextToken().toString();
double baseMva = str2d(basemva);
ODMLogger.getLogger().fine("baseMva: " + baseMva);
baseCaseNet.setBasePower(BaseDataSetter.createPowerMvaValue(baseMva));
}
private void processBusData(final String str, OpfModelParser parser) {
// parse the input data line
final String[] s = getBusDataFields(str);
final String busId = IODMModelParser.BusIdPreFix + s[0];
final int type = str2i(s[1]);
final double pl = str2d(s[2]);
final double ql = str2d(s[3]);
final double pshunt = str2d(s[4]);
final double qshunt = str2d(s[5]);
final int area = str2i(s[6]);
final double vm = str2d(s[7]);
final double va = str2d(s[8]);
final double baseKv = str2d(s[9]);
final int zone = str2i(s[10]);
final double vmax = str2d(s[11]);
final double vmin = str2d(s[12]);
LoadflowBusXmlType aclfBus = null;
// OpfGenBusXmlType opfGenBus = null;
try {
if (type == 2 || type == 3) {
OpfGenBusXmlType opfGenBus = parser.createOpfGenBus(busId);
aclfBus = (LoadflowBusXmlType) opfGenBus;
opfGenBus
.setOperatingMode(OpfGenOperatingModeEnumType.PV_GENERATOR);
} else {
aclfBus = parser.createBus(busId);
}
} catch (Exception e) {
this.logErr(e.toString());
return;
}
ODMLogger.getLogger().fine("Bus data loaded, id: " + busId);
aclfBus.setNumber(new Long(s[0]));
final String busName = busId;
aclfBus.setName(busName);
aclfBus.setAreaNumber(area);
aclfBus.setZoneNumber(zone);
aclfBus.setBaseVoltage(BaseDataSetter.createVoltageValue(baseKv,
VoltageUnitType.KV));
aclfBus.setVoltage(BaseDataSetter.createVoltageValue(vm,
VoltageUnitType.PU));
aclfBus.setAngle(BaseDataSetter.createAngleValue(va, AngleUnitType.DEG));
if (pl != 0.0 || ql != 0.0) {
AclfDataSetter.setLoadData(aclfBus, LFLoadCodeEnumType.CONST_P, pl,
ql, ApparentPowerUnitType.MVA);
}
// 1 - PQ; 2 - pv; 3 - swing; 4 - isolated
LFGenCodeEnumType genType = type == 3 ? LFGenCodeEnumType.SWING
: (type == 2 ? LFGenCodeEnumType.PV
: (type == 1 ? LFGenCodeEnumType.PQ
: LFGenCodeEnumType.OFF));
if (type == 2 || type == 3) {
AclfDataSetter.setGenData(aclfBus, genType, vm, VoltageUnitType.PU,
0, 0, ApparentPowerUnitType.MVA);
}
double baseKva = parser.getBaseOpfNet().getBasePower().getValue() / 1000;
if (pshunt != 0.0 || qshunt != 0.0) {
aclfBus.getShuntYData().setEquivY(BaseDataSetter.createYValue(pshunt / baseKva,
qshunt / baseKva, YUnitType.PU));
}
}
private void processGenData(final String str, OpfModelParser parser) {
// parse the input data line
final String[] s = getGenDataFields(str);
final String id = s[0];
final String busId = IODMModelParser.BusIdPreFix + id;
OpfGenBusXmlType bus = (OpfGenBusXmlType) parser.getBus(busId);
opfGenContainer.add(bus);
double pg = str2d(s[1]);
double qg = str2d(s[2]);
LoadflowGenDataXmlType defaultGen = AclfParserHelper.getDefaultGen(bus.getGenData());
defaultGen.setPower(BaseDataSetter.createPowerValue(pg, qg,
ApparentPowerUnitType.MVA));
int status = str2i(s[7]);
if (status > 0) {
defaultGen.setOffLine(false);
} else {
defaultGen.setOffLine(true);
}
double pgmax = str2d(s[8]);
double pgmin = str2d(s[9]);
ActivePowerLimitXmlType plimit = BaseDataSetter.createActivePowerLimit(
pgmax, pgmin, ActivePowerUnitType.MW);
ConstraintsXmlType constraint = new ConstraintsXmlType();
constraint.setActivePowerLimit(plimit);
bus.setConstraints(constraint);
}
private void processBranchData(final String str, /*int cirId,*/ OpfModelParser parser) {
// parse the input data line
final String[] s = getBranchDataFields(str);
final String fid = IODMModelParser.BusIdPreFix + s[0];
final String tid = IODMModelParser.BusIdPreFix + s[1];
OpfBranchXmlType opfBra = null;
try {
// MapPower does not have branch cirId defined. It will be auto set in the
// branch creation process
opfBra = parser.createOpfBranch(fid, tid);
} catch (Exception e) {
this.logErr("branch data error, " + e.toString());
}
double r = str2d(s[2]);
double z = str2d(s[3]);
AclfDataSetter.setLineData(opfBra, r, z, ZUnitType.PU, 0.0, 0,
YUnitType.PU);
double rating1Mvar = 0.0, rating2Mvar = 0.0, rating3Mvar = 0.0;
if (!s[5].trim().equals(""))
rating1Mvar = new Integer(s[5]).intValue();
if (!s[6].trim().equals(""))
rating2Mvar = new Integer(s[6]).intValue();
if (!s[7].trim().equals(""))
rating3Mvar = new Integer(s[7]).intValue();
opfBra.setRatingLimit(this.factory.createBranchRatingLimitXmlType());
ActivePowerRatingXmlType rating = new ActivePowerRatingXmlType();
rating.setRating1(rating1Mvar);
rating.setRating2(rating2Mvar);
rating.setRating3(rating3Mvar);
rating.setUnit(ActivePowerUnitType.MW);
opfBra.getRatingLimit().setMw(rating);
}
private void processGencostData(final String str, int gencnt) {
final String[] s = getGencostDataFields(str);
int type = str2i(s[0]);
OpfGenBusXmlType bus = opfGenContainer.get(gencnt);
IncCostXmlType incCost = new IncCostXmlType();
int np = str2i(s[3]);
if (type == 2) {
if (np > 3) {
ODMLogger
.getLogger()
.severe("Polynomial gen cost function with order higher than 2 is not supported!");
return;
}
incCost.setCostModel(CostModelEnumType.QUADRATIC_MODEL);
double[] point = new double[np];
int startIdx = 4;
for (int i = 0; i < np; i++) {
point[i] = str2d(s[startIdx++]);
}
OpfDataSetter.setQuadraticModel(incCost, point[0],
ActivePowerPriceEnumType.DOLLAR_PER_MW_SQUARE, point[1],
ActivePowerPriceEnumType.DOLLAR_PER_MW, point[2]);
} else {
incCost.setCostModel(CostModelEnumType.PIECE_WISE_LINEAR_MODEL);
double[] point = new double[np * 2];
int startIdx = 4;
for (int i = 0; i < 2 * np; i++) {
point[i] = str2d(s[startIdx++]);
}
OpfDataSetter.setPWModel(incCost, point);
}
bus.setIncCost(incCost);
}
/*
* private void processVersionData( String str, final AclfModelParser
* parser) { str = str.replace(';', ' '); final StringTokenizer st = new
* StringTokenizer(str); st.nextToken(); // mpc.version st.nextToken(); // =
* //st.nextToken(); // = final String versionNum =
* st.nextToken().toString(); // '2' final StringTokenizer st1 = new
* StringTokenizer(versionNum, " "); String version = st1.nextToken();
* ODMLogger.getLogger().fine("Matpower version: " + version );
*
* }
*/
private String[] getBusDataFields(String str) {
str = str.replace(';', ' ');
final String[] strAry = new String[17];
final StringTokenizer st = new StringTokenizer(str);
int cnt = 0;
while (st.hasMoreTokens()) {
strAry[cnt++] = st.nextToken().trim();
}
return strAry;
}
private String[] getGenDataFields(String str) {
str = str.replace(';', ' ');
final String[] strAry = new String[25];
final StringTokenizer st = new StringTokenizer(str);
int cnt = 0;
while (st.hasMoreTokens()) {
strAry[cnt++] = st.nextToken().trim();
}
return strAry;
}
private String[] getBranchDataFields(String str) {
str = str.replace(';', ' ');
final String[] strAry = new String[21];
final StringTokenizer st = new StringTokenizer(str);
int cnt = 0;
while (st.hasMoreTokens()) {
strAry[cnt++] = st.nextToken().trim();
}
return strAry;
}
private String[] getGencostDataFields(String str) {
str = str.replace(';', ' ');
final StringTokenizer st = new StringTokenizer(str);
int size = st.countTokens();
final String[] strAry = new String[size];
int cnt = 0;
while (st.hasMoreTokens()) {
strAry[cnt++] = st.nextToken().trim();
}
return strAry;
}
private double str2d(String str) {
double d = new Double(str).doubleValue();
return d;
}
private int str2i(String str) {
int d = new Integer(str).intValue();
return d;
}
}