457 lines
15 KiB
C++
457 lines
15 KiB
C++
#include "cimexporter.h"
|
||
#include <iostream>
|
||
CIMExporter::CIMExporter(const QHash<QString, BasicElementInfo *> &eleHT, const QString &loadDir):loadDir(loadDir),eleHT(eleHT)
|
||
{
|
||
}
|
||
|
||
void CIMExporter::add(const QPair<QString,QString>& fromTo,Line* line)
|
||
{
|
||
LineStru lineStru;
|
||
lineStru.line=line;
|
||
lineStru.fromID=fromTo.first;
|
||
lineStru.toID=fromTo.second;
|
||
lineStru.id=line->ac->getID();
|
||
lineStru.isZeroBranch=std::fabs(line->length)<1e-5;
|
||
lineStru.dispose=false;
|
||
lineStru.type="AC";
|
||
lineStru.length=line->length;
|
||
this->line.push_back(lineStru);
|
||
|
||
}
|
||
void CIMExporter::add(const QPair<QString,QString>& fromTo,Switch* sw)
|
||
{
|
||
SwitchStru switchStru;
|
||
switchStru.sw=sw;
|
||
switchStru.fromID=fromTo.first;
|
||
switchStru.toID=fromTo.second;
|
||
switchStru.id=sw->id;
|
||
switchStru.isZeroBranch=true;
|
||
switchStru.dispose=false;
|
||
switchStru.type="SW";
|
||
this->sw.push_back(switchStru);
|
||
}
|
||
void CIMExporter::add(const QPair<QString,QString>& fromTo,Transformer* tf)
|
||
{
|
||
TransformerStru tfStru;
|
||
tfStru.tf=tf;
|
||
tfStru.fromID=fromTo.first;
|
||
tfStru.toID=fromTo.second;
|
||
tfStru.isZeroBranch=false;
|
||
tfStru.dispose=false;
|
||
tfStru.id=tf->getTF()->getID();
|
||
tfStru.type="TF";
|
||
this->tf.push_back(tfStru);
|
||
}
|
||
|
||
void CIMExporter::add(const QPair<QString,QString>& fromTo,DG* dg)
|
||
{
|
||
DGStru dgStru;
|
||
dgStru.dg=dg;
|
||
dgStru.fromID=fromTo.first;
|
||
dgStru.toID=fromTo.second;
|
||
dgStru.isZeroBranch=false;
|
||
dgStru.dispose=false;
|
||
dgStru.id=dg->id;
|
||
dgStru.type="DG";
|
||
this->dg.push_back(dgStru);
|
||
}
|
||
|
||
void CIMExporter::exportTo(const QString& path,const QString &rootID)
|
||
{
|
||
char seperator='\t';
|
||
QString endLine="\r\n";
|
||
//输出到文件
|
||
QFile fd(path);
|
||
if(fd.open(QFile::WriteOnly))
|
||
{
|
||
//消减元件
|
||
QList<BranchStruc*> elements;
|
||
for(int i=0;i<this->line.length();i++)
|
||
{
|
||
// std::cout<<this->line[i].fromID.toStdString()<<" "<<this->line[i].id.toStdString()<<" "<<this->line[i].toID.toStdString()<<std::endl;
|
||
elements.push_back( &(this->line[i]) );
|
||
}
|
||
for(int i=0;i<this->sw.length();i++)
|
||
{
|
||
// std::cout<<this->sw[i].fromID.toStdString()<<" "<<this->sw[i].id.toStdString()<<" "<<this->sw[i].toID.toStdString()<<std::endl;
|
||
elements.push_back( &(this->sw[i]) );
|
||
}
|
||
for(int i=0;i<this->tf.length();i++)
|
||
{
|
||
// std::cout<<this->tf[i].fromID.toStdString()<<" "<<this->tf[i].id.toStdString()<<" "<<this->tf[i].toID.toStdString()<<std::endl;
|
||
elements.push_back( &(this->tf[i]) );
|
||
}
|
||
for(int i=0;i<this->dg.length();i++)
|
||
{
|
||
// std::cout<<this->dg[i].fromID.toStdString()<<" "<<this->dg[i].id.toStdString()<<" "<<this->dg[i].toID.toStdString()<<std::endl;
|
||
elements.push_back( &(this->dg[i]) );
|
||
}
|
||
ElementReduction elementReduction(elements);
|
||
elementReduction.doIt(rootID);//消除0阻抗支路,把几段线路连成一段
|
||
//先给所有节点都编号
|
||
this->idToNumber(this->line);
|
||
this->idToNumber(this->sw);
|
||
this->idToNumber(this->tf);
|
||
this->idToNumber(this->dg);
|
||
//开始按iPso格式要求输出
|
||
QTextStream writer(&fd);
|
||
//iPso 第一行
|
||
writer<<this->number.keys().length()<<seperator;//节点数
|
||
//TODO: 支路数要单独计算
|
||
writer<<0<<seperator;//支路数,由于有些支路被删掉了,所以要计算一下。这里暂时不计算。
|
||
writer<<1<<seperator;//计算目标
|
||
writer<<1e-5<<seperator;//收敛精度
|
||
writer<<-1<<endLine;//忘记是什么了
|
||
writer<<0<<endLine;//数据间隔
|
||
int balanceNum;//平衡节点号
|
||
foreach(LineStru l,this->line )
|
||
{
|
||
if(l.id==rootID)
|
||
{
|
||
balanceNum=l.fromNum;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// std::cout<<"line number "<<this->line.first().fromNum<<" "<<this->line.first().toNum<<" "<<this->line.first().isZeroBranch<<this->line.first().dispose <<std::endl;
|
||
writer<<1<<seperator<<balanceNum<<seperator;
|
||
writer<<"1.05"<<endLine;//平衡节点电压
|
||
writer<<0<<endLine;//数据间隔
|
||
|
||
int seqN=1;//序号
|
||
//先输出线路
|
||
|
||
// writer<<QStringLiteral("线路")<<QStringLiteral("\r\n");
|
||
// writer<<QStringLiteral("节点号")<<QStringLiteral("\t")<<QStringLiteral("节点号")<<QStringLiteral("\t")<<QStringLiteral("型号")<<QStringLiteral("\t")<<QStringLiteral("长度(m)")<<QStringLiteral("\r\n");
|
||
for(QList<LineStru>::iterator ite=this->line.begin();
|
||
ite!=this->line.end();
|
||
ite++)
|
||
{
|
||
LineStru l=*ite;
|
||
if(l.dispose)
|
||
{
|
||
continue;
|
||
}
|
||
writer<<seqN++<<seperator;
|
||
writer<<l.fromNum<<seperator;
|
||
writer<<l.toNum<<seperator;
|
||
writer<<l.line->r<<seperator;
|
||
writer<<l.line->x<<seperator;
|
||
writer<<l.line->b1<<seperator;
|
||
writer<<l.line->b2<<seperator;
|
||
writer<<endLine;
|
||
}
|
||
|
||
//输出刀闸
|
||
for(QList<SwitchStru>::iterator ite=this->sw.begin();
|
||
ite!=this->sw.end();
|
||
ite++)
|
||
{
|
||
if(ite->dispose)
|
||
{
|
||
continue;
|
||
}
|
||
writer<<seqN++<<seperator;
|
||
writer<<ite->fromNum<<seperator;
|
||
writer<<ite->toNum<<seperator;
|
||
writer<<ite->sw->r<<seperator;
|
||
writer<<ite->sw->x<<seperator;
|
||
writer<<ite->sw->b1<<seperator;
|
||
writer<<ite->sw->b2<<seperator;
|
||
writer<<endLine;
|
||
// writer<<"type"<<"\t";
|
||
// writer<<ite->id<<"\t";
|
||
// writer<<0<<"\r\n";
|
||
}
|
||
writer<<0<<endLine;//数据间隔
|
||
//输出变压器
|
||
RecurseDir recurseDir;
|
||
recurseDir.setDir(this->loadDir);
|
||
QStringList files;
|
||
files=recurseDir.getFiles();
|
||
//只取文件名
|
||
|
||
QStringList baseNames;
|
||
foreach(QString file,files)
|
||
{
|
||
QFileInfo fileInfo(file);
|
||
if(fileInfo.suffix().toLower()!="csv")
|
||
{
|
||
continue;
|
||
}
|
||
baseNames<<fileInfo.baseName();
|
||
// std::cout<<"has "<<fileInfo.baseName().toLocal8Bit().data()<<std::endl;
|
||
}
|
||
seqN=1;
|
||
// writer<<QStringLiteral("变压器")<<"\r\n";
|
||
// writer<<QStringLiteral("节点号")<<"\t"<<QStringLiteral("节点号")<<"\t"<<QStringLiteral("型号")<<"\t"<<QStringLiteral("容量(MVA)")<<"\r\n";
|
||
|
||
//把接地支路准备一下
|
||
QList<CIMExporter::GroundBranch > groudBranch;//first is g, second is b.
|
||
QList<CIMExporter::NodePQ> nodePQ;//节点注入功率,也就是负荷或者发电机
|
||
QStringList usedLoad;
|
||
for(QList<TransformerStru>::iterator ite=this->tf.begin();
|
||
ite!=this->tf.end();
|
||
ite++)
|
||
{
|
||
if(ite->dispose)
|
||
{
|
||
continue;
|
||
}
|
||
PowerTransformer *tf=ite->tf->getTF();
|
||
QString subID=tf->getEquipmentMemberOf_EquipmentContainer();//所属Substation的ID
|
||
|
||
Substation *sub=static_cast<Substation *>(this->eleHT[subID]);
|
||
if(!sub)
|
||
{
|
||
std::cout<<"CIMExporter:: can not substation of "<<subID.toStdString()<<std::endl;
|
||
continue;
|
||
}
|
||
// std::cout<<"sub id"<< subID.toStdString()<<" "<<sub->getID().toStdString()<<std::endl;
|
||
|
||
writer<<seqN++<<seperator;
|
||
writer<<0<<seperator;//变压器区域
|
||
writer<<ite->fromNum<<seperator;
|
||
writer<<ite->toNum<<seperator;
|
||
writer<<ite->tf->r<<seperator;
|
||
writer<<ite->tf->x<<seperator;
|
||
writer<<ite->tf->ratio<<seperator;
|
||
writer<<1<<seperator;
|
||
writer<<1<<seperator;
|
||
writer<<1<<seperator;
|
||
writer<<endLine;
|
||
//保存接地支路
|
||
groudBranch.push_back(CIMExporter::GroundBranch(ite->toNum, ite->tf->g1,ite->tf->b1));//都只用g1,b1的数据
|
||
|
||
|
||
LoadMapping loadMapping;
|
||
QVector<QSharedPointer<LoadInfo> > vecLoadInfo=loadMapping.getSubstationLoad(sub->getID());
|
||
foreach(QSharedPointer<LoadInfo> p,vecLoadInfo)
|
||
{
|
||
|
||
QFileInfo targetBasename(p->getLoadPath());
|
||
// std::cout<<"search for "<<targetBasename.baseName().toLocal8Bit().data()<<std::endl;
|
||
if( baseNames.contains( targetBasename.baseName()) and !usedLoad.contains(targetBasename.baseName()))
|
||
{
|
||
// std::cout<<targetBasename.baseName().toLocal8Bit().data()<<" used "<<std::endl;
|
||
usedLoad<<targetBasename.baseName();
|
||
//保存节点注入功率
|
||
nodePQ.push_back(CIMExporter::NodePQ(ite->toNum,p->get3PhP(),p->get3PhQ()));
|
||
// writer<<"type"<<"\t";
|
||
// writer<<ite->id<<"\t";
|
||
// writer<<tf->getMVA()<<"\r\n";
|
||
//加到LoadExport中
|
||
LoadExporter loadExporter;
|
||
loadExporter.add(targetBasename.baseName(),p);
|
||
break;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<0<<endLine;//数据间隔
|
||
seqN=1;
|
||
foreach(CIMExporter::GroundBranch gb,groudBranch)
|
||
{
|
||
writer<<seqN++<<seperator;
|
||
writer<<gb.nodeNum<<seperator;
|
||
writer<<gb.g<<seperator;
|
||
writer<<gb.b<<seperator;
|
||
writer<<endLine;
|
||
}
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<0<<endLine;//数据间隔
|
||
//列出DG
|
||
// writer<<QStringLiteral("分布式电源")<<"\r\n";
|
||
for(QList<DGStru>::iterator ite=this->dg.begin();
|
||
ite!=this->dg.end();
|
||
ite++)
|
||
{
|
||
//保存到节点注入功率中
|
||
nodePQ.push_back(CIMExporter::NodePQ(ite->toNum,-ite->dg->capacity,-ite->dg->capacity) );
|
||
// writer<<ite->fromNum<<"\t";
|
||
// writer<<ite->toNum<<"\t";
|
||
// writer<<ite->dg->capacity<<"\r\n";
|
||
}
|
||
|
||
//iPso 开始输出注入功率
|
||
CIMExporter::NodePQ *nodePQPointer=new CIMExporter::NodePQ[this->number.keys().length()];
|
||
foreach(CIMExporter::NodePQ n,nodePQ)
|
||
{
|
||
int nodeNum=n.nodeNum;
|
||
if(nodeNum>this->number.keys().length())
|
||
{
|
||
std::cout<<"number of nodePQ is beyond node number."<<std::endl;
|
||
break;
|
||
}
|
||
nodePQPointer[nodeNum-1]=n;
|
||
}
|
||
seqN=1;
|
||
for(int i=0;i<this->number.keys().length();i++)
|
||
{
|
||
writer<<seqN<<seperator;
|
||
writer<<-1<<seperator;
|
||
writer<<seqN++<<seperator;
|
||
writer<<10<<seperator;
|
||
writer<<0<<seperator;
|
||
writer<<0<<seperator;
|
||
writer<<nodePQPointer[i].P<<seperator;
|
||
writer<<nodePQPointer[i].Q<<seperator;
|
||
writer<<1<<seperator;
|
||
writer<<0<<seperator;
|
||
writer<<endLine;
|
||
}
|
||
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<1<< seperator<<1<< seperator<<balanceNum<< seperator<<1<< seperator<< -100<< seperator<<100<< seperator<<0<< seperator<<0<< seperator<<0<< seperator<<0<< seperator;
|
||
writer<<endLine;
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<1<< seperator<<1<< seperator<<balanceNum<<seperator<<1<< seperator<<1.05<< seperator<< -100<< seperator<<100<< seperator<<0<< seperator<<0<< seperator<<0<< seperator<<0<< seperator;
|
||
writer<<endLine;
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<1<< seperator<<balanceNum<< seperator<<0.999<< seperator<<1.001<<seperator;
|
||
writer<<endLine;
|
||
//接着13个0
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<0<<endLine;//数据间隔
|
||
writer<<0<<endLine;//数据间隔
|
||
|
||
|
||
//列出没有用的负荷文件
|
||
foreach(QString name, baseNames)
|
||
{
|
||
if(!usedLoad.contains(name))
|
||
{
|
||
LoadMatchException except;
|
||
if(!except.contains(name))
|
||
{
|
||
std::cout<<name.toLocal8Bit().data()<<"not used"<<std::endl;
|
||
}
|
||
else
|
||
{
|
||
std::cout<<name.toLocal8Bit().data()<<"not used but excepted."<<std::endl;
|
||
}
|
||
}
|
||
}
|
||
this->topologyTest();
|
||
fd.close();
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
}
|
||
|
||
template<typename T>
|
||
void CIMExporter::idToNumber(QList<T> &s)//把所有元件的标识进行编号
|
||
{
|
||
for(typename QList<T>::iterator ite=s.begin();
|
||
ite!=s.end();
|
||
ite++
|
||
)
|
||
{
|
||
if(ite->dispose)
|
||
{
|
||
// std::cout<<ite->id.toStdString()<<" dispose"<<std::endl;
|
||
continue;
|
||
|
||
}
|
||
T _t=*ite;
|
||
_t.fromNum=this->numberIt(_t.fromID);
|
||
_t.toNum=this->numberIt(_t.toID);
|
||
std::cout<<"id "<<_t.id.toStdString()<<" "<<_t.fromNum<<" "<<_t.toNum<<std::endl;
|
||
*ite=_t;
|
||
}
|
||
}
|
||
|
||
int CIMExporter::numberIt(const QString& id)
|
||
{
|
||
if(this->number.contains(id))
|
||
{
|
||
return this->number.value(id);
|
||
}
|
||
else
|
||
{
|
||
int n=this->number.keys().length()+1;
|
||
this->number[id]=n;
|
||
// std::cout<<id.toStdString()<<" "<<n<<std::endl;
|
||
return n;
|
||
|
||
}
|
||
}
|
||
|
||
|
||
bool CIMExporter::topologyTest()
|
||
{
|
||
//检查一下拓扑关系
|
||
QList<QPair<int,int> > linkage;
|
||
for(QList<LineStru>::iterator ite=this->line.begin();
|
||
ite!=this->line.end();
|
||
ite++)
|
||
{
|
||
if(ite->dispose)
|
||
{
|
||
continue;
|
||
}
|
||
linkage.push_back(QPair<int,int>(ite->fromNum,ite->toNum));
|
||
}
|
||
for(QList<SwitchStru>::iterator ite=this->sw.begin();
|
||
ite!=this->sw.end();
|
||
ite++)
|
||
{
|
||
if(ite->dispose)
|
||
{
|
||
continue;
|
||
}
|
||
linkage.push_back(QPair<int,int>(ite->fromNum,ite->toNum));
|
||
}
|
||
for(QList<TransformerStru>::iterator ite=this->tf.begin();
|
||
ite!=this->tf.end();
|
||
ite++)
|
||
{
|
||
if(ite->dispose)
|
||
{
|
||
continue;
|
||
}
|
||
linkage.push_back(QPair<int,int>(ite->fromNum,ite->toNum));
|
||
}
|
||
|
||
for(QList<DGStru>::iterator ite=this->dg.begin();
|
||
ite!=this->dg.end();
|
||
ite++)
|
||
{
|
||
if(ite->dispose)
|
||
{
|
||
continue;
|
||
}
|
||
linkage.push_back(QPair<int,int>(ite->fromNum,ite->toNum));
|
||
}
|
||
|
||
|
||
TopologyTest tpTest(this->number.keys().length());
|
||
if(tpTest.start(linkage))
|
||
{
|
||
std::cout<<"topoloty ok!"<<std::endl;
|
||
return true;
|
||
}else
|
||
{
|
||
std::cout<<"not ok topology"<<std::endl;
|
||
return false;
|
||
}
|
||
}
|