|
@@ -460,6 +460,7 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
|
|
|
if scdXmlObj == nil {
|
|
|
return errors.New("无效的SCD")
|
|
|
}
|
|
|
+ scdidStr := fmt.Sprintf("%d", c.ScdId)
|
|
|
db := orm.NewOrm()
|
|
|
//获取当前站的各电压等级
|
|
|
volRows := []orm.Params{}
|
|
@@ -561,11 +562,12 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
|
|
|
return ied_type, vol
|
|
|
}
|
|
|
//从间隔装置中过滤出指定类型的IED
|
|
|
- var filterAreaIeds = func(ied_type, volLevelCode string, s1 []orm.Params) []orm.Params {
|
|
|
+ var filterAreaIeds = func(ied_type, volLevelCode string, s1 []orm.Params, abCode string, isPm ...bool) []orm.Params {
|
|
|
iedlst := []orm.Params{}
|
|
|
if volLevelCode == "" || (volLevelCode != "H" && volLevelCode != "M" && volLevelCode != "L") {
|
|
|
for _, r := range s1 {
|
|
|
- if strings.HasPrefix(tools.IsEmpty(r["ied_name"]), ied_type) {
|
|
|
+ iedname := tools.IsEmpty(r["ied_name"])
|
|
|
+ if strings.HasPrefix(iedname, ied_type) || (abCode != "" && strings.HasSuffix(iedname, abCode)) {
|
|
|
iedlst = append(iedlst, r)
|
|
|
}
|
|
|
}
|
|
@@ -573,11 +575,20 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
|
|
|
tmpLst := map[string]orm.Params{}
|
|
|
for _, r := range s1 {
|
|
|
iedname := tools.IsEmpty(r["ied_name"])
|
|
|
- if strings.HasPrefix(iedname, ied_type) {
|
|
|
+ if strings.HasPrefix(iedname, ied_type) || (abCode != "" && strings.HasSuffix(iedname, abCode)) {
|
|
|
tmpLst[iedname] = r
|
|
|
}
|
|
|
}
|
|
|
- h, m, l := c.getIedListByVol(ied_type, tmpLst, volMap)
|
|
|
+ //PM类型的装置需要单独处理
|
|
|
+ if len(isPm) > 0 {
|
|
|
+ //只有1台PM装置时,不用区分电压等级直接返回
|
|
|
+ if len(tmpLst) == 1 {
|
|
|
+ for _, r1 := range tmpLst {
|
|
|
+ return []orm.Params{r1}
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ h, m, l := c.getIedListByVol(ied_type, tmpLst, volMap, abCode)
|
|
|
if volLevelCode == "H" {
|
|
|
iedlst = h
|
|
|
}
|
|
@@ -592,6 +603,12 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
|
|
|
}
|
|
|
//iedRelationMgr := new(SysCheckModelIedRelationMgr)
|
|
|
modelFcda := sync.Map{}
|
|
|
+ //已经加载过遥信的装置
|
|
|
+ isLoadYxIed := map[string]map[*node_attr.NExtRef]string{}
|
|
|
+ //已经处理过遥信端子的装置
|
|
|
+ isDealYxIed := map[string]int{}
|
|
|
+ //已获取端子的装置
|
|
|
+ isLoadExtref := map[string]map[string]*node_attr.NExtRef{}
|
|
|
for _, row := range arealist {
|
|
|
//获取间隔标准装置及关系
|
|
|
modelid, _ := strconv.Atoi(tools.IsEmpty(row["model_id"]))
|
|
@@ -623,46 +640,44 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
|
|
|
s1 := []orm.Params{}
|
|
|
_, err = db.Raw("select ied_name from t_data_check_area_ied where area_id=?", area_id).Values(&s1)
|
|
|
typeMappingMgr := new(SysCheckModelIedtypeMappingMgr)
|
|
|
+ pmCode := c.getIedTypeCode(modelid, "PM")
|
|
|
//循环处理关联关系
|
|
|
for to_ied_type2, refrow := range funclist {
|
|
|
+ logger.Logger.Debug(fmt.Sprintf("================正在检查类型%s关系===============", to_ied_type2))
|
|
|
ts := strings.Split(to_ied_type2, ",")
|
|
|
//从间隔中获取当前同类型的信号接收装置
|
|
|
ied_type := c.getIedTypeCode(modelid, ts[0])
|
|
|
if v, h := groupList[ied_type]; h {
|
|
|
- ied_type = v
|
|
|
- }
|
|
|
- mappresult := typeMappingMgr.GetMappingType(modelid, ied_type)
|
|
|
- if mappresult != "" {
|
|
|
- ied_type = mappresult
|
|
|
+ ied_type = typeMappingMgr.GetMappingType(modelid, v)
|
|
|
}
|
|
|
+ abCode := c.getIedTypeABCode(ied_type)
|
|
|
ied_type, vol := getIedTypeAndVolCode(ied_type)
|
|
|
- iedlst := filterAreaIeds(ied_type, vol, s1)
|
|
|
- logger.Logger.Debug(fmt.Sprintf("正在检查装置类型:%s的装置(%+v)端子关系", ied_type, iedlst))
|
|
|
+ isReceivePm := strings.HasPrefix(ied_type, pmCode) //接收装置是Pm装置
|
|
|
+ iedlst := filterAreaIeds(ied_type, vol, s1, abCode, isReceivePm)
|
|
|
+ logger.Logger.Debug(fmt.Sprintf("装置类型%s#%s与%s的装置(%+v)端子关系", ied_type, vol, ts[1], iedlst))
|
|
|
//从间隔中获取当前信号输出装置
|
|
|
outiedlist := map[string]orm.Params{}
|
|
|
fromiedcode := c.getIedTypeCode(modelid, ts[1])
|
|
|
if v, h := groupList[fromiedcode]; h {
|
|
|
- fromiedcode = v
|
|
|
- }
|
|
|
- mappresult = typeMappingMgr.GetMappingType(modelid, fromiedcode)
|
|
|
- if mappresult != "" {
|
|
|
- fromiedcode = mappresult
|
|
|
+ fromiedcode = typeMappingMgr.GetMappingType(modelid, v)
|
|
|
}
|
|
|
+ fromAbCode := c.getIedTypeABCode(fromiedcode)
|
|
|
from_ied_type, vol2 := getIedTypeAndVolCode(fromiedcode)
|
|
|
- outiedlist2 := filterAreaIeds(from_ied_type, vol2, s1)
|
|
|
+ isOutPm := strings.HasPrefix(from_ied_type, pmCode) //输出装置是PM装置
|
|
|
+ outiedlist2 := filterAreaIeds(from_ied_type, vol2, s1, fromAbCode, isOutPm)
|
|
|
for _, iedrow := range outiedlist2 {
|
|
|
iedname := tools.IsEmpty(iedrow["ied_name"])
|
|
|
outiedlist[iedname] = iedrow
|
|
|
}
|
|
|
if len(outiedlist) == 0 {
|
|
|
- logger.Logger.Debug(fmt.Sprintf("装置类型%s未发现输出任何装置", ied_type))
|
|
|
+ logger.Logger.Debug(fmt.Sprintf("装置类型%s#%s%s未从类型%s%s的任何电压等级%s装置接收信号", ied_type, vol, abCode, from_ied_type, fromAbCode, vol2))
|
|
|
continue
|
|
|
}
|
|
|
- logger.Logger.Debug(fmt.Sprintf("当前装置类型:%s的装置(%+v)存在以下信号输出装置:%+v", ied_type, iedlst, outiedlist))
|
|
|
+ logger.Logger.Debug(fmt.Sprintf("当前装置类型:%s%s的装置(%+v)与类型%s#%s%s存在以下信号输出装置:%+v", ied_type, abCode, iedlst, from_ied_type, fromAbCode, vol2, outiedlist))
|
|
|
//logger.Logger.Debug(fmt.Sprintf("设计端子关联关系:%+v", refrow))
|
|
|
for _, ied := range iedlst {
|
|
|
iedname := tools.IsEmpty(ied["ied_name"])
|
|
|
- iedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), iedname)
|
|
|
+ iedObj := scdNodeMgr.GetIed(scdXmlObj, scdidStr, iedname)
|
|
|
iedObjDesc := ""
|
|
|
if iedObj != nil {
|
|
|
iedObjDesc = iedObj.Desc
|
|
@@ -670,31 +685,41 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
|
|
|
logger.Logger.Error(fmt.Sprintf("信号接收装置%s未找到!", iedname))
|
|
|
continue
|
|
|
}
|
|
|
- extreflist := getIedExtRefs(iedname)
|
|
|
+ //遥信端子列表:仅根据scd实际配置检查其双方端子的doi名称是否相同
|
|
|
+ scdMgr := new(ScdMgr)
|
|
|
+ yx, h := isLoadYxIed[iedname]
|
|
|
+ if !h {
|
|
|
+ yx = scdMgr.GetYxExtref(scdXmlObj, c.ScdId, iedname)
|
|
|
+ isLoadYxIed[iedname] = yx
|
|
|
+ }
|
|
|
+ yxAddrMap := map[string]int{}
|
|
|
+ for sg, _ := range yx {
|
|
|
+ key := fmt.Sprintf("%s%s%s%s%s%s%s", sg.IedName, sg.IntAddr, sg.LdInst, sg.Prefix, sg.LnClass, sg.LnInst, sg.DoName)
|
|
|
+ yxAddrMap[key] = 1
|
|
|
+ }
|
|
|
+ //所有端子列表
|
|
|
+ extreflist := isLoadExtref[iedname]
|
|
|
+ if extreflist == nil {
|
|
|
+ extreflist = getIedExtRefs(iedname)
|
|
|
+ }
|
|
|
for outiedname, _ := range outiedlist {
|
|
|
if iedname == outiedname {
|
|
|
continue
|
|
|
}
|
|
|
logger.Logger.Debug(fmt.Sprintf("正在匹配装置%s与%s的端子关联关系", iedname, outiedname))
|
|
|
- outIedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), outiedname)
|
|
|
- //outIedObjDesc := ""
|
|
|
+ outIedObj := scdNodeMgr.GetIed(scdXmlObj, scdidStr, outiedname)
|
|
|
+ outIedObjDesc := ""
|
|
|
if outIedObj == nil {
|
|
|
logger.Logger.Error(fmt.Sprintf("信号输出装置%s未找到!", outiedname))
|
|
|
} else {
|
|
|
- //outIedObjDesc = outIedObj.Desc
|
|
|
+ outIedObjDesc = outIedObj.Desc
|
|
|
}
|
|
|
if iedObj == nil && outIedObj == nil {
|
|
|
continue
|
|
|
}
|
|
|
outiedFcdaList := getIedFcdas(outiedname) //输入装置的信号输出端子
|
|
|
//检查是否有错误和缺失的端子
|
|
|
- hasYaoXinFunc := false //是否具备遥信功能
|
|
|
for _, r := range refrow {
|
|
|
- //判断装置是否具备遥信功能,具备时需要单独处理遥信类端子
|
|
|
- //遥信类端子处理规则:以scd中实际配置为准,通过检查装置双方的端子名称是否完全一致,以及是否有缺失和多余的遥信端子
|
|
|
- if strings.Contains(tools.IsEmpty(r["to_func_name"]), "遥信") || strings.Contains(tools.IsEmpty(r["from_func_name"]), "遥信") {
|
|
|
- hasYaoXinFunc = true
|
|
|
- }
|
|
|
extref_name := tools.IsEmpty(r["to_fcda_name"])
|
|
|
fcda_name := tools.IsEmpty(r["from_fcda_name"])
|
|
|
extref_name_exp := tools.IsEmpty(r["to_fcda_match_exp"])
|
|
@@ -703,14 +728,24 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
|
|
|
extrefObj := new(node_attr.NExtRef)
|
|
|
fcda2Exist := false
|
|
|
fcdaObj := new(node_attr.NFCDA)
|
|
|
+ isYx := false
|
|
|
for desc, item := range extreflist {
|
|
|
//logger.Logger.Debug(fmt.Sprintf("接收装置%s的设计端子%s匹配SCD ExtRef DO端子%s", iedname, extref_name_exp, desc))
|
|
|
if tools.RexGroupTestMatch(extref_name_exp, desc) {
|
|
|
+ //判断是否是遥信端子
|
|
|
+ if yxAddrMap[fmt.Sprintf("%s%s%s%s%s%s%s", item.IedName, item.IntAddr, item.LdInst, item.Prefix, item.LnClass, item.LnInst, item.DoName)] == 1 {
|
|
|
+ isYx = true
|
|
|
+ break
|
|
|
+ }
|
|
|
funcExist = true
|
|
|
extrefObj = item
|
|
|
break
|
|
|
}
|
|
|
}
|
|
|
+ if isYx {
|
|
|
+ //遥信端子不处理
|
|
|
+ continue
|
|
|
+ }
|
|
|
if funcExist {
|
|
|
//判断输出端端子是否存在
|
|
|
for desc, item := range outiedFcdaList {
|
|
@@ -722,53 +757,33 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- if !funcExist || !fcda2Exist {
|
|
|
- if !funcExist {
|
|
|
- parse_result := fmt.Sprintf("间隔%s的装置%s缺失端子%s", area_name, iedname, extref_name)
|
|
|
- re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
|
|
|
- "ied_name": iedname,
|
|
|
- "ied_desc": iedObjDesc,
|
|
|
- "out_ied_name": "",
|
|
|
- "out_ied_desc": "",
|
|
|
- "fcda_desc": extref_name,
|
|
|
- "fcda_addr": "",
|
|
|
- "out_fcda_desc": "",
|
|
|
- "out_fcda_addr": "",
|
|
|
- "error_type": "3",
|
|
|
- }
|
|
|
- //检查未通过
|
|
|
- scdNodeRule.AppendFcdaCheckResult(re)
|
|
|
+ if !funcExist {
|
|
|
+ parse_result := fmt.Sprintf("间隔%s的装置%s缺失端子%s", area_name, iedname, extref_name)
|
|
|
+ re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
|
|
|
+ "ied_name": iedname,
|
|
|
+ "ied_desc": iedObjDesc,
|
|
|
+ "out_ied_name": "",
|
|
|
+ "out_ied_desc": "",
|
|
|
+ "fcda_desc": extref_name,
|
|
|
+ "fcda_addr": "",
|
|
|
+ "out_fcda_desc": "",
|
|
|
+ "out_fcda_addr": "",
|
|
|
+ "error_type": "3",
|
|
|
}
|
|
|
- /*
|
|
|
- if !fcda2Exist {
|
|
|
- parse_result := fmt.Sprintf("间隔%s的装置%s缺失端子%s", area_name, outiedname, fcda_name)
|
|
|
- re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
|
|
|
- "ied_name": "",
|
|
|
- "ied_desc": "",
|
|
|
- "out_ied_name": outiedname,
|
|
|
- "out_ied_desc": outIedObjDesc,
|
|
|
- "fcda_desc": "",
|
|
|
- "fcda_addr": "",
|
|
|
- "out_fcda_desc": fcda_name,
|
|
|
- "out_fcda_addr": "",
|
|
|
- "error_type": "3",
|
|
|
- }
|
|
|
- //检查未通过
|
|
|
- scdNodeRule.AppendFcdaCheckResult(re)
|
|
|
- }
|
|
|
- */
|
|
|
+ //检查未通过
|
|
|
+ scdNodeRule.AppendFcdaCheckResult(re)
|
|
|
} else {
|
|
|
//检查端子是否关联正确
|
|
|
- if fcda2Exist && (extrefObj.LdInst != fcdaObj.LdInst ||
|
|
|
+ //fcda2Exist为false表示实际的端子from ied不是当前设计的ied
|
|
|
+ //fcda2Exist为true时,进一步判断端子地址是否与设计相符
|
|
|
+ if !fcda2Exist || (extrefObj.LdInst != fcdaObj.LdInst ||
|
|
|
extrefObj.LnInst != fcdaObj.LnInst ||
|
|
|
extrefObj.LnClass != fcdaObj.LnClass ||
|
|
|
extrefObj.Prefix != fcdaObj.Prefix ||
|
|
|
extrefObj.DoName != fcdaObj.DoName) {
|
|
|
//不正确
|
|
|
- logger.Logger.Debug(fmt.Sprintf("extref_name:%s extref_name_exp:%s extrefObj:%+v", extref_name, extref_name_exp, extrefObj))
|
|
|
- logger.Logger.Debug(fmt.Sprintf("fcda_name:%s fcda_name_exp:%s fcdaObj:%+v", fcda_name, fcda_name_exp, fcdaObj))
|
|
|
- iedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), iedname)
|
|
|
- outIedObj := scdNodeMgr.GetIed(scdXmlObj, fmt.Sprintf("%d", c.ScdId), outiedname)
|
|
|
+ //logger.Logger.Debug(fmt.Sprintf("extref_name:%s extref_name_exp:%s extrefObj:%+v", extref_name, extref_name_exp, extrefObj))
|
|
|
+ //logger.Logger.Debug(fmt.Sprintf("fcda_name:%s fcda_name_exp:%s fcdaObj:%+v", fcda_name, fcda_name_exp, fcdaObj))
|
|
|
parse_result := fmt.Sprintf("间隔%s的装置%s端子%s与装置%s端子%s关联错误", area_name, iedname, extref_name, outiedname, fcda_name)
|
|
|
daname := ""
|
|
|
if fcdaObj.DaName != "" {
|
|
@@ -778,7 +793,7 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
|
|
|
"ied_name": iedname,
|
|
|
"ied_desc": iedObj.Desc,
|
|
|
"out_ied_name": outiedname,
|
|
|
- "out_ied_desc": outIedObj.Desc,
|
|
|
+ "out_ied_desc": outIedObjDesc,
|
|
|
"fcda_desc": extref_name,
|
|
|
"fcda_addr": extrefObj.IntAddr,
|
|
|
"out_fcda_desc": fcda_name,
|
|
@@ -792,13 +807,14 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
|
|
|
}
|
|
|
//检查是否有多余(SCD中有不存在于设计中)的端子
|
|
|
for extrefdesc, r := range extreflist { //scd中的端子关系
|
|
|
+ //判断是否是遥信端子
|
|
|
+ if yxAddrMap[fmt.Sprintf("%s%s%s%s%s%s%s", r.IedName, r.IntAddr, r.LdInst, r.Prefix, r.LnClass, r.LnInst, r.DoName)] == 1 {
|
|
|
+ continue
|
|
|
+ }
|
|
|
extref_name := ""
|
|
|
fcda_name := ""
|
|
|
isHave := false
|
|
|
for _, r1 := range refrow { //设计的端子关系
|
|
|
- if strings.Contains(tools.IsEmpty(r1["to_func_name"]), "遥信") || strings.Contains(tools.IsEmpty(r1["from_func_name"]), "遥信") {
|
|
|
- hasYaoXinFunc = true
|
|
|
- }
|
|
|
extref_name_exp := tools.IsEmpty(r1["to_fcda_match_exp"])
|
|
|
if extrefdesc == extref_name_exp || tools.RexGroupTestMatch(extref_name_exp, extrefdesc) {
|
|
|
//端子存在
|
|
@@ -815,16 +831,17 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
|
|
|
if doi != nil {
|
|
|
extref_name = doi.(*node_attr.NDOI).Desc
|
|
|
}
|
|
|
- doi, _ = scdNodeRule.IedFcdaExist(outiedname, r.LdInst, r.LnClass, r.LnInst, r.Prefix, r.DoName, "")
|
|
|
+ doi, _ = scdNodeRule.IedFcdaExist(r.IedName, r.LdInst, r.LnClass, r.LnInst, r.Prefix, r.DoName, "")
|
|
|
if doi != nil {
|
|
|
fcda_name = doi.(*node_attr.NDOI).Desc
|
|
|
}
|
|
|
+ tmpIedObj := scdNodeMgr.GetIed(scdXmlObj, scdidStr, r.IedName)
|
|
|
parse_result := fmt.Sprintf("间隔%s下装置(%s)的端子%s在设计中不存在", area_name, iedname, extref_name)
|
|
|
re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
|
|
|
"ied_name": iedname,
|
|
|
"ied_desc": iedObj.Desc,
|
|
|
- "out_ied_name": outiedname,
|
|
|
- "out_ied_desc": outIedObj.Desc,
|
|
|
+ "out_ied_name": r.IedName,
|
|
|
+ "out_ied_desc": tmpIedObj.Desc,
|
|
|
"fcda_desc": extref_name,
|
|
|
"fcda_addr": r.IntAddr,
|
|
|
"out_fcda_desc": fcda_name,
|
|
@@ -835,62 +852,62 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
|
|
|
scdNodeRule.AppendFcdaCheckResult(re)
|
|
|
}
|
|
|
}
|
|
|
- if hasYaoXinFunc {
|
|
|
- //遥信端子检查:仅根据scd实际配置检查其双方端子的doi名称是否相同
|
|
|
- scdMgr := new(ScdMgr)
|
|
|
- yx := scdMgr.GetYxExtref(scdXmlObj, c.ScdId, iedname)
|
|
|
- if len(yx) > 0 {
|
|
|
- for extref, doiDesc := range yx {
|
|
|
- if extref.IedName != outiedname {
|
|
|
- //非当前输入装置的,不处理
|
|
|
- continue
|
|
|
- }
|
|
|
- daname := ""
|
|
|
- if extref.DaName != "" {
|
|
|
- daname = "." + extref.DaName
|
|
|
- }
|
|
|
- //获取输出端端子名称
|
|
|
- outFcdaDoi, _ := scdNodeRule.IedFcdaExist(extref.IedName, extref.LdInst, extref.LnClass, extref.LnInst, extref.Prefix, extref.DoName, extref.DaName)
|
|
|
- if outFcdaDoi == nil {
|
|
|
- //端子缺失
|
|
|
- parse_result := fmt.Sprintf("间隔%s的装置%s端子%s的关联端子不存在", area_name, iedname, doiDesc)
|
|
|
- re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
|
|
|
- "ied_name": iedname,
|
|
|
- "ied_desc": iedObj.Desc,
|
|
|
- "out_ied_name": outiedname,
|
|
|
- "out_ied_desc": outIedObj.Desc,
|
|
|
- "fcda_desc": doiDesc,
|
|
|
- "fcda_addr": extref.IntAddr,
|
|
|
- "out_fcda_desc": "",
|
|
|
- "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName, daname),
|
|
|
- "error_type": "3",
|
|
|
- }
|
|
|
- //检查未通过
|
|
|
- scdNodeRule.AppendFcdaCheckResult(re)
|
|
|
- } else if outFcdaDoi.(*node_attr.NDOI).Desc != doiDesc {
|
|
|
- //关联错误
|
|
|
- parse_result := fmt.Sprintf("间隔%s的装置%s端子%s与装置%s端子%s名称不匹配", area_name, iedname, doiDesc, outiedname, outFcdaDoi.(*node_attr.NDOI).Desc)
|
|
|
- re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
|
|
|
- "ied_name": iedname,
|
|
|
- "ied_desc": iedObj.Desc,
|
|
|
- "out_ied_name": outiedname,
|
|
|
- "out_ied_desc": outIedObj.Desc,
|
|
|
- "fcda_desc": doiDesc,
|
|
|
- "fcda_addr": extref.IntAddr,
|
|
|
- "out_fcda_desc": outFcdaDoi.(*node_attr.NDOI).Desc,
|
|
|
- "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName, daname),
|
|
|
- "error_type": "2",
|
|
|
- }
|
|
|
- //检查未通过
|
|
|
- scdNodeRule.AppendFcdaCheckResult(re)
|
|
|
- }
|
|
|
+ }
|
|
|
+ //判断装置是否具备遥信功能,具备时需要单独处理遥信类端子
|
|
|
+ //遥信类端子处理规则:以scd中实际配置为准,通过检查装置双方的端子名称是否完全一致,以及是否有缺失和多余的遥信端子
|
|
|
+ if len(yx) > 0 && isDealYxIed[iedname] == 0 {
|
|
|
+ //logger.Logger.Debug(fmt.Sprintf("=============正在处理装置%s遥信端子数:%d %+v", iedname, len(yx), isDealYxIed))
|
|
|
+ isDealYxIed[iedname] = 1
|
|
|
+ for extref, doiDesc := range yx {
|
|
|
+ daname := ""
|
|
|
+ if extref.DaName != "" {
|
|
|
+ daname = "." + extref.DaName
|
|
|
+ }
|
|
|
+ //获取输出端端子名称
|
|
|
+ outFcdaDoi, _ := scdNodeRule.IedFcdaExist(extref.IedName, extref.LdInst, extref.LnClass, extref.LnInst, extref.Prefix, extref.DoName, extref.DaName)
|
|
|
+ tmpIedObj := scdNodeMgr.GetIed(scdXmlObj, scdidStr, extref.IedName)
|
|
|
+ if tmpIedObj == nil || outFcdaDoi == nil {
|
|
|
+ //端子缺失
|
|
|
+ parse_result := fmt.Sprintf("间隔%s的装置%s遥信端子%s的关联端子不存在", area_name, iedname, doiDesc)
|
|
|
+ re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
|
|
|
+ "ied_name": iedname,
|
|
|
+ "ied_desc": iedObj.Desc,
|
|
|
+ "out_ied_name": tmpIedObj.Name,
|
|
|
+ "out_ied_desc": tmpIedObj.Desc,
|
|
|
+ "fcda_desc": doiDesc,
|
|
|
+ "fcda_addr": extref.IntAddr,
|
|
|
+ "out_fcda_desc": "",
|
|
|
+ "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName, daname),
|
|
|
+ "error_type": "3",
|
|
|
}
|
|
|
+ //检查未通过
|
|
|
+ scdNodeRule.AppendFcdaCheckResult(re)
|
|
|
+ } else if outFcdaDoi.(*node_attr.NDOI).Desc != doiDesc {
|
|
|
+ //关联错误
|
|
|
+ parse_result := fmt.Sprintf("间隔%s的装置%s遥信端子%s与装置%s端子%s名称不匹配", area_name, iedname, doiDesc, tmpIedObj.Name, outFcdaDoi.(*node_attr.NDOI).Desc)
|
|
|
+ re := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result,
|
|
|
+ "ied_name": iedname,
|
|
|
+ "ied_desc": iedObj.Desc,
|
|
|
+ "out_ied_name": tmpIedObj.Name,
|
|
|
+ "out_ied_desc": tmpIedObj.Desc,
|
|
|
+ "fcda_desc": doiDesc,
|
|
|
+ "fcda_addr": extref.IntAddr,
|
|
|
+ "out_fcda_desc": outFcdaDoi.(*node_attr.NDOI).Desc,
|
|
|
+ "out_fcda_addr": fmt.Sprintf("%s/%s%s%s.%s%s", extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName, daname),
|
|
|
+ "error_type": "2",
|
|
|
+ }
|
|
|
+ //检查未通过
|
|
|
+ scdNodeRule.AppendFcdaCheckResult(re)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ yxAddrMap = nil
|
|
|
+ extreflist = nil
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ isLoadYxIed = nil
|
|
|
+ isDealYxIed = nil
|
|
|
scdNodeRule.CheckFinish()
|
|
|
scdNodeRule.Flush()
|
|
|
return nil
|
|
@@ -1000,7 +1017,7 @@ func (c *CheckAreaMgr) ParseModelArea() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-//根据默认装置类型获取其类型编码。如果没有自定义编码,则返回默认编码
|
|
|
+//根据默认装置类型获取其类型编码。如果没有自定义编码,则返回默认编码。返回编码时已自动去除套别标识
|
|
|
func (c *CheckAreaMgr) getIedTypeCode(modelid int, iedtype string) string {
|
|
|
mapptype := new(SysCheckModelIedtypeMappingMgr)
|
|
|
mappresult := mapptype.GetMappingType(modelid, iedtype)
|
|
@@ -1008,7 +1025,7 @@ func (c *CheckAreaMgr) getIedTypeCode(modelid int, iedtype string) string {
|
|
|
if mappresult != "" {
|
|
|
ptCode = mappresult //自定义主变保护编码
|
|
|
}
|
|
|
- return ptCode
|
|
|
+ return strings.Split(ptCode, "-")[0]
|
|
|
}
|
|
|
|
|
|
//变压器间隔分析
|
|
@@ -1147,6 +1164,11 @@ func (c *CheckAreaMgr) pT(modelid int, iedtypes string, ieds map[string]orm.Para
|
|
|
delMm = true
|
|
|
continue
|
|
|
}
|
|
|
+ //判断是否指定的套别标识
|
|
|
+ abCode := c.getIedTypeABCode(tyCode)
|
|
|
+ if abCode != "" {
|
|
|
+ iednameParts[7] = abCode
|
|
|
+ }
|
|
|
//判断间隔是否需要包含差动装置
|
|
|
if strings.Contains(tyCode, "#C") {
|
|
|
_, iedname := getIedByDesc(ieds, tyCode, "差动")
|
|
@@ -1175,7 +1197,7 @@ func (c *CheckAreaMgr) pT(modelid int, iedtypes string, ieds map[string]orm.Para
|
|
|
}
|
|
|
dlIeds := []orm.Params{}
|
|
|
imtcode := c.getIedTypeCode(modelid, tyCode)
|
|
|
- h, m, l := c.getIedListByVol(imtcode, ieds, volMap)
|
|
|
+ h, m, l := c.getIedListByVol(imtcode, ieds, volMap, abCode)
|
|
|
//logger.Logger.Debug(fmt.Sprintf("tyCode:%s H:%+v,M:%+v,L:%+v", tyCode, h, m, l))
|
|
|
if volValue == "" || volValue == "H" {
|
|
|
dlIeds = append(dlIeds, h...)
|
|
@@ -1286,6 +1308,10 @@ func (c *CheckAreaMgr) pL(modelid int, vol, iedtypes string, ieds map[string]orm
|
|
|
//装置如果是分组成员装置,则不用检测
|
|
|
continue
|
|
|
}
|
|
|
+ abCode := c.getIedTypeABCode(tyCode)
|
|
|
+ if abCode != "" {
|
|
|
+ iednameParts[7] = abCode
|
|
|
+ }
|
|
|
if tyCode == pmCode {
|
|
|
//母线保护和母线合并单元装置编号跟随变压器
|
|
|
//查找变压器编号
|
|
@@ -1843,7 +1869,8 @@ func (c *CheckAreaMgr) cT(modelid string, scdXmlObj *node_attr.SCL, scdNodeMgr *
|
|
|
}
|
|
|
|
|
|
//根据参考ied name找出应该关联PM装置
|
|
|
-func (c *CheckAreaMgr) getPMName(iednameParts []string, ieds map[string]orm.Params) string {
|
|
|
+//abcode:套别标识代码。可选。不指定时将自动从iedtype识别
|
|
|
+func (c *CheckAreaMgr) getPMName(iednameParts []string, ieds map[string]orm.Params, abcode ...string) string {
|
|
|
//如果只有一个PM装置,则直接返回该 装置
|
|
|
pmLst := []string{}
|
|
|
for n, _ := range ieds {
|
|
@@ -1854,8 +1881,19 @@ func (c *CheckAreaMgr) getPMName(iednameParts []string, ieds map[string]orm.Para
|
|
|
if len(pmLst) == 1 {
|
|
|
return pmLst[0]
|
|
|
}
|
|
|
+ ab := ""
|
|
|
+ if len(abcode) > 0 {
|
|
|
+ ab = abcode[0]
|
|
|
+ }
|
|
|
//暴力匹配
|
|
|
for _, n := range pmLst {
|
|
|
+ if ab != "" {
|
|
|
+ //优先完全匹配指定套别
|
|
|
+ if strings.HasSuffix(n, ab) {
|
|
|
+ return n
|
|
|
+ }
|
|
|
+ continue
|
|
|
+ }
|
|
|
if strings.HasSuffix(n, iednameParts[7]) {
|
|
|
return n
|
|
|
}
|
|
@@ -1882,13 +1920,36 @@ func (c *CheckAreaMgr) getMMName(iednameParts []string, ieds map[string]orm.Para
|
|
|
return ""
|
|
|
}
|
|
|
|
|
|
+//获取装置编码中的套别代码(A、B..)
|
|
|
+func (c *CheckAreaMgr) getIedTypeABCode(iedtype string) string {
|
|
|
+ if strings.Index(iedtype, "-") > 0 {
|
|
|
+ return strings.Split(iedtype, "-")[1]
|
|
|
+ }
|
|
|
+ return iedtype
|
|
|
+}
|
|
|
+
|
|
|
//根据当前设备列表,分析出电压等级(高、中、低)的设备列表
|
|
|
// CT测控、IT智能终端、MT合并单元需要判断是否是本体装置,是则将其归为主变高压侧
|
|
|
-func (c *CheckAreaMgr) getIedListByVol(iedtype string, ieds map[string]orm.Params, vollevel map[string]string) (hightLst, middleLst, lowLst []orm.Params) {
|
|
|
+//iedtype:装置编码
|
|
|
+//ieds:装置筛选范围列表
|
|
|
+//vollevel:电压等级代码。H:高压 M:中压 L:低压
|
|
|
+//abcode:套别标识代码。可选。不指定时将自动从iedtype识别
|
|
|
+func (c *CheckAreaMgr) getIedListByVol(iedtype string, ieds map[string]orm.Params, vollevel map[string]string, abcode ...string) (hightLst, middleLst, lowLst []orm.Params) {
|
|
|
tmpLst := map[string][]orm.Params{}
|
|
|
for _, v := range vollevel {
|
|
|
tmpLst[v] = []orm.Params{}
|
|
|
}
|
|
|
+ ab := ""
|
|
|
+ if len(abcode) > 0 {
|
|
|
+ ab = abcode[0]
|
|
|
+ }
|
|
|
+ if strings.Index(iedtype, "-") > 0 {
|
|
|
+ //去除套别标识
|
|
|
+ iedtype = strings.Split(iedtype, "-")[0]
|
|
|
+ if ab == "" {
|
|
|
+ ab = strings.Split(iedtype, "-")[1]
|
|
|
+ }
|
|
|
+ }
|
|
|
it := strings.Split(iedtype, "#")
|
|
|
scdParseMgr := new(ScdParse)
|
|
|
for _, row := range ieds {
|
|
@@ -1897,6 +1958,10 @@ func (c *CheckAreaMgr) getIedListByVol(iedtype string, ieds map[string]orm.Param
|
|
|
continue
|
|
|
}
|
|
|
iednameParts := scdParseMgr.ParseIedName(pl_iedname)
|
|
|
+ if ab != "" && iednameParts[7] != ab {
|
|
|
+ //指定了套别时,装置套别必须与指定套别完全相同
|
|
|
+ continue
|
|
|
+ }
|
|
|
volvalue := iednameParts[3] + iednameParts[4]
|
|
|
if tmpLst[volvalue] == nil {
|
|
|
tmpLst[volvalue] = []orm.Params{row}
|