package org.ieee.odm.adapter.pwd.impl; import org.ieee.odm.adapter.pwd.InputLineStringParser; import org.ieee.odm.common.ODMException; import org.ieee.odm.common.ODMLogger; import org.ieee.odm.model.AbstractModelParser; import org.ieee.odm.model.IODMModelParser; import org.ieee.odm.model.aclf.AclfDataSetter; import org.ieee.odm.model.aclf.AclfModelParser; import org.ieee.odm.model.aclf.AclfParserHelper; import org.ieee.odm.model.base.BaseDataSetter; import org.ieee.odm.model.base.BaseJaxbHelper; import org.ieee.odm.schema.ActivePowerUnitType; import org.ieee.odm.schema.AngleUnitType; import org.ieee.odm.schema.AngleXmlType; import org.ieee.odm.schema.ApparentPowerUnitType; 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.ReactivePowerUnitType; import org.ieee.odm.schema.SwitchedShuntModeEnumType; import org.ieee.odm.schema.SwitchedShuntXmlType; import org.ieee.odm.schema.VoltageUnitType; import org.ieee.odm.schema.YUnitType; /** * Bus data processor for PowerWorld-TO-ODM Adapter based on power world v16 data definition * This processor processes the bus basic data, e.g. busNum, baseVolt, as well as bus load and * generation data. These data are defined in PWD separately, hence, processed separately in this processor. * * @version 0.2 01/08/2013 * @author * */ public class BusDataProcessor extends InputLineStringParser { public static long swingBusNum=-1; private boolean isSubDataSection=false; private String STATION_TOKEN ="SubStation"; private AclfModelParser parser = null; public BusDataProcessor(AclfModelParser parser) { this.parser = parser; } public void processBusBasicData(String busDataStr){ /* * DATA (BUS, [BusNum,BusName,BusNomVolt,BusPUVolt,BusAngle,BusG:1,BusB:1,AreaNum,ZoneNum, SubNum,BusSlack]) */ long busNum=-1; int areaNum=-1,zoneNum=-1,ownerNum=-1;// purposely set to -1, a not real number; String busName="",busId="",substation=""; double basekV=0, puVolt=0,kvVolt=0,angle=-360,busG=0,busB=0; boolean isSlackBus=false,busConnected=true; //first, parse the data and set it to the internal Hashtable parseData(busDataStr); try { busNum=getLong("BusNum"); busName=exist("BusName")?getString("BusName"):""; if(exist("BusStatus")){ busConnected=(getString("BusStatus").equalsIgnoreCase("Connected")||getString("BusStatus").equalsIgnoreCase("Closed"))?true:false; } if(exist("BusNomVolt")){ basekV=getDouble("BusNomVolt"); } if(exist("BusPUVolt")){ puVolt=getDouble("BusPUVolt"); } if(exist("BusKVVolt")){ kvVolt=getDouble("BusKVVolt"); } if(exist("BusAngle")){ angle=getDouble("BusAngle"); } busG=exist("BusG:1")?getDouble("BusG:1"):0; busB=exist("BusB:1")?getDouble("BusB:1"):0; if(exist("AreaNum")){ areaNum=getInt("AreaNum"); } if(exist("ZoneNum")){ zoneNum=getInt("ZoneNum"); } if(exist("OwnerNum")){ ownerNum=getInt("OwnerNum"); } if(exist("BusSlack")){ isSlackBus=getString("BusSlack").equalsIgnoreCase("YES") ?isSlackBus=true:false; } else throw new ODMException("No slack bus information is provided " + "in the input data!"); if(busNum==-1) ODMLogger.getLogger().severe("bus Num is not defined yet!"); busId=IODMModelParser.BusIdPreFix+busNum; LoadflowBusXmlType bus=parser.createBus(busId); bus.setId(busId); bus.setNumber(busNum); bus.setOffLine(!busConnected); if(!busName.equals("")) bus.setName(busName); if(areaNum!=-1)bus.setAreaNumber(areaNum); if(zoneNum!=-1)bus.setZoneNumber(zoneNum); //if(ownerNum!=-1)bus.getOwnerList().add(new OwnerXmlType());//setOwnerNumber(ownerNum); bus.setBaseVoltage(BaseDataSetter.createVoltageValue(basekV, VoltageUnitType.KV)); if(puVolt==0&&kvVolt!=0){ puVolt=kvVolt/basekV; } bus.setVoltage(BaseDataSetter.createVoltageValue(puVolt, VoltageUnitType.PU)); if(angle!=-360)bus.setAngle(BaseDataSetter.createAngleValue(angle,AngleUnitType.DEG)); if (busG != 0.0 || busB != 0.0) { bus.getShuntYData().setEquivY(BaseDataSetter.createYValue(busG, busB,YUnitType.MVAR)); } if(isSlackBus){ swingBusNum=busNum; //System.out.println ("==>Swing Bus number:"+swingBusNum); } //bus substation name //assume busName is created by following the convention: substationName_baseKV_busId substation = getBusSubstationName(busName); if(!substation.equals("")){ BaseJaxbHelper.addNVPair(bus, STATION_TOKEN, substation); } } catch (ODMException e) { e.printStackTrace(); } } public void processBusLoadData(String busLoadDataStr){ /* * DATA (LOAD, [BusNum,LoadID,LoadStatus,LoadSMW,LoadSMVR,LoadIMW,LoadIMVR,LoadZMW,LoadZMVR, AreaNum,ZoneNum]) */ long busNum=-1; String busId="",loadId=""; double loadSMVR=0,loadSMW=0,loadIMVR=0,loadIMW=0,loadZMVR=0,loadZMW=0; int areaNum=-1,zoneNum=-1; boolean loadOnLine=false; String CustomStrToken="CustomString"; String customString =""; parseData(busLoadDataStr); try { busNum=getLong("BusNum"); //mandatory filed if(exist("LoadID")) loadId=getString("LoadID"); if(exist("LoadStatus")) loadOnLine=getString("LoadStatus").equalsIgnoreCase("Closed")?true:false; loadSMW = exist("LoadSMW")?getDouble("LoadSMW"):0; loadSMVR = exist("LoadSMVR")?getDouble("LoadSMVR"):0; loadIMW = exist("LoadIMW")?getDouble("LoadIMW"):0; loadIMVR = exist("LoadIMVR")?getDouble("LoadIMVR"):0; loadZMW = exist("LoadZMW")?getDouble("LoadZMW"):0; loadZMVR = exist("LoadZMVR")?getDouble("LoadZMVR"):0; areaNum = exist("AreaNum")?getInt("AreaNum"):0; zoneNum = exist("ZoneNum")?getInt("ZoneNum"):0; //process custom string, this is for specifically customized data if(exist(CustomStrToken)) { customString = getString(CustomStrToken); } } catch (ODMException e) { e.printStackTrace(); } busId=IODMModelParser.BusIdPreFix+busNum; LoadflowBusXmlType bus=parser.getBus(busId); // END OF DATA PROCESSING ,BEGIN DATA SETTING //TODO 04/03/2013 //Some of original load is actually ZERO, we can set it as it is in the data //if(loadSMW!=0||loadSMVR!=0){ if(loadIMW!=0||loadIMVR!=0||loadZMW!=0||loadZMVR!=0){ AclfDataSetter.setZIPLoadData(bus, loadSMW, loadSMVR, loadIMW, loadIMVR, loadZMW, loadZMVR, ApparentPowerUnitType.MVA); }else{ AclfDataSetter.setLoadData(bus, LFLoadCodeEnumType.CONST_P, loadSMW, loadSMVR, ApparentPowerUnitType.MVA); } //} if(!customString.equals("")) BaseJaxbHelper.addNVPair(bus, "Load_"+CustomStrToken, customString); //TODO constI, constZ part of load is not processed. } public void processBusGenData(String busGenDataStr){ /* * DATA (GEN, [BusNum,GenID,GenStatus,GenMW,GenMVR,GenAGCAble,GenEnforceMWLimits,GenMWMin, GenMWMax,GenParFac,GenAVRAble,GenVoltSet,GenRegNum,GenMVRMin,GenMVRMax, GenRMPCT,GenUseCapCurve,GenUseLDCRCC,GenXLDCRCC,GenMVABase,GenZR,GenZX, GenStepR,GenStepX,GenStepTap,AreaNum,ZoneNum]) */ long busNum=-1,regBusNum=-1; int areaNum=-1,zoneNum=-1; String genId=""; double genVoltSet=0; double genMW=0,genMVR=0,genMWMin=0,genMWMax=0,genMVRMin=-9999,genMVRMax=9999,genMVABase=100; boolean genOnLine=false; boolean pLimitForced=true; double partFactor = 0.0; boolean genAGCAble = false; String customString="", //extended name, e.g., "Sub1_14.9_G1" customString_1 ="", //unique equipment name, e.g., "G1" customString_2 =""; String substation =""; //substring before the underscore of customString if(busGenDataStr.trim().startsWith("<SUBDATA")){ isSubDataSection=true; return; } else if(busGenDataStr.trim().startsWith("</SUBDATA>")){ isSubDataSection=false; return; } /* * skips SubData, since they are not used in load flow analysis; */ if (!isSubDataSection) {// if there is no subData or subData ends parseData(busGenDataStr); try { busNum=getLong("BusNum");// mandatory filed genId =exist("GenID")?getString("GenID"):""; if (exist("GenStatus")) genOnLine =getString("GenStatus").equalsIgnoreCase("Closed")?true:false; if (exist("GenMW")) genMW =getDouble("GenMW"); if(exist("GenEnforceMWLimits")) pLimitForced= getString("GenEnforceMWLimits").equalsIgnoreCase("YES")? true:false; if(exist("GenRegNum")) regBusNum =getInt("GenRegNum"); genMVR =getDouble("GenMVR"); if(exist("GenMWMin")) genMWMin = getDouble("GenMWMin"); if (exist("GenMWMax")) genMWMax =getDouble("GenMWMax"); if (exist("GenMVRMin")) genMVRMin = getDouble("GenMVRMin"); if (exist("GenMVRMax")) genMVRMax = getDouble("GenMVRMax"); if (exist("GenMVABase")) genMVABase =getDouble("GenMVABase"); if (exist("AreaNum")) areaNum = getInt("AreaNum"); if (exist("ZoneNum")) zoneNum = getInt("ZoneNum"); if(exist("GenVoltSet")) genVoltSet=getDouble("GenVoltSet"); if(exist("GenAGCAble")) genAGCAble=getString("GenAGCAble").toLowerCase().equals("yes"); if(exist("GenParFac")) partFactor= getDouble("GenParFac"); //process custom string, this is for specifically customized data if(exist("CustomString")) { customString = getString("CustomString"); } if(exist("CustomString:1")) customString_1 = getString("CustomString:1"); if(exist("CustomString:2")) customString_2 = getString("CustomString:2"); int underScoreIdx = customString.indexOf("_"); if(underScoreIdx>0 && !customString_1.isEmpty() ) substation =getGenSubstationName(customString,customString_1); } catch (ODMException e) { e.printStackTrace(); } String busId = IODMModelParser.BusIdPreFix + busNum; LoadflowBusXmlType bus = parser.getBus(busId); //save custom string as NV pairs if(!substation.equals(""))BaseJaxbHelper.addNVPair(bus, STATION_TOKEN, substation); if(!customString.equals(""))BaseJaxbHelper.addNVPair(bus, "Gen_CustomString", customString); if(!customString_1.equals(""))BaseJaxbHelper.addNVPair(bus, "Gen_CustomString:1", customString_1); if(!customString_2.equals(""))BaseJaxbHelper.addNVPair(bus, "Gen_CustomString:2", customString_2); if (regBusNum != -1) { // this generator control the bus it connects to //generator regulates itself by default when regBusNum==0 if (regBusNum == busNum||regBusNum==0) { if (busNum != swingBusNum) {// This bus is a PV bus AclfDataSetter.setGenData(bus, LFGenCodeEnumType.PV, genVoltSet, VoltageUnitType.PU, genMW, genMVR, ApparentPowerUnitType.MVA); LoadflowGenDataXmlType defaultGen = AclfParserHelper.getDefaultGen(bus.getGenData()); defaultGen.setId(genId); defaultGen.setOffLine(!genOnLine); // equivGen.setRatedPower(BaseDataSetter.createApparentPower(genMVABase, // ApparentPowerUnitType.MVA)); defaultGen.setPLimit(BaseDataSetter .createActivePowerLimit(genMWMax, genMWMin, ActivePowerUnitType.MW)); defaultGen.getPLimit().setActive(pLimitForced); defaultGen.setQLimit(BaseDataSetter .createReactivePowerLimit(genMVRMax, genMVRMin, ReactivePowerUnitType.MVAR)); if (areaNum != -1) defaultGen.setAreaNumber(areaNum); if (zoneNum != -1) defaultGen.setZoneNumber(zoneNum); } else { // swing bus //VoltageXmlType v = bus.getVoltage(); AngleXmlType angle = bus.getAngle(); AclfDataSetter.setGenData(bus, LFGenCodeEnumType.SWING, genVoltSet, VoltageUnitType.PU, genMW, genMVR, ApparentPowerUnitType.MVA); LoadflowGenDataXmlType defaultGen = AclfParserHelper.getDefaultGen(bus.getGenData()); defaultGen.setId(genId); defaultGen.setMvaBase(BaseDataSetter.createPowerMvaValue(genMVABase)); defaultGen.setOffLine(!genOnLine); // p limit defaultGen.setPLimit(BaseDataSetter .createActivePowerLimit(genMWMax, genMWMin, ActivePowerUnitType.MW)); defaultGen.getPLimit().setActive(pLimitForced); // q limit defaultGen.setQLimit(BaseDataSetter .createReactivePowerLimit(genMVRMax, genMVRMin, ReactivePowerUnitType.MVAR)); if (areaNum != -1) defaultGen.setAreaNumber(areaNum); if (zoneNum != -1) defaultGen.setZoneNumber(zoneNum); } } else {// the regulated bus is a remote bus //Define a remote bus that a generator controls/regulates, as a PV // And this gen bus is a PV bus itself // set remote bus data String regBusId = IODMModelParser.BusIdPreFix + regBusNum; // set this gen bus data AclfDataSetter.setGenData(bus, LFGenCodeEnumType.PV, genVoltSet, VoltageUnitType.PU, genMW, genMVR, ApparentPowerUnitType.MVA); LoadflowGenDataXmlType defaultGen = AclfParserHelper.getDefaultGen(bus.getGenData()); defaultGen.setId(genId); defaultGen.setMvaBase(BaseDataSetter.createPowerMvaValue(genMVABase)); defaultGen.setPLimit(BaseDataSetter.createActivePowerLimit( genMWMax, genMWMin, ActivePowerUnitType.MW)); defaultGen.getPLimit().setActive(pLimitForced); defaultGen.setQLimit(BaseDataSetter.createReactivePowerLimit( genMVRMax, genMVRMin, ReactivePowerUnitType.MVAR)); if (areaNum != -1) defaultGen.setAreaNumber(areaNum); if (zoneNum != -1) defaultGen.setZoneNumber(zoneNum); // define the remote control bus defaultGen.setRemoteVoltageControlBus(parser .createBusRef(regBusId)); } // process generator participation factor LoadflowGenDataXmlType defaultGen = AclfParserHelper.getDefaultGen(bus.getGenData()); if (genAGCAble) defaultGen.setMwControlParticipateFactor(partFactor); } }//end of if-subData } public void processBusShuntData(String shuntDataStr){ /* * DATA (SHUNT, [BusNum,ShuntID,AreaNum,ZoneNum,SSRegNum,SSStatus,SSCMode,SSVHigh,SSVLow,SSNMVR, SSBlockNumSteps,SSBlockMVarPerStep,SSBlockNumSteps:1,SSBlockMVarPerStep:1, SSBlockNumSteps:2,SSBlockMVarPerStep:2,SSBlockNumSteps:3,SSBlockMVarPerStep:3, SSBlockNumSteps:4,SSBlockMVarPerStep:4,SSBlockNumSteps:5,SSBlockMVarPerStep:5, SSBlockNumSteps:6,SSBlockMVarPerStep:6,SSBlockNumSteps:7,SSBlockMVarPerStep:7, SSBlockNumSteps:8,SSBlockMVarPerStep:8,SSBlockNumSteps:9,SSBlockMVarPerStep:9]) sample data: DATA (SHUNT, [CustomString, BusNum, ShuntID, SSRegNum, SSStatus, SSCMode, DesiredVoltage, SSVHigh, SSVLow, SSNMVR, SSBlockNumSteps, SSBlockMVarPerStep]) { "C62" 7296 1 7288 "Closed" "Discrete" 1.016 1.026 1.006 0.0 1 25.0 "C64" 7294 1 7287 "Closed" "Discrete" 1.016 1.026 1.006 0.0 1 25.0 } */ long busNum=-1,regBusNum=-1; int areaNum=-1,zoneNum=-1,steps1=0,steps2=0; String shuntId=""; boolean closed=false; double vHigh=1.0,vLow=1.0,normalMVR=0,MVarPerStep1=0,MVarPerStep2=0; SwitchedShuntModeEnumType mode=null; //Control Mode: Fixed, Discrete, Continuous, or Bus Shunt; String CustomStrToken="CustomString"; String customString =""; parseData(shuntDataStr); try { busNum=getLong("BusNum"); if(exist("SSRegNum")) regBusNum=getLong("SSRegNum"); shuntId=exist("ShuntID")?getString("ShuntID"):""; if(exist("SSStatus")) closed=getString("SSStatus").equalsIgnoreCase("Closed")?true:false; if (exist("AreaNum")) areaNum=getInt("AreaNum"); if (exist("ZoneNum")) zoneNum=getInt("ZoneNum"); if (exist("SSCMode")){ String modeStr=getString("SSCMode"); mode=modeStr.equalsIgnoreCase("Discrete")?SwitchedShuntModeEnumType.DISCRETE: (modeStr.equalsIgnoreCase("Continuous")?SwitchedShuntModeEnumType.CONTINUOUS: SwitchedShuntModeEnumType.FIXED); } if (exist("SSVHigh")) vHigh=getDouble("SSVHigh"); if (exist("SSVLow")) vLow=getDouble("SSVLow"); if (exist("SSNMVR")) normalMVR=getDouble("SSNMVR"); //TODO How to determine the number of blocks if (exist("SSBlockNumSteps")) steps1=new Double(getString("SSBlockNumSteps")).intValue(); if (exist("SSBlockMVarPerStep")) MVarPerStep1=getDouble("SSBlockMVarPerStep"); if (exist("SSBlockNumSteps:1")) steps2=new Double(getString("SSBlockNumSteps:1")).intValue(); if (exist("SSBlockMVarPerStep:1")) MVarPerStep2=getDouble("SSBlockMVarPerStep:1"); if(exist(CustomStrToken)) { customString = getString(CustomStrToken); int underScoreIdx = customString.indexOf("_"); if(underScoreIdx>0) customString.substring(0, underScoreIdx); } } catch (ODMException e) { e.printStackTrace(); } //TODO no shunt status defined in ODM String busId=IODMModelParser.BusIdPreFix+busNum; LoadflowBusXmlType bus=parser.getBus(busId); AclfDataSetter.setShuntCompensatorData(bus, mode, normalMVR, vHigh, vLow); SwitchedShuntXmlType shunt=bus.getSwitchedShunt(); // store custom string if(!customString.equals("")) BaseJaxbHelper.addNVPair(bus, "Shunt_"+CustomStrToken, customString); // regulate a remote bus if(busNum!=regBusNum) shunt.setRemoteControlledBus(parser.createBusRef(IODMModelParser.BusIdPreFix+regBusNum)); if(steps1>0&&MVarPerStep1!=0) AclfDataSetter.addShuntCompensatorBlock(bus, steps1, MVarPerStep1, ReactivePowerUnitType.MVAR); if(steps2>0&&MVarPerStep2!=0) AclfDataSetter.addShuntCompensatorBlock(bus, steps2, MVarPerStep2, ReactivePowerUnitType.MVAR); //TODO now only two blocks are considered. //This should be enough for almost all real cases, one for capacitive, one for reactive } /** * Get the substaion name out of the busName string, it is required that busName is created * by following the convention: substationName_baseKV_busId * * busName: "GE_CO_14_115_1" * substationName: GE_CO_14 * * @param customStr * @return */ private String getBusSubstationName(String customStr){ String substr=""; int last_underscore = customStr.lastIndexOf("_"); if(last_underscore>0){ String str2 = customStr.substring(0, last_underscore); int second_last_underscore=str2.lastIndexOf("_"); if(second_last_underscore>0){ substr = str2.substring(0, second_last_underscore); } } return substr; } private String getGenSubstationName(String customStr,String customStr_1){ String subName = ""; int idx= customStr.length()-customStr_1.length()-1; if(idx<=0){ subName = null; /* ODMLogger.getLogger().info("Equipment Name is not contained in the branch extented name." + " # Extented Name: "+customStr+", # equipment name:"+customStr_1); */ } else if(!customStr.substring(idx).equals("_"+customStr_1)){ subName = null; /* ODMLogger.getLogger().info("Equipment Name is not contained in the branch extented name." + " # Extented Name: "+customStr+", # equipment name:"+customStr_1); */ } else{ String s3=customStr.substring(0, idx); int last_underscore = s3.lastIndexOf("_"); if(last_underscore<0){ /* ODMLogger.getLogger().info("No underscore within " + s3 +", # Extented Name: "+customStr+", # equipment name:"+customStr_1); */ subName = null; } else{ subName =s3.substring(0, last_underscore); } } return subName; } }