# C7 spot-check: render one scene of the authors' numpy port (pipe_t.render, their code) for the still and the
# half-step dither (both exactly periodic: 1 and 2 frames, so 2 renders each suffice), then score
#  (a) with pipe_t.seen() as written (16 frames, last 6 used), to reproduce out/pipe.txt, and
#  (b) my way: the grain's spatial mean taken out before the Hann window and counted once as DC; the flip's
#      shimmer exactly, as an amplitude d(x) = (Y0 - Y1)/2 at fps/2 (no temporal window).
# run: python3 c7_spot.py <scene> <R>      (scene in glow faint stack ring; R 5 or 0)
import sys, numpy as np
sys.path.insert(0, '..')
import pipe_t as PT, vis
scene, R = sys.argv[1], int(sys.argv[2])
sc = PT.scenes()[scene]
Yi = PT.luminance(PT.ideal(sc, R, 2)); PT.YI = Yi
def frames(kind):
    Y = [PT.luminance(PT.render(sc, kind, R, 2, t)/255.) for t in (0, 1)]
    return np.array([Y[t % 2] for t in range(PT.T)])
def spec2(a, w2):
    return np.abs(np.fft.fft2(a*w2))**2/(w2**2).sum()/a.size
def mine(Ys, fps, model):
    Y = PT.crop(Ys[PT.WARM:]); Yc = PT.crop(Yi); loc = PT.blur(Yc, 2.0) + PT.Y0
    m = Y.mean(0); g = (m - Yc)/loc; d = (Y[0] - Y[1])/2/loc
    n = g.shape[0]; ws = np.hanning(n + 2)[1:-1]; w2 = ws[:, None]*ws[None, :]
    fy = np.fft.fftfreq(n)[:, None]; fx = np.fft.fftfreq(n)[None, :]; cpd = np.hypot(fx, fy)*PT.PPD
    S = vis.MODELS[model]
    c0 = (g*w2).sum()/w2.sum()
    G = 2*spec2(g - c0, w2); G[0, 0] = 0
    grain2 = c0**2*S(0., 0.)**2 + (G*S(cpd, 0.)**2).sum()
    D = 2*spec2(d, w2)          # d has (near) zero mean; any DC is a uniform flicker (self-conjugate): halve it
    D[0, 0] /= 2
    sh2 = (D*S(cpd, fps/2)**2).sum()
    return np.sqrt(grain2), np.sqrt(sh2), c0*S(0., 0.)
for kind in ('still', 'half'):
    Ys = frames(kind)
    out = [kind]
    for model, fps in (('bright', 60), ('bright', 30), ('dark', 60)):
        a = PT.seen(Ys, fps, model); b = mine(Ys, fps, model)
        out.append(f'{model} {fps}: seen() grain {a[0]:.2f} shimmer {a[1]:.2f} total {np.hypot(*a):.2f} | mine grain {b[0]:.2f} (DC part {b[2]:.2f}) shimmer {b[1]:.2f} total {np.hypot(b[0], b[1]):.2f}')
    print(f'{scene} R={R} ' + '\n   '.join(out), flush=True)
