Skip to content

Fix flux loss, aliasing, and placement errors in image-plane resampling and overlay#958

Open
teutoburg wants to merge 2 commits into
mainfrom
fh/impufixs
Open

Fix flux loss, aliasing, and placement errors in image-plane resampling and overlay#958
teutoburg wants to merge 2 commits into
mainfrom
fh/impufixs

Conversation

@teutoburg

Copy link
Copy Markdown
Contributor

This PR fixes three defects in scopesim/optics/image_plane_utils.py, all in the ImageSourceField → FOV → ImagePlane path (point/table sources are unaffected, which is what makes the discrepancies visible in point-vs-extended comparisons).

Silent flux loss / aliasing in rescale_imagehdu

When the input is finer than the instrument (zoom < 1), resampling used ndi.zoom, which point-samples the output lattice instead of integrating — so structure narrower than the sample spacing is aliased away, and a compact source on an unlucky grid phase vanishes entirely (all flux zeroed, then silently skipped by the if sum_new != 0 guard). Broad sources hid this because conserve_flux renormalises any partial hit exactly. The fix replaces the downsampling direction with an exact area-weighted rebin (cumulative sum differenced at the output bin edges), which conserves flux to machine precision by construction and, unlike a smoothing prefilter, never spreads a compact source beyond its output cell (a prefilter would leak flux into wings that a smaller FOV then clips after conserve_flux normalised the unclipped total — a phase-dependent deficit). It is gated to spline_order > 0: order == 0 is nearest-neighbour resampling of categorical data (masks, strehl labels) where integrating would synthesise phantom values, and those keep the stock path. A warning now fires if all flux is lost rather than dropping it silently.

Nominal-vs-realised zoom in the WCS update

ndi.zoom returns round(N·zoom) pixels, so the realised zoom differs from the nominal whenever N·zoom isn't integer. CDELT correctly keeps the nominal zoom (CDELT' == pixel_scale exactly), but CRPIX must use the realised zoom or the reference — and every source — is misplaced by up to half an output pixel.

+1px overlay shift (another off-by-one)

Separately, overlay_image did np.ceil(coords.round(10)), and .round(10) is far too tight for the ~1e-8 px float dust that the deg-space WCS round-trip in extract_from leaves on integer coordinates; ceil then amplifies it to a full-pixel paste offset (image sources landed +1px in x and y relative to point sources). ceil itself is correct and stays (even-sized fields legitimately hand over half-integer centres); only the dust tolerance is loosened to round(4).

Clauded, but would have taken at least a week otherwise.....

@teutoburg teutoburg self-assigned this Jul 20, 2026
@teutoburg teutoburg added the bugfix PR resolving one or more bugs (use "Bug" type for issues, not this label) label Jul 20, 2026
@codecov

codecov Bot commented Jul 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.57143% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.64%. Comparing base (7a851ab) to head (d104780).

Files with missing lines Patch % Lines
scopesim/optics/image_plane_utils.py 88.57% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #958      +/-   ##
==========================================
+ Coverage   75.60%   75.64%   +0.04%     
==========================================
  Files          70       70              
  Lines        8981     9013      +32     
==========================================
+ Hits         6790     6818      +28     
- Misses       2191     2195       +4     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@teutoburg teutoburg moved this to 👀 Awaiting Review in ScopeSim-development Jul 20, 2026
@teutoburg
teutoburg requested a review from a team July 20, 2026 12:36
@teutoburg
teutoburg marked this pull request as ready for review July 20, 2026 12:36
@hugobuddel

Copy link
Copy Markdown
Collaborator

Awesome! Thanks @teutoburg, a major step into improving the experience of using ScopeSim.

I suggest that we demonstrate the correctness of this with some tests. Maybe even a notebook that demonstrates the now non-existence of these problems.

More importantly, we can we use that as a regression test to prevent the problem from returning. I think this is very important, because otherwise someone might optimize your fix away at some point. Even with your great comments.

@teutoburg

Copy link
Copy Markdown
Contributor Author

I suggest that we demonstrate the correctness of this with some tests. Maybe even a notebook that demonstrates the now non-existence of these problems.

More importantly, we can we use that as a regression test to prevent the problem from returning. I think this is very important, because otherwise someone might optimize your fix away at some point. Even with your great comments.

I do have notebooks and tests for this in a branch over in ScopeSim-Targets. In fact, the notebooks (or rather plots therein) are how I found out about these bugs in the first place!

Agree that these tests should eventually live in ScopeSim itself, but they currently rely on some other code in Targets, so this needs the scopesim-core refactor to be moved. Or we just extract the pure-Source parts there. Anyway, it is tested somewhere. If you want to look at the notebooks already, they can be seen here: https://scopesim-targets.readthedocs.io/en/fh-extfluxtest/flux_construction.html (and the two pages following that one). All very much work in progress.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix PR resolving one or more bugs (use "Bug" type for issues, not this label)

Projects

Status: 👀 Awaiting Review

Development

Successfully merging this pull request may close these issues.

2 participants