1406 lines
46 KiB
Go
1406 lines
46 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, []*model.HistogramLine, error) {
|
|
var fTHistogram []*model.Histogram
|
|
var fTHistogramLine []*model.HistogramLine
|
|
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)
|
|
|
|
if !req.MergeChart {
|
|
x = []string{}
|
|
minDecimal, _ = decimal.NewFromString(fTHistogram[index].Min)
|
|
maxDecimal, _ = decimal.NewFromString(fTHistogram[index].Max)
|
|
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 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 float64(v) > fTHistogram[index].MaxY {
|
|
fTHistogram[index].MaxY = float64(v)
|
|
fTHistogram[index].MaxYX = k
|
|
}
|
|
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)
|
|
|
|
if !req.MergeChart {
|
|
x = []string{}
|
|
minDecimal, _ = decimal.NewFromString(fTHistogram[index].Min)
|
|
maxDecimal, _ = decimal.NewFromString(fTHistogram[index].Max)
|
|
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 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 float64(v) > fTHistogram[index].MaxY {
|
|
fTHistogram[index].MaxY = float64(v)
|
|
fTHistogram[index].MaxYX = k
|
|
}
|
|
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
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for _, histogram := range fTHistogram {
|
|
var aFTHistogramLine model.HistogramLine
|
|
for _, histogramX := range histogram.X {
|
|
aFTHistogramLine.X = append(aFTHistogramLine.X, histogramX)
|
|
}
|
|
for _, histogramX := range histogram.X {
|
|
xDecimal, _ := decimal.NewFromString(histogramX)
|
|
xFloat, _ := xDecimal.Float64()
|
|
aFTHistogramLine.Y = append(aFTHistogramLine.Y, decimal.NewFromFloat(1).
|
|
Div(decimal.NewFromFloat(histogram.StandardDeviation*math.Sqrt(2*math.Pi))).
|
|
Mul(decimal.NewFromFloat(math.Exp(-1*math.Pow(xFloat-histogram.MaxYX, 2)/(2*math.Pow(histogram.StandardDeviation, 2))))).
|
|
String())
|
|
//histogram.Average
|
|
}
|
|
aFTHistogramLine.Field = histogram.Field
|
|
aFTHistogramLine.N = histogram.MaxYX
|
|
fTHistogramLine = append(fTHistogramLine, &aFTHistogramLine)
|
|
}
|
|
return fTHistogram, fTHistogramLine, 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 xScatterLimitArray, yScatterLimitArray []model.ScatterLimit
|
|
//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)
|
|
xScatterLimitArray = append(xScatterLimitArray, model.ScatterLimit{
|
|
Max: "",
|
|
Min: "",
|
|
})
|
|
yScatterLimitArray = append(yScatterLimitArray, model.ScatterLimit{
|
|
Max: "",
|
|
Min: "",
|
|
})
|
|
}
|
|
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 xScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Min == "" {
|
|
xScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Min = data[fieldMap[xySelection.X]]
|
|
} else {
|
|
xScatterLimitFloat, _ := strconv.ParseFloat(xScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Min, 8)
|
|
dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.X]], 8)
|
|
if xScatterLimitFloat > dataFloat {
|
|
xScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Min = data[fieldMap[xySelection.X]]
|
|
}
|
|
}
|
|
if xScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Max == "" {
|
|
xScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Max = data[fieldMap[xySelection.X]]
|
|
} else {
|
|
xScatterLimitFloat, _ := strconv.ParseFloat(xScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Max, 8)
|
|
dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.X]], 8)
|
|
if xScatterLimitFloat < dataFloat {
|
|
xScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Max = data[fieldMap[xySelection.X]]
|
|
}
|
|
}
|
|
if yScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Min == "" {
|
|
yScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Min = data[fieldMap[xySelection.Y]]
|
|
} else {
|
|
yScatterLimitFloat, _ := strconv.ParseFloat(yScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Min, 8)
|
|
dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.Y]], 8)
|
|
if yScatterLimitFloat > dataFloat {
|
|
yScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Min = data[fieldMap[xySelection.Y]]
|
|
}
|
|
}
|
|
if yScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Max == "" {
|
|
yScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Max = data[fieldMap[xySelection.Y]]
|
|
} else {
|
|
yScatterLimitFloat, _ := strconv.ParseFloat(yScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Max, 8)
|
|
dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.Y]], 8)
|
|
if yScatterLimitFloat < dataFloat {
|
|
yScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Max = 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+"-Site"+site]; !ok {
|
|
scatter := &model.Scatter{
|
|
Field: xySelection.X + "," + xySelection.Y + "-Site" + site, Datas: [][]string{}}
|
|
scatterFieldMap[xySelection.X+","+xySelection.Y+"-Site"+site] = len(scatters)
|
|
scatters = append(scatters, scatter)
|
|
xScatterLimitArray = append(xScatterLimitArray, model.ScatterLimit{
|
|
Max: "",
|
|
Min: "",
|
|
})
|
|
yScatterLimitArray = append(yScatterLimitArray, model.ScatterLimit{
|
|
Max: "",
|
|
Min: "",
|
|
})
|
|
}
|
|
scatters[scatterFieldMap[xySelection.X+","+xySelection.Y+"-Site"+site]].Datas = append(
|
|
scatters[scatterFieldMap[xySelection.X+","+xySelection.Y+"-Site"+site]].Datas,
|
|
[]string{data[fieldMap[xySelection.X]], data[fieldMap[xySelection.Y]]})
|
|
//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 xScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Min == "" {
|
|
xScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Min = data[fieldMap[xySelection.X]]
|
|
} else {
|
|
xScatterLimitFloat, _ := strconv.ParseFloat(xScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Min, 8)
|
|
dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.X]], 8)
|
|
if xScatterLimitFloat > dataFloat {
|
|
xScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Min = data[fieldMap[xySelection.X]]
|
|
}
|
|
}
|
|
if xScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Max == "" {
|
|
xScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Max = data[fieldMap[xySelection.X]]
|
|
} else {
|
|
xScatterLimitFloat, _ := strconv.ParseFloat(xScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Max, 8)
|
|
dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.X]], 8)
|
|
if xScatterLimitFloat < dataFloat {
|
|
xScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Max = data[fieldMap[xySelection.X]]
|
|
}
|
|
}
|
|
if yScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Min == "" {
|
|
yScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Min = data[fieldMap[xySelection.Y]]
|
|
} else {
|
|
yScatterLimitFloat, _ := strconv.ParseFloat(yScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Min, 8)
|
|
dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.Y]], 8)
|
|
if yScatterLimitFloat > dataFloat {
|
|
yScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Min = data[fieldMap[xySelection.Y]]
|
|
}
|
|
}
|
|
if yScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Max == "" {
|
|
yScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Max = data[fieldMap[xySelection.Y]]
|
|
} else {
|
|
yScatterLimitFloat, _ := strconv.ParseFloat(yScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Max, 8)
|
|
dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.Y]], 8)
|
|
if yScatterLimitFloat < dataFloat {
|
|
yScatterLimitArray[scatterFieldMap[xySelection.X+","+xySelection.Y]].Max = 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, xScatterLimitArray, yScatterLimitArray, 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,
|
|
}
|
|
}
|