Behavior
On the jax backend, background_deviation_box returns a flat array (every pixel = the global xp.std(data)) instead of per-box sigmas — silently wrong results, no error (verified empirically 2026-07-27). On numpy it works, but only by side effect.
Root cause
The xpx.at(...).set(...) result is never assigned:
|
barr = data * 0.0 + xp.std(data) |
|
ylen, xlen = data.shape |
|
for i in range(int(0.5 * bbox), xlen, bbox): |
|
for j in range(int(0.5 * bbox), ylen, bbox): |
|
x1, x2, y1, y2 = setbox(i, j, bbox, xlen, ylen) |
|
xpx.at(barr)[y1:y2, x1:x2].set(float(sigma_func(data[y1:y2, x1:x2]))) |
On numpy, xpx.at takes its in-place fast path so the discarded return value doesn't matter; on immutable backends (jax) it returns a new array that is thrown away, leaving barr at its initialized value. This is the same discarded-update bug class fixed for flat_correct/ccdmask in #956, and (as far as I can find) the last live instance on main.
Note on #931
The "Suggested fix" in #931 cites this exact line as the correct-pattern exemplar to copy — please don't: the pattern is only correct with the result rebound. I'll drop a note on #931 pointing here.
Suggested fix
One-line rebind:
barr = xpx.at(barr)[y1:y2, x1:x2].set(float(sigma_func(data[y1:y2, x1:x2])))
plus a jax-lane regression test asserting per-box values differ from the global std (the numpy lane can't catch this — the in-place fast path masks it).
Follow-up to #909 / #956. This issue was written by Claude (via Claude Code); Matt reviewed and approved its content before filing.
Behavior
On the jax backend,
background_deviation_boxreturns a flat array (every pixel = the globalxp.std(data)) instead of per-box sigmas — silently wrong results, no error (verified empirically 2026-07-27). On numpy it works, but only by side effect.Root cause
The
xpx.at(...).set(...)result is never assigned:ccdproc/ccdproc/core.py
Lines 1341 to 1346 in 736555d
On numpy,
xpx.attakes its in-place fast path so the discarded return value doesn't matter; on immutable backends (jax) it returns a new array that is thrown away, leavingbarrat its initialized value. This is the same discarded-update bug class fixed forflat_correct/ccdmaskin #956, and (as far as I can find) the last live instance on main.Note on #931
The "Suggested fix" in #931 cites this exact line as the correct-pattern exemplar to copy — please don't: the pattern is only correct with the result rebound. I'll drop a note on #931 pointing here.
Suggested fix
One-line rebind:
plus a jax-lane regression test asserting per-box values differ from the global std (the numpy lane can't catch this — the in-place fast path masks it).
Follow-up to #909 / #956. This issue was written by Claude (via Claude Code); Matt reviewed and approved its content before filing.