// Render on existing image buffer. Resize it if needed func On(img *image.RGBA, f *data.Slice, fmin, fmax string, arrowSize int, colormap ...color.RGBA) { dim := f.NComp() switch dim { default: log.Fatalf("unsupported number of components: %v", dim) case 3: drawVectors(img, f.Vectors(), arrowSize) case 1: min, max := extrema(f.Host()[0]) if fmin != "auto" { m, err := strconv.ParseFloat(fmin, 32) if err != nil { util.Fatal("draw: scale:", err) } min = float32(m) } if fmax != "auto" { m, err := strconv.ParseFloat(fmax, 32) if err != nil { util.Fatal("draw: scale:", err) } max = float32(m) } if min == max { min -= 1 max += 1 // make it gray instead of black } drawFloats(img, f.Scalars(), min, max, colormap...) } }
func checkNaN(s *data.Slice, name string) { h := s.Host() for _, h := range h { for _, v := range h { if math.IsNaN(float64(v)) || math.IsInf(float64(v), 0) { util.Fatal("NaN or Inf in", name) } } } }
// Extract real parts, copy them from src to dst. // In the meanwhile, check if imaginary parts are nearly zero // and scale the kernel to compensate for unnormalized FFTs. // scale = 1/N, with N the FFT logical size. func scaleRealParts(dst, src *data.Slice, scale float32) { util.Argument(2*dst.Len() == src.Len()) util.Argument(dst.NComp() == 1 && src.NComp() == 1) srcList := src.Host()[0] dstList := dst.Host()[0] // Normally, the FFT'ed kernel is purely real because of symmetry, // so we only store the real parts... maximg := float32(0.) for i := 0; i < src.Len()/2; i++ { dstList[i] = srcList[2*i] * scale if fabs(srcList[2*i+1]) > maximg { maximg = fabs(srcList[2*i+1]) } } maximg *= float32(math.Sqrt(float64(scale))) // after 1 FFT, normalization is sqrt(N) // ...however, we check that the imaginary parts are nearly zero, // just to be sure we did not make a mistake during kernel creation. if maximg > FFT_IMAG_TOLERANCE { log.Fatalf("FFT kernel imaginary part: %v\n", maximg) } }