test_data/repository/test.data/chart.go

1258 lines
38 KiB
Go

package test_data
import (
"encoding/json"
"errors"
"github.com/shopspring/decimal"
"math"
"sort"
"strconv"
"testData/global"
"testData/model"
"testData/request"
)
// QuerySelection 查询可选择的参数
func QuerySelection(req *request.QuerySelection) map[string][]string {
return LotInMultipleFilesSelection(req.Product, req.Lot, req.PBI, req.Step, req.WaferID)
}
// Histogram 直方图
func Histogram(req *request.Histogram) ([]*model.Histogram, error) {
var fTHistogram []*model.Histogram
var x, groups []string
var xMax, xMin string
//var datas [][]string
//fieldMap := make(map[string]int)
if len(req.SubBatch) == 0 && len(req.WaferID) == 0 {
//datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI, req.Step)
groups = append(groups, "")
} else if len(req.SubBatch) != 0 {
groups = req.SubBatch
} else if len(req.WaferID) != 0 {
groups = req.WaferID
}
for _, group := range groups {
var datas [][]string
fieldMap := make(map[string]int)
if group == "" {
datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI, req.Step)
} else if len(req.SubBatch) != 0 {
datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, group, "", req.Step)
} else if len(req.WaferID) != 0 {
datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, "", group, req.Step)
}
left := req.Average - req.Offset*req.StandardDeviation
right := req.Average + req.Offset*req.StandardDeviation
for _, selection := range req.Selections {
if _, ok := fieldMap[selection]; !ok {
continue
}
if len(req.Site) == 0 {
var n float64
var sumSelection float64 = 0
// 计算最大值、最小值、标准差、均值、数量
//var standardDeviation float64
var maxValue, minValue string
for _, data := range datas {
selectionDecimal, _ := decimal.NewFromString(data[fieldMap[selection]])
if req.XMax != "" && req.XMin != "" {
xMaxDecimal, _ := decimal.NewFromString(req.XMax)
xMinDecimal, _ := decimal.NewFromString(req.XMin)
if !(selectionDecimal.LessThanOrEqual(xMaxDecimal) && xMinDecimal.LessThanOrEqual(selectionDecimal)) {
continue
}
}
if req.Offset != 0 {
leftDecimal := decimal.NewFromFloat(left)
rightDecimal := decimal.NewFromFloat(right)
if selectionDecimal.LessThan(leftDecimal) || rightDecimal.LessThan(selectionDecimal) {
continue
}
}
// 筛选SBin
var binInclude bool
if len(req.Bin) == 0 {
binInclude = true
} else {
for _, bin := range req.Bin {
if data[fieldMap["SOFT_BIN"]] == bin {
binInclude = true
break
}
}
}
if binInclude {
if data[fieldMap[selection]] != "" {
selectionData, _ := strconv.ParseFloat(data[fieldMap[selection]], 64)
sumSelection += selectionData
n++
//difference := sumSelection/n - selectionData
//standardDeviation += math.Pow(difference, 2)
if maxValue == "" {
maxValue = data[fieldMap[selection]]
} else {
maxDecimal, _ := strconv.ParseFloat(maxValue, 64)
if maxDecimal < selectionData {
maxValue = data[fieldMap[selection]]
}
}
if minValue == "" {
minValue = data[fieldMap[selection]]
} else {
minDecimal, _ := strconv.ParseFloat(minValue, 64)
if selectionData < minDecimal {
minValue = data[fieldMap[selection]]
}
}
if xMax == "" {
xMax = data[fieldMap[selection]]
} else {
maxDecimal, _ := strconv.ParseFloat(xMax, 64)
if maxDecimal < selectionData {
xMax = data[fieldMap[selection]]
}
}
if xMin == "" {
xMin = data[fieldMap[selection]]
} else {
minDecimal, _ := strconv.ParseFloat(xMin, 64)
if selectionData < minDecimal {
xMin = data[fieldMap[selection]]
}
}
}
}
}
averageFloat64 := sumSelection / n
//standardDeviation = math.Sqrt(standardDeviation / n)
var filed string
if group == "" {
filed = selection
} else {
filed = selection + "-" + group
}
fTHistogram = append(fTHistogram, &model.Histogram{
Field: filed,
Average: averageFloat64,
//StandardDeviation: standardDeviation,
Max: maxValue,
Min: minValue,
N: n,
})
} else {
for _, site := range req.Site {
var n float64
var sumSelection float64 = 0
// 计算最大值、最小值、标准差、均值、数量
//var standardDeviation float64
var maxValue, minValue string
for _, data := range datas {
selectionDecimal, _ := decimal.NewFromString(data[fieldMap[selection]])
if req.XMax != "" && req.XMin != "" {
xMaxDecimal, _ := decimal.NewFromString(req.XMax)
xMinDecimal, _ := decimal.NewFromString(req.XMin)
if !(selectionDecimal.LessThanOrEqual(xMaxDecimal) && xMinDecimal.LessThanOrEqual(selectionDecimal)) {
continue
}
}
if req.Offset != 0 {
leftDecimal := decimal.NewFromFloat(left)
rightDecimal := decimal.NewFromFloat(right)
if selectionDecimal.LessThan(leftDecimal) || rightDecimal.LessThan(rightDecimal) {
continue
}
}
// 筛选Site
var siteInclude bool
if data[fieldMap["SITE_NUM"]] == site {
siteInclude = true
}
// 筛选SBin
var binInclude bool
if len(req.Bin) == 0 {
binInclude = true
} else {
for _, bin := range req.Bin {
if data[fieldMap["SOFT_BIN"]] == bin {
binInclude = true
break
}
}
}
if siteInclude && binInclude {
if data[fieldMap[selection]] != "" {
selectionData, _ := strconv.ParseFloat(data[fieldMap[selection]], 64)
sumSelection += selectionData
n++
//difference := sumSelection/n - selectionData
//standardDeviation += math.Pow(difference, 2)
if maxValue == "" {
maxValue = data[fieldMap[selection]]
} else {
maxDecimal, _ := strconv.ParseFloat(maxValue, 64)
if maxDecimal < selectionData {
maxValue = data[fieldMap[selection]]
}
}
if minValue == "" {
minValue = data[fieldMap[selection]]
} else {
minDecimal, _ := strconv.ParseFloat(minValue, 64)
if selectionData < minDecimal {
minValue = data[fieldMap[selection]]
}
}
if xMax == "" {
xMax = data[fieldMap[selection]]
} else {
maxDecimal, _ := strconv.ParseFloat(xMax, 64)
if maxDecimal < selectionData {
xMax = data[fieldMap[selection]]
}
}
if xMin == "" {
xMin = data[fieldMap[selection]]
} else {
minDecimal, _ := strconv.ParseFloat(xMin, 64)
if selectionData < minDecimal {
xMin = data[fieldMap[selection]]
}
}
}
}
}
averageFloat64 := sumSelection / n
//standardDeviation = math.Sqrt(standardDeviation / n)
var filed string
if group == "" {
filed = selection + "-Site" + site
} else {
filed = selection + "-" + group + "-Site" + site
}
fTHistogram = append(fTHistogram, &model.Histogram{
Field: filed,
Average: averageFloat64,
//StandardDeviation: standardDeviation,
Max: maxValue,
Min: minValue,
N: n,
})
}
}
}
}
// 生成X坐标
if req.XMax != "" {
xMax = req.XMax
}
if req.XMin != "" {
xMin = req.XMin
}
//minDecimal, _ := strconv.ParseFloat(xMin, 64)
//maxDecimal, _ := strconv.ParseFloat(xMax, 64)
//interval := (maxDecimal - minDecimal) / 50
//for i := 0; i < 51; i++ {
// xPoint := strconv.FormatFloat(minDecimal+interval*float64(i), 'f', 6, 64)
// x = append(x, xPoint)
//}
minDecimal, _ := decimal.NewFromString(xMin)
if minDecimal.LessThan(decimal.NewFromInt(0)) {
minDecimal = minDecimal.RoundUp(0)
} else {
minDecimal = minDecimal.RoundDown(0)
}
maxDecimal, _ := decimal.NewFromString(xMax)
if maxDecimal.LessThan(decimal.NewFromInt(0)) {
maxDecimal = maxDecimal.RoundDown(0)
} else {
maxDecimal = maxDecimal.RoundUp(0)
}
interval := maxDecimal.Sub(minDecimal).Div(decimal.NewFromInt(50))
for i := 0; i < 51; i++ {
xPoint := minDecimal.Add(interval.Mul(decimal.NewFromInt(int64(i)))).String()
x = append(x, xPoint)
}
for _, group := range groups {
var datas [][]string
fieldMap := make(map[string]int)
if group == "" {
datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI, req.Step)
} else if len(req.SubBatch) != 0 {
datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, group, "", req.Step)
} else if len(req.WaferID) != 0 {
datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, "", group, req.Step)
}
for _, selection := range req.Selections {
if _, ok := fieldMap[selection]; !ok {
continue
}
if len(req.Site) == 0 {
var filed string
if group == "" {
filed = selection
} else {
filed = selection + "-" + group
}
var standardDeviation, average float64
var index int
for k, v := range fTHistogram {
if v.Field == filed {
average = v.Average
index = k
break
}
}
var y []string
counter := make(map[float64]int)
// 计算最大值、最小值、标准差、均值、数量
for _, data := range datas {
// 筛选SBin
var binInclude bool
if len(req.Bin) == 0 {
binInclude = true
} else {
for _, bin := range req.Bin {
if data[fieldMap["SOFT_BIN"]] == bin {
binInclude = true
break
}
}
}
if binInclude {
if data[fieldMap[selection]] != "" {
selectionData, _ := strconv.ParseFloat(data[fieldMap[selection]], 64)
standardDeviation += math.Pow(average-selectionData, 2)
counter[selectionData]++
}
}
}
fTHistogram[index].StandardDeviation = math.Sqrt(standardDeviation / fTHistogram[index].N)
for i := 0; i < len(x); i++ {
if i == len(x)-1 {
xFloat, _ := strconv.ParseFloat(x[i], 64)
if yValue, ok := counter[xFloat]; ok {
y = append(y, strconv.Itoa(yValue))
} else {
y = append(y, "0")
}
break
}
xPointMin, _ := decimal.NewFromString(x[i])
xPointMax, _ := decimal.NewFromString(x[i+1])
var yCounter float64 = 0
for k, v := range counter {
if xPointMin.LessThanOrEqual(decimal.NewFromFloat(k)) && decimal.NewFromFloat(k).LessThan(xPointMax) {
yCounter += float64(v)
}
}
yPoint := strconv.FormatFloat(yCounter, 'f', 0, 64)
y = append(y, yPoint)
}
fTHistogram[index].X = x
fTHistogram[index].Y = y
} else {
for _, site := range req.Site {
var filed string
if group == "" {
filed = selection + "-Site" + site
} else {
filed = selection + "-" + group + "-Site" + site
}
var standardDeviation, average float64
var index int
for k, v := range fTHistogram {
if v.Field == filed {
average = v.Average
index = k
break
}
}
var y []string
counter := make(map[float64]int)
for _, data := range datas {
// 筛选Site
var siteInclude bool
if data[fieldMap["SITE_NUM"]] == site {
siteInclude = true
}
// 筛选SBin
var binInclude bool
if len(req.Bin) == 0 {
binInclude = true
} else {
for _, bin := range req.Bin {
if data[fieldMap["SOFT_BIN"]] == bin {
binInclude = true
break
}
}
}
if siteInclude && binInclude {
if data[fieldMap[selection]] != "" {
selectionData, _ := strconv.ParseFloat(data[fieldMap[selection]], 64)
standardDeviation += math.Pow(average-selectionData, 2)
counter[selectionData]++
}
}
}
fTHistogram[index].StandardDeviation = math.Sqrt(standardDeviation / fTHistogram[index].N)
for i := 0; i < len(x); i++ {
if i == len(x)-1 {
xFloat, _ := strconv.ParseFloat(x[i], 64)
if yValue, ok := counter[xFloat]; ok {
y = append(y, strconv.Itoa(yValue))
} else {
y = append(y, "0")
}
break
}
xPointMin, _ := strconv.ParseFloat(x[i], 64)
xPointMax, _ := strconv.ParseFloat(x[i+1], 64)
var yCounter float64 = 0
for k, v := range counter {
if xPointMin <= k && k < xPointMax {
yCounter += float64(v)
}
}
yPoint := strconv.FormatFloat(yCounter, 'f', 0, 64)
y = append(y, yPoint)
}
fTHistogram[index].X = x
fTHistogram[index].Y = y
}
}
}
}
return fTHistogram, nil
}
// Scatter 散点图
func Scatter(req *request.Scatter) ([]*model.Scatter, model.ScatterLimit, model.ScatterLimit, error) {
var groups []string
if len(req.SubBatch) == 0 && len(req.WaferID) == 0 {
groups = append(groups, "")
} else if len(req.SubBatch) != 0 {
groups = req.SubBatch
} else if len(req.WaferID) != 0 {
groups = req.WaferID
}
// 判断子批次还是大批次查询数据
var datas [][]string
fieldMap := make(map[string]int)
if len(req.SubBatch) == 0 {
datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI, req.Step)
} else {
for _, group := range groups {
if len(req.SubBatch) != 0 {
groupDatas, groupFieldMap := LotInAFile(req.Product, req.Lot, req.PBI, group, "", req.Step)
datas = append(datas, groupDatas...)
fieldMap = groupFieldMap
} else {
groupDatas, groupFieldMap := LotInAFile(req.Product, req.Lot, req.PBI, "", group, req.Step)
datas = append(datas, groupDatas...)
fieldMap = groupFieldMap
}
}
}
var scatters []*model.Scatter
var xScatterLimit, yScatterLimit model.ScatterLimit
if len(req.Site) == 0 {
scatterFieldMap := make(map[string]int)
counter := make(map[string]map[string]int)
for _, data := range datas {
// 筛选SBin
var binInclude bool
if len(req.Bin) == 0 {
binInclude = true
} else {
for _, bin := range req.Bin {
if data[fieldMap["SOFT_BIN"]] == bin {
binInclude = true
break
}
}
}
if binInclude {
for _, xySelection := range req.XYSelection {
if data[fieldMap[xySelection.X]] == "" || data[fieldMap[xySelection.Y]] == "" {
continue
}
if _, ok := counter[xySelection.X+","+xySelection.Y]; !ok {
counter[xySelection.X+","+xySelection.Y] = map[string]int{}
}
// 过滤重复点
needAppend := true
coordinate := data[fieldMap[xySelection.X]] + "," + data[fieldMap[xySelection.Y]]
if _, ok := counter[xySelection.X+","+xySelection.Y][coordinate]; ok {
needAppend = false
}
if needAppend {
counter[xySelection.X+","+xySelection.Y][coordinate]++
if _, ok := scatterFieldMap[xySelection.X+","+xySelection.Y]; !ok {
scatter := &model.Scatter{
Field: xySelection.X + "," + xySelection.Y + " All Site", Datas: [][]string{}}
scatterFieldMap[xySelection.X+","+xySelection.Y] = len(scatters)
scatters = append(scatters, scatter)
}
scatters[scatterFieldMap[xySelection.X+","+xySelection.Y]].Datas = append(
scatters[scatterFieldMap[xySelection.X+","+xySelection.Y]].Datas,
[]string{data[fieldMap[xySelection.X]], data[fieldMap[xySelection.Y]]})
if xScatterLimit.Min == "" {
xScatterLimit.Min = data[fieldMap[xySelection.X]]
} else {
xScatterLimitFloat, _ := strconv.ParseFloat(xScatterLimit.Min, 8)
dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.X]], 8)
if xScatterLimitFloat > dataFloat {
xScatterLimit.Min = data[fieldMap[xySelection.X]]
}
}
if xScatterLimit.Max == "" {
xScatterLimit.Max = data[fieldMap[xySelection.X]]
} else {
xScatterLimitFloat, _ := strconv.ParseFloat(xScatterLimit.Max, 8)
dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.X]], 8)
if xScatterLimitFloat < dataFloat {
xScatterLimit.Max = data[fieldMap[xySelection.X]]
}
}
if yScatterLimit.Min == "" {
yScatterLimit.Min = data[fieldMap[xySelection.Y]]
} else {
yScatterLimitFloat, _ := strconv.ParseFloat(yScatterLimit.Min, 8)
dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.Y]], 8)
if yScatterLimitFloat > dataFloat {
yScatterLimit.Min = data[fieldMap[xySelection.Y]]
}
}
if yScatterLimit.Max == "" {
yScatterLimit.Max = data[fieldMap[xySelection.Y]]
} else {
yScatterLimitFloat, _ := strconv.ParseFloat(yScatterLimit.Max, 8)
dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.Y]], 8)
if yScatterLimitFloat < dataFloat {
yScatterLimit.Max = data[fieldMap[xySelection.Y]]
}
}
}
}
}
}
} else {
scatterFieldMap := make(map[string]int)
for _, site := range req.Site {
counter := make(map[string]map[string]int)
for _, data := range datas {
// 筛选Site
if data[fieldMap["SITE_NUM"]] != site {
continue
}
// 筛选SBin
var binInclude bool
if len(req.Bin) == 0 {
binInclude = true
} else {
for _, bin := range req.Bin {
if data[fieldMap["SOFT_BIN"]] == bin {
binInclude = true
break
}
}
}
if binInclude {
for _, xySelection := range req.XYSelection {
if data[fieldMap[xySelection.X]] == "" || data[fieldMap[xySelection.Y]] == "" {
continue
}
if _, ok := counter[xySelection.X+","+xySelection.Y]; !ok {
counter[xySelection.X+","+xySelection.Y] = map[string]int{}
}
// 过滤重复点
needAppend := true
coordinate := data[fieldMap[xySelection.X]] + "," + data[fieldMap[xySelection.Y]]
if _, ok := counter[xySelection.X+","+xySelection.Y][coordinate]; ok {
needAppend = false
}
if needAppend {
counter[xySelection.X+","+xySelection.Y][coordinate]++
if _, ok := scatterFieldMap[xySelection.X+","+xySelection.Y]; !ok {
scatter := &model.Scatter{
Field: xySelection.X + "," + xySelection.Y + "-Site" + site, Datas: [][]string{}}
scatterFieldMap[xySelection.X+","+xySelection.Y] = len(scatters)
scatters = append(scatters, scatter)
}
scatters[scatterFieldMap[xySelection.X+","+xySelection.Y]].Datas = append(
scatters[scatterFieldMap[xySelection.X+","+xySelection.Y]].Datas,
[]string{data[fieldMap[xySelection.X]], data[fieldMap[xySelection.Y]]})
if xScatterLimit.Min == "" {
xScatterLimit.Min = data[fieldMap[xySelection.X]]
} else {
xScatterLimitFloat, _ := strconv.ParseFloat(xScatterLimit.Min, 8)
dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.X]], 8)
if xScatterLimitFloat > dataFloat {
xScatterLimit.Min = data[fieldMap[xySelection.X]]
}
}
if xScatterLimit.Max == "" {
xScatterLimit.Max = data[fieldMap[xySelection.X]]
} else {
xScatterLimitFloat, _ := strconv.ParseFloat(xScatterLimit.Max, 8)
dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.X]], 8)
if xScatterLimitFloat < dataFloat {
xScatterLimit.Max = data[fieldMap[xySelection.X]]
}
}
if yScatterLimit.Min == "" {
yScatterLimit.Min = data[fieldMap[xySelection.Y]]
} else {
yScatterLimitFloat, _ := strconv.ParseFloat(yScatterLimit.Min, 8)
dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.Y]], 8)
if yScatterLimitFloat > dataFloat {
yScatterLimit.Min = data[fieldMap[xySelection.Y]]
}
}
if yScatterLimit.Max == "" {
yScatterLimit.Max = data[fieldMap[xySelection.Y]]
} else {
yScatterLimitFloat, _ := strconv.ParseFloat(yScatterLimit.Max, 8)
dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.Y]], 8)
if yScatterLimitFloat < dataFloat {
yScatterLimit.Max = data[fieldMap[xySelection.Y]]
}
}
}
}
}
}
}
}
return scatters, xScatterLimit, yScatterLimit, nil
}
func Pie(req *request.Pie) ([]*model.Pie, error) {
var pie []*model.Pie
var datas [][]string
fieldMap := make(map[string]int)
if req.SubBatch == "" {
datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI, req.Step)
} else {
datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, req.SubBatch, req.Step, req.Step)
}
if _, ok := fieldMap[req.Selection]; !ok {
return nil, errors.New("不存在该参数")
}
m := make(map[string]int)
if req.Min == "" {
req.Min = "0"
}
if req.Max == "" {
req.Max = "0"
}
minDecimal, _ := decimal.NewFromString(req.Min)
maxDecimal, _ := decimal.NewFromString(req.Max)
for _, data := range datas {
var siteInclude bool
if len(req.Site) == 0 {
siteInclude = true
} else {
for _, site := range req.Site {
if data[fieldMap["SITE_NUM"]] == site {
siteInclude = true
break
}
}
}
var binInclude bool
if len(req.Bin) == 0 {
binInclude = true
} else {
for _, bin := range req.Bin {
if data[fieldMap["SOFT_BIN"]] == bin {
binInclude = true
break
}
}
}
if siteInclude && binInclude {
if data[fieldMap[req.Selection]] == "" {
data[fieldMap[req.Selection]] = "0"
}
selectionDecimal, _ := decimal.NewFromString(data[fieldMap[req.Selection]])
if minDecimal.LessThanOrEqual(selectionDecimal) && selectionDecimal.LessThanOrEqual(maxDecimal) {
var isValid bool
for _, interval := range req.PieInterval {
if interval.Min == "" {
interval.Min = "0"
}
if interval.Max == "" {
interval.Max = "0"
}
minIntervalDecimal, _ := decimal.NewFromString(interval.Min)
maxIntervalDecimal, _ := decimal.NewFromString(interval.Max)
if minIntervalDecimal.LessThanOrEqual(selectionDecimal) && selectionDecimal.LessThan(maxIntervalDecimal) {
m[interval.Name]++
isValid = true
break
}
}
if !isValid {
m["else"]++
}
}
}
}
for k, v := range m {
pie = append(pie, &model.Pie{
Name: k,
Value: v,
})
}
return pie, nil
}
func Line(req *request.Line) (*model.Line, error) {
var datas [][]string
fieldMap := make(map[string]int)
if req.SubBatch == "" {
datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI, req.Step)
} else {
datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, req.SubBatch, req.Step, req.Lot)
}
var x, y []string
for index, data := range datas {
var siteInclude bool
if len(req.Site) == 0 {
siteInclude = true
} else {
for _, site := range req.Site {
if data[fieldMap["SITE_NUM"]] == site {
siteInclude = true
break
}
}
}
var binInclude bool
if len(req.Bin) == 0 {
binInclude = true
} else {
for _, bin := range req.Bin {
if data[fieldMap["SOFT_BIN"]] == bin {
binInclude = true
break
}
}
}
if siteInclude && binInclude {
x = append(x, strconv.Itoa(index))
y = append(y, data[fieldMap[req.Selection]])
}
}
lineChart := &model.Line{
X: x,
Y: y,
}
return lineChart, nil
}
// CPMap CP晶圆图
func CPMap(req *request.CPMap) (map[string]interface{}, error) {
// 需要显示的参数
selections := []string{"SITE_NUM", "SOFT_BIN", "HARD_BIN"}
if len(req.Selection) > 0 {
selections = append(selections, req.Selection[0])
}
// CP测试没有子批次
var fileHandle *model.FileHandled
global.PostGreSQL.Where("pbi = ? AND product = ? AND lot = ? AND wafer_id = ? AND step LIKE ?",
req.PBI, req.Product, req.Lot, req.WaferID, "%"+req.Step+"%").
Find(&fileHandle)
//f, err := os.Open(fileHandle.Path)
//if err != nil {
// log.Println(err)
// return nil, err
//}
//defer f.Close()
//scanner := bufio.NewScanner(f)
//datas := make([][]string, 0)
//fieldMap := make(map[string]int)
//for scanner.Scan() {
// line := scanner.Text()
// s := strings.Split(line, ",")
// datas = append(datas, s[:len(s)-1])
// if len(datas) == 1 {
// for index, cell := range s {
// if index == len(s)-1 {
// continue
// }
// fieldMap[cell] = index
// }
// }
//}
//if len(datas) >= 1 {
// datas = datas[1:]
//}
datas, fieldMap := LotInAFile(req.Product, req.Lot, req.PBI, "", req.WaferID, req.Step)
//sbinHbinMap := make(map[string]map[string]string)
sbinHbinMap := make(map[string]string)
res := make(map[string]interface{})
resDatas := make([]map[string]interface{}, 0)
selectDatas := make(map[string]interface{})
// 颜色、标题、数据数组初始化
color := []string{"#4FFF00", "#FF0000", "#1B81FF", "#FF0000", "#E12AE8"}
datasTitle := []string{"第一次测试Pass", "第一次测试Fail", "复测Pass", "复测Fail", "复测Fail变动"}
selectDatas["第一次测试Pass"] = [][]string{}
selectDatas["第一次测试Fail"] = [][]string{}
selectDatas["复测Pass"] = [][]string{}
selectDatas["复测Fail"] = [][]string{}
selectDatas["复测Fail变动"] = [][]string{}
for _, sBinColor := range req.SBinColor {
color = append(color, sBinColor.Color)
datasTitle = append(datasTitle, sBinColor.Name)
selectDatas[sBinColor.Name] = [][]string{}
}
for _, hBinColor := range req.HBinColor {
color = append(color, hBinColor.Color)
datasTitle = append(datasTitle, hBinColor.Name)
selectDatas[hBinColor.Name] = [][]string{}
}
for _, selectionColor := range req.SelectionColor {
color = append(color, selectionColor.Color)
datasTitle = append(datasTitle, selectionColor.Name+":"+selectionColor.Min+"~"+selectionColor.Max)
selectDatas[selectionColor.Name+":"+selectionColor.Min+"~"+selectionColor.Max] = [][]string{}
}
sbinHbinByte := []byte(fileHandle.SbinHbin)
_ = json.Unmarshal(sbinHbinByte, &sbinHbinMap)
passArray := selectDatas["复测Pass"].([][]string)
failArray := selectDatas["复测Fail"].([][]string)
failChangeArray := selectDatas["复测Fail变动"].([][]string)
lastPassArray := selectDatas["第一次测试Pass"].([][]string)
lastFailArray := selectDatas["第一次测试Fail"].([][]string)
var total, pass float64
binMap := make(map[string]int)
sbinColorMap := make(map[string]int)
hbinColorMap := make(map[string]int)
selectionColorMap := make(map[string]int)
for _, data := range datas {
var softBinName string
if req.Step == "CP1+CP2" && data[fieldMap["SOFT_BIN_CP2"]] != "" {
softBinName = "SOFT_BIN_CP2"
} else {
softBinName = "SOFT_BIN"
}
//binInfoMap := sbinHbinMap[data[fieldMap[softBinName]]]
// 筛选Site
var siteInclude bool
if len(req.Site) == 0 {
siteInclude = true
} else {
for _, site := range req.Site {
if data[fieldMap["SITE_NUM"]] == site {
siteInclude = true
break
}
}
}
if !siteInclude {
continue
}
// 筛选Soft Bin
var sBinInclude bool
if len(req.SBin) == 0 {
sBinInclude = true
} else {
for _, bin := range req.SBin {
if data[fieldMap[softBinName]] == bin {
sBinInclude = true
break
}
}
}
if !sBinInclude {
continue
}
// 筛选Hard Bin
var hBinInclude bool
if len(req.HBin) == 0 {
hBinInclude = true
} else {
for _, bin := range req.HBin {
//if binInfoMap["HBin"] == bin {
// hBinInclude = true
// break
//}
if sbinHbinMap[data[fieldMap[softBinName]]] == bin {
hBinInclude = true
break
}
}
}
if !hBinInclude {
continue
}
// 将HBin写入单行信息内
//data = append(data, binInfoMap["HBin"])
x := data[fieldMap["X_COORD"]]
y := data[fieldMap["Y_COORD"]]
//data[fieldMap["PASSFG"]] = strings.ToLower(data[fieldMap["PASSFG"]])
// 判断测试点是否通过测试
var isPass bool
if data[fieldMap[softBinName]] == "1" {
isPass = true
}
// 需要显示的参数
var field []string
for _, selection := range selections {
var dataValue string
if selection == "HARD_BIN" {
dataValue = sbinHbinMap[data[fieldMap[softBinName]]]
//dataValue = binInfoMap["HBin"]
field = append(field, []string{selection, dataValue}...)
continue
}
if _, ok := fieldMap[selection]; !ok {
dataValue = "0"
} else {
dataValue = data[fieldMap[selection]]
}
field = append(field, []string{selection, dataValue}...)
}
// 区分通过、不通过、第一次测试数据
var isSamePoint bool
var isFinal bool
for _, lastPoint := range lastFailArray {
if lastPoint[0] == x && lastPoint[1] == y {
if isPass {
passArray = append(passArray, append([]string{x, y}, field...))
} else {
var isChangeFail bool
for lastPointFieldIndex := 2; lastPointFieldIndex < len(lastPoint); lastPointFieldIndex++ {
if lastPoint[lastPointFieldIndex] == "SOFT_BIN" {
for pointFieldIndex := 2; pointFieldIndex < len(field); pointFieldIndex++ {
if field[pointFieldIndex] == "SOFT_BIN" && lastPoint[lastPointFieldIndex+1] != field[pointFieldIndex+1] {
isChangeFail = true
}
}
}
}
if isChangeFail {
failArray = append(failArray, append([]string{x, y}, field...))
failChangeArray = append(failChangeArray, append([]string{x, y}, field...))
} else {
failArray = append(failArray, append([]string{x, y}, field...))
}
}
isFinal = true
isSamePoint = true
break
}
}
if !isSamePoint {
if isPass {
lastPassArray = append(lastPassArray, append([]string{x, y}, field...))
isFinal = true
} else {
lastFailArray = append(lastFailArray, append([]string{x, y}, field...))
isFinal = true
}
}
if isFinal {
total++
if isPass {
pass++
}
binMap[data[fieldMap[softBinName]]]++
sbinColorMap[data[fieldMap[softBinName]]]++
hbinColorMap[sbinHbinMap[data[fieldMap[softBinName]]]]++
//hbinColorMap[binInfoMap["HBin"]]++
// 根据SOFT_BIN区分颜色
for _, sBinColor := range req.SBinColor {
array := selectDatas[sBinColor.Name].([][]string)
var isReplace bool
for _, point := range array {
if point[0] == x && point[1] == y {
point = append([]string{x, y}, field...)
isReplace = true
break
}
}
if !isReplace && data[fieldMap[softBinName]] == sBinColor.Name {
array = append(array, append([]string{x, y}, field...))
selectDatas[sBinColor.Name] = array
break
}
}
// 根据HARD_BIN区分颜色
for _, hBinColor := range req.HBinColor {
array := selectDatas[hBinColor.Name].([][]string)
var isReplace bool
for _, point := range array {
if point[0] == x && point[1] == y {
point = append([]string{x, y}, field...)
isReplace = true
break
}
}
if !isReplace && sbinHbinMap[data[fieldMap[softBinName]]] == hBinColor.Name {
array = append(array, append([]string{x, y}, field...))
selectDatas[hBinColor.Name] = array
break
}
//if !isReplace && binInfoMap["HBin"] == hBinColor.Name {
// array = append(array, append([]string{x, y}, field...))
// selectDatas[hBinColor.Name] = array
// break
//}
}
// 根据参数范围区分颜色
for _, selectionColor := range req.SelectionColor {
if data[fieldMap[selectionColor.Name]] == "" {
break
}
selection, _ := decimal.NewFromString(data[fieldMap[selectionColor.Name]])
max, _ := decimal.NewFromString(selectionColor.Max)
min, _ := decimal.NewFromString(selectionColor.Min)
if selection.LessThanOrEqual(max) && min.LessThanOrEqual(selection) {
s := selectionColor.Name + ":" + selectionColor.Min + "~" + selectionColor.Max
selectionColorMap[s]++
array := selectDatas[s].([][]string)
var isReplace bool
for _, point := range array {
if point[0] == x && point[1] == y {
point = append([]string{x, y}, field...)
isReplace = true
selectDatas[s] = array
break
}
}
if !isReplace {
array = append(array, append([]string{x, y}, field...))
selectDatas[s] = array
break
}
}
//selection, _ := strconv.ParseFloat(data[fieldMap[selectionColor.Name]], 8)
//max, _ := strconv.ParseFloat(selectionColor.Max, 8)
//min, _ := strconv.ParseFloat(selectionColor.Min, 8)
//if selection <= max && min <= selection {
// selectionColorMap[selectionColor.Name]++
// s := selectionColor.Name + ":" + selectionColor.Min + "~" + selectionColor.Max
// array := selectDatas[s].([][]string)
// var isReplace bool
// for _, point := range array {
// if point[0] == x && point[1] == y {
// point = append([]string{x, y}, field...)
// isReplace = true
// selectDatas[s] = array
// break
// }
// }
// if !isReplace {
// array = append(array, append([]string{x, y}, field...))
// selectDatas[s] = array
// break
// }
//}
}
}
}
selectDatas["复测Pass"] = passArray
selectDatas["复测Fail"] = failArray
selectDatas["复测Fail变动"] = failChangeArray
selectDatas["第一次测试Pass"] = lastPassArray
selectDatas["第一次测试Fail"] = lastFailArray
// 将根据标题顺序存入数组
for _, v := range datasTitle {
resDatas = append(resDatas, map[string]interface{}{
"name": v,
"data": selectDatas[v],
})
}
res["color"] = color
res["datas_title"] = datasTitle
res["datas"] = resDatas
totalDecimal := decimal.NewFromFloat(total)
passDecimal := decimal.NewFromFloat(pass)
res["Total"] = totalDecimal.String()
if !totalDecimal.IsZero() {
res["PassProbability"] = passDecimal.Div(totalDecimal).Round(4).Mul(decimal.NewFromInt(100)).String() + "%"
}
var binArray []string
for bin := range binMap {
binArray = append(binArray, bin)
}
sort.Slice(binArray, func(i, j int) bool {
return binMap[binArray[i]] > binMap[binArray[j]]
})
var binProbability [][]string
for _, bin := range binArray {
binDecimal := decimal.NewFromInt(int64(binMap[bin]))
probability := "0%"
if !totalDecimal.IsZero() {
probability = binDecimal.Div(totalDecimal).Round(4).Mul(decimal.NewFromInt(100)).String() + "%"
}
binProbability = append(binProbability, []string{"BIN " + bin, probability, strconv.Itoa(binMap[bin])})
}
res["Bin情况"] = binProbability
res["Sbin数量"] = sbinColorMap
res["Hbin数量"] = hbinColorMap
res["参数数量"] = selectionColorMap
return res, nil
}
// CPMap CP晶圆图
func AllCPMap(req *request.CPMap) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
var fileHandles []*model.FileHandled
if len(req.WaferIDS) == 0 {
global.PostGreSQL.Where("product = ? AND lot = ? AND step = ?", req.Product, req.Lot, req.Step).
Order("wafer_id").Find(&fileHandles)
} else {
global.PostGreSQL.Where("product = ? AND lot = ? AND step = ? AND wafer_id IN ?",
req.Product, req.Lot, req.Step, req.WaferIDS).Order("wafer_id").Find(&fileHandles)
}
for _, fileHandle := range fileHandles {
//cpMap, err := CPMap(&request.CPMap{
// PBI: fileHandle.PBI,
// Product: req.Product,
// Lot: req.Lot,
// WaferID: fileHandle.WaferID,
// Step: req.Step,
//})
//if err != nil {
// log.Println(err)
//}
//res = append(res, cpMap)
//fmt.Println(cpMap)
_, err := strconv.Atoi(fileHandle.WaferID)
if err != nil {
continue
}
res = append(res, map[string]interface{}{
"pbi": fileHandle.PBI,
"product": req.Product,
"lot": req.Lot,
"wafer_id": fileHandle.WaferID,
"step": req.Step,
})
}
return res
}
func LogSiteChart(req *request.LogSiteChart) *model.Histogram {
//var fileHandle *model.FileHandled
//global.PostGreSQL.Where("product = ? AND sub_batch = ?", req.Product, req.SubBatch).Find(&fileHandle)
var datas [][]string
fieldMap := make(map[string]int)
if req.SubBatch == "" {
datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI, req.Step)
} else {
datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, req.SubBatch, req.Step, req.Step)
}
var x []string
for _, v := range req.Site {
x = append(x, "Site"+v)
}
var y []string
if req.ContentType == "数量" {
counter := make(map[string]int)
for _, data := range datas {
counter[data[fieldMap["SITE_NUM"]]]++
}
for _, v := range req.Site {
y = append(y, strconv.Itoa(counter[v]))
}
//y = append(y, strconv.Itoa(counter["Site1"]), strconv.Itoa(counter["Site2"]), strconv.Itoa(counter["Site3"]), strconv.Itoa(counter["Site4"]))
} else if req.ContentType == "良率" {
counter := make(map[string]int)
passCounter := make(map[string]int)
for _, data := range datas {
counter[data[fieldMap["SITE_NUM"]]]++
if data[fieldMap["PASSFG"]] == "True" {
passCounter[data[fieldMap["SITE_NUM"]]]++
}
}
for _, v := range x {
counterDecimal := decimal.NewFromInt(int64(counter[v]))
passCounterDecimal := decimal.NewFromInt(int64(passCounter[v]))
s := passCounterDecimal.Div(counterDecimal).Round(4).Mul(decimal.NewFromInt(10000)).String()
if s == "0" {
y = append(y, "0%")
continue
}
s = s[:2] + "." + s[2:] + "%"
y = append(y, s)
}
} else if req.ContentType == "参数均值" {
counter := make(map[string]int)
sum := make(map[string]string)
for _, data := range datas {
if len(req.Bin) != 0 {
var isContain bool
for _, bin := range req.Bin {
if data[fieldMap["SOFT_BIN"]] == bin {
isContain = true
break
}
}
if !isContain {
continue
}
}
counter[data[fieldMap["SITE_NUM"]]]++
if data[fieldMap[req.Selection]] == "" {
data[fieldMap[req.Selection]] = "0"
}
if sum[data[fieldMap["SITE_NUM"]]] == "" {
sum[data[fieldMap["SITE_NUM"]]] = "0"
}
selectionDecimal, _ := decimal.NewFromString(data[fieldMap[req.Selection]])
sumDecimal, _ := decimal.NewFromString(sum[data[fieldMap["SITE_NUM"]]])
sum[data[fieldMap["SITE_NUM"]]] = sumDecimal.Add(selectionDecimal).String()
}
for _, v := range req.Site {
counterDecimal := decimal.NewFromInt(int64(counter[v]))
passCounterDecimal, _ := decimal.NewFromString(sum[v])
s := passCounterDecimal.Div(counterDecimal).Round(4).String()
y = append(y, s)
}
}
return &model.Histogram{
X: x,
Y: y,
}
}