package group import ( "encoding/json" "fmt" "gitea.anxinyun.cn/container/common_models" "gitea.anxinyun.cn/container/common_models/constant/settlementParam" "log" "time" ) // 沉降分组业务处理说明: // dimensionId 对应WEB端配置:组网配置/采集策略 // taskId是维度下的schema每次调用的时候,生成一个唯一的 // 分组配置要求:分组计算中的测点的【采集策略】同一个周期采集 // 特殊场景:上报类测点,要进行分组计算,需要在协议里处理,输出_acq_number确保一致 type CalcTask struct { *BaseDueTask stationGroup *common_models.StationGroup dimensionId string // 第一个测点归属的采集维度 taskId string acqTime time.Time stationMap map[int]common_models.Station } func NewGroupCalcTask(group *common_models.StationGroup, dimensionId string, taskId string, acqTime time.Time) *CalcTask { return &CalcTask{ BaseDueTask: NewBaseDueTask(), stationGroup: group, dimensionId: dimensionId, taskId: taskId, acqTime: acqTime, stationMap: make(map[int]common_models.Station), } } func (t *CalcTask) AddStationData(data common_models.Station) { if data.Data.ThemeData == nil || len(data.Data.ThemeData) == 0 { return } t.stationMap[data.Info.Id] = data } func (t *CalcTask) GetStationData(stationId int) *common_models.Station { if station, ok := t.stationMap[stationId]; ok { return &station } return nil } // CheckIntegrity 检查计算项是否完整 func (t *CalcTask) CheckIntegrity() bool { for _, item := range t.stationGroup.AllCorrItems() { if _, ok := t.stationMap[item.StationId]; !ok { return false } } return true } // SetTimeout 根据第一个测点归属的采集维度类型,设置任务超时时长 func (t *CalcTask) SetTimeout() int { var expireSeconds int if t.stationMap == nil || len(t.stationMap) == 0 { expireSeconds = DefaultExpire() } if t.dimensionId == "" { expireSeconds = DefaultExpire() } else { expireSeconds = FromDimension(t.dimensionId) } t.SetDeadLineTime(expireSeconds) return expireSeconds } // ToDump 输出分组计算信息 func (t *CalcTask) ToDump() string { corrItemsBytes, err := json.Marshal(t.stationGroup.AllCorrItems()) if err != nil { fmt.Println("[et_calc.group.CalcTask.ToDump()] Error marshalling JSON:", err) } return fmt.Sprintf("【groupId:%d taskId:%s acqTime:%s】 %d/%v", t.stationGroup.Id, t.taskId, t.acqTime, len(t.stationMap), string(corrItemsBytes)) } // Calc 沉降分组计算 TODO 计算完成后返回分组的数据(要重新定义结构体) func (t *CalcTask) Calc() []common_models.Station { // 基点信息异常时数据处理:将 themeData 转储到 phyData, 再将 themeData 设置为 map[string]any{}; funcSetErrorData := func() []common_models.Station { var result []common_models.Station for _, objStation := range t.stationMap { objStation.Data.PyhData = objStation.Data.ThemeData objStation.Data.ThemeData = map[string]any{} result = append(result, objStation) } return result } var resultStations []common_models.Station baseItem := t.stationGroup.GetSettlementBaseItem() if baseItem == nil || t.stationMap[baseItem.StationId].Info.Id == 0 { // 无基点的分组数据处理 return funcSetErrorData() } else { // 有基点,进行减基点计算 baseStation := t.stationMap[baseItem.StationId] _, ok := baseStation.Data.GetValidThemeData() if !ok { log.Printf("基点数据计算失败,无效的主题数据。%s\n", baseStation.LogMsg()) return funcSetErrorData() } // baseValidFields 有效的监测项,主题数据的 field 必须在监测原型中存在 base_themeData_fields := baseStation.Data.GetThemeFields() base_proto_fields := baseStation.GetProtoFields() baseValidFields, ok := t.filterFields(base_themeData_fields, base_proto_fields) if !ok { log.Printf("基点数据计算失败,无效的监测项(数据 field 必须在监测原型中存在)。%s\n", baseStation.LogMsg()) return funcSetErrorData() } // 基点数据(包含虚拟基点的计算) virtualBase := t.calcVirtualSettlementBase(*baseItem, baseValidFields) if virtualBase == nil || len(virtualBase) == 0 { log.Printf("虚拟基点数据计算失败。%s\n", baseStation.LogMsg()) return funcSetErrorData() } // 减基点计算 for _, groupItem := range t.stationGroup.Items { objStation, ok := t.stationMap[groupItem.StationId] if !ok { continue } if groupItem.ParamsValue[settlementParam.Base] == true { // 基点主题数据处理 for key, _ := range virtualBase { objStation.Data.PyhData[key] = objStation.Data.ThemeData[key] objStation.Data.ThemeData[key] = 0.0 } } else { // 测点数据处理 themeData, ok := objStation.Data.GetValidThemeData() if !ok { log.Printf("减基点计算失败,无有效的主题数据。%s\n", objStation.LogMsg()) objStation.Data.PyhData = objStation.Data.ThemeData objStation.Data.ThemeData = map[string]any{} continue } // validFields 有效的监测项,主题数据的 field 必须在 baseValidFields 中存在 station_themeData_fields := objStation.Data.GetThemeFields() validFields, ok := t.filterFields(baseValidFields, station_themeData_fields) if !ok { log.Printf("基点数据计算失败,主题数据的 field 必须在 baseValidFields 中存在;"+ "baseValidFields:%v, station_themeData_fields:%v 。 %s\n", baseValidFields, station_themeData_fields, baseStation.LogMsg()) objStation.Data.PyhData = objStation.Data.ThemeData objStation.Data.ThemeData = map[string]any{} continue } // 减基点 var resultData map[string]any for _, field := range validFields { resultData[field] = virtualBase[field] - themeData[field] } objStation.Data.PyhData = objStation.Data.ThemeData objStation.Data.ThemeData = resultData } } // for t.stationGroup.Items } return resultStations } // calcVirtualSettlementBase 计算虚拟基点 // Result = Base + (RefB - RefS) // Base - 测量系统基点 // RefS - 远端参考系统测点 // RefB - 远端参考系统基点 func (t *CalcTask) calcVirtualSettlementBase(item common_models.GroupItem, fields []string) map[string]float64 { baseStation := t.stationMap[item.StationId] data, ok := baseStation.Data.GetValidThemeData() if !ok { log.Printf("基点无数据。%s\n", baseStation.LogMsg()) return make(map[string]float64) } // SubItem 为 nil,表示未参照任何分组,虚拟基点值等于自己 if item.SubItems == nil { result := make(map[string]float64) for _, f := range fields { result[f] = data[f] } return result } logMsg, _ := json.Marshal(item) log.Printf("级联分组:%s\n", string(logMsg)) refS := t.calcVirtualSettlementBase(item.SubItems[settlementParam.Ref_point], fields) refB := t.calcVirtualSettlementBase(item.SubItems[settlementParam.Ref_base], fields) if len(refS) == 0 || len(refB) == 0 { return make(map[string]float64) } result := make(map[string]float64) for _, f := range fields { // 虚拟基点 = 当前分组的基点测量值 + 参考点沉降 result[f] = data[f] + (refB[f] - refS[f]) } return result } // filterFields 过滤有效的数据项(交集操作) func (t *CalcTask) filterFields(arrA []string, arrB []string) ([]string, bool) { setA := make(map[string]bool) for _, a := range arrA { setA[a] = true } var result []string for _, b := range arrB { if setA[b] { result = append(result, b) } } return result, len(result) > 0 }