Skip to content

fix: express pixelized source flux per data pixel in the latents - #728

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/pixelized-source-magnification-latent
Sep 5, 2026
Merged

Jammy2211 merged 1 commit into
mainfrom
feature/pixelized-source-magnification-latent

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Summary

Correction to #727 (part of #726). _pixelized_source_flux returned the plain surface integral Σᵢ sᵢ Aᵢ over the source mesh, but every other flux latent in autolens/analysis/latent.py is a sum over data pixels (∫ I d²θ / A_pix), and the reconstruction sᵢ is in those per-data-pixel units (the mapping matrix maps s onto image-pixel values). The pixelized magnification therefore scaled with the data's pixel scale: on the Euclid pipeline's 0.1"/pixel simulated dataset it came out 1095, exactly 100× the plausible 10.95 (the Sersic control on the same scene is 15.15). PyAutoLens' fixtures use 1" pixels (A_pix = 1), which is why #727's tests could not see it.

The helper now divides by the data pixel area read from fit.dataset.grids.lp — the same grid the light-profile flux term is evaluated on, so both terms of total_source_flux share one convention. Grid2D.pixel_area is a Python float, so the per-sample jax.jit latent path is unaffected. If no pixel area resolves (no pixel_area, no pixel_scales on the grid or dataset) the helper returns NaN with a once-per-process warning rather than a silently unscaled number. Docstrings on _pixelized_source_flux, total_source_flux, total_source_flux_mujy and magnification state the convention and why the ratio is then the physical ∫ I d²θ / ∫ S d²β.

Measured after the fix on the Euclid euclid_dr1_like scene (Delaunay, 150 Hilbert + 30 edge points, PyPI autoarray's Voronoi areas): magnification 10.95, total_source_flux 1.257 (Sersic control 15.15 / 0.868). The accuracy check against truth stays the human acceptance step on #726.

API Changes

Changed behaviour, no signature changes:

  • total_source_flux, total_source_flux_mujy and magnification for a pixelized source are now Σ sᵢAᵢ / A_pix based rather than Σ sᵢAᵢ — a factor 1/A_pix (100× at 0.1"/pixel) relative to fix: magnification latent finite for pixelized sources #727, which was never released. Light-profile-only fits and 1"/pixel data are numerically unchanged.
    See full details below.

Test Plan

  • test_autolens/analysis/test_latent.py: 34 passed (3 new — a rectangular pixelized fit at 0.5"/pixel pins Σ sA / 0.25 (4.561 → 1.140, exactly the pixel-area factor); an unresolvable pixel area gives NaN and exactly one warning; a fixed-field-of-view Sersic-behind-isothermal scene observed at 0.4" and 0.2" gives pixelized magnifications within a factor 2 of each other (48.97 / 61.22), which the undivided value violated by 4×). With the division reverted exactly the two value-bearing tests fail.
  • Full suite python -m pytest test_autolens/ -n auto: 620 passed, 1 xfailed
  • CI green on the Python 3.12 / 3.13 matrix
Full API Changes (for automation & release notes)

Added

  • autolens.analysis.latent._data_pixel_area(fit) -> Optional[float] — private helper; fit.dataset.grids.lp.pixel_area, falling back to the product of pixel_scales on the grid then the dataset; None if none resolves.

Changed

  • autolens.analysis.latent._pixelized_source_flux(fit, xp=np) — returns Σ sᵢAᵢ / A_pix (was Σ sᵢAᵢ in fix: magnification latent finite for pixelized sources #727); NaN + one warning when A_pix cannot be resolved.
  • total_source_flux, total_source_flux_mujy, magnification — pixelized-source values rescaled by 1/A_pix accordingly; unchanged for light-profile-only sources.

Removed

  • None.

Migration

Generated by the PyAutoLabs agent workflow.

🤖 Generated with Claude Code

https://claude.ai/code/session_011kyfKgDB1rMkcQsn19ow4T


Generated by Claude Code

`_pixelized_source_flux` (PR #727) returned the plain surface integral
`sum_i s_i A_i` over the source mesh, but every other flux latent in the
module is a sum over data pixels (`integral / A_pix`), and the
reconstruction `s_i` is in those per-data-pixel units. The pixelized
`magnification` therefore scaled with the data's pixel scale: on the
Euclid pipeline's 0.1"/pixel simulated dataset it came out 1095, exactly
100x the plausible 10.95. The 1" fixtures have `A_pix = 1`, which hid it.

Divide by the data pixel area read from `fit.dataset.grids.lp` (the grid
the light-profile term is evaluated on), a Python float so the jit path
is unaffected; NaN plus one warning if no pixel area resolves. Docstrings
state the convention.

Tests: the existing pixelized tests state `sum(s A) / A_pix`; a fit at
0.5"/pixel pins the division (4.561 -> 1.140, exactly the pixel-area
factor); an unresolvable pixel area gives NaN and one warning; a
fixed-field-of-view scene observed at 0.4" and 0.2" gives magnifications
within a factor 2 of each other, which the undivided value violated by 4x.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011kyfKgDB1rMkcQsn19ow4T
@Jammy2211 Jammy2211 added the pending-release PR queued for the next release build label Sep 5, 2026 — with Claude
@Jammy2211
Jammy2211 merged commit 1f5b1e9 into main Sep 5, 2026
4 checks passed
@Jammy2211
Jammy2211 deleted the feature/pixelized-source-magnification-latent branch September 5, 2026 14:24
@Jammy2211 Jammy2211 removed the pending-release PR queued for the next release build label Sep 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant