Repository navigation
fix: magnification latent finite for pixelized sources - #727
Merged
Merged
Conversation
`total_source_flux` / `total_source_flux_mujy` read the source galaxy's `image_2d_from`, which is zeros for a galaxy whose only light model is a `Pixelization`, so every pixelized fit had `total_source_flux = 0.0` and `magnification = inf` (a dropped column, or an archived `0.0` sentinel). Add `_pixelized_source_flux`: the inversion's reconstruction integrated over the source mesh with its `areas_for_magnification`, summed for every mapper that `inversion.linear_obj_galaxy_dict` assigns to the source galaxy. Light-profile flux plus pixelized flux is now the source-plane flux; `magnification` keeps its form and becomes finite. A mesh geometry with no `areas_for_magnification` gives NaN with a one-time warning, never a silent zero. All branching is on Python structure, so the per-sample `jax.jit` latent path is unaffected. Tests: Delaunay and rectangular pixelized fits give a finite magnification equal to sum(image) / sum(reconstruction * areas); linear light profile + pixelization sums both terms; light-profile-only fits are unchanged; the no-inversion, no-source-mapper and missing-areas (NaN + one warning) branches are pinned. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011kyfKgDB1rMkcQsn19ow4T
This was referenced Sep 5, 2026
palacios22c
pushed a commit
to palacios22c/PyAutoLens
that referenced
this pull request
Sep 13, 2026
…utoLabs#726) `_pixelized_source_flux` (PR PyAutoLabs#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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Part of #726 (library half; the
euclid_strong_lens_modeling_pipelinefollow-up closes the issue). Themagnificationlatent divides image-plane source flux bytotal_source_flux_mujy, which read the source galaxy'simage_2d_from— zeros for a galaxy whose only light model is aPixelization. Every pixelized fit therefore hadtotal_source_flux = 0.0andmagnification = inf(dropped as a column by PyAutoFit's NaN guard, or archived as a0.0sentinel in the Euclidvis_pix/full_modelstages), while the Sersic control on the same fit reproduced truth bit-for-bit.autolens/analysis/latent.pygains_pixelized_source_flux(fit, xp): the inversion's reconstruction integrated over the source mesh with itsareas_for_magnification, summed over every mapper thatinversion.linear_obj_galaxy_dictassigns to the source galaxy.total_source_fluxandtotal_source_flux_mujyare now light-profile flux plus that pixelized flux;magnificationkeeps its form and becomes finite. A mesh geometry with noareas_for_magnificationyields NaN with a one-time-per-process warning — never a silent zero. The lookup deliberately uses the dict the inversion already carries rather thanfit.tracer_to_inversion, which is an uncached property whose freshly built mappers would not keyreconstruction_dict. All branching is on Python structure (None checks,isinstance, dict membership), so the per-samplejax.jitlatent path is unaffected.End-to-end Delaunay accuracy depends on PyAutoArray#524 / PR #525 (barycentric dual areas as
areas_for_magnification, merged 2026-09-05, pending release). The unit tests here assert internal consistency (Σ image / Σ reconstruction·areas) and hold on either PyAutoArray.API Changes
Changed behaviour, no signature changes:
total_source_flux,total_source_flux_mujyandmagnificationnow include a pixelized source's reconstruction flux. For a pixelization-only source they were0.0/0.0/inf; they are now the integrated reconstruction and a finite ratio. Light-profile-only fits are numerically unchanged.See full details below.
Test Plan
test_autolens/analysis/test_latent.py: 31 passed (7 new — Delaunay and rectangular pixelized fits give a finitemagnificationequal toΣ galaxy image / Σ reconstruction·areas_for_magnification; linear light profile + pixelization sums both terms; light-profile-only fit unchanged; no-inversion and no-source-mapper branches return 0.0; a mapper without mesh areas gives NaN and exactly one warning)python -m pytest test_autolens/ -n auto: 617 passed, 1 xfailedpart3b_fit_latent.pyconstruction (Delaunay fit oneuclid_dr1_like, magzero 24.6) reports a finitemagnificationclose to the Sersic control's 15.146 — record on fix: magnification latent is inf/0.0 for any pixelized source #726Full API Changes (for automation & release notes)
Added
autolens.analysis.latent._pixelized_source_flux(fit, xp=np)— private helper; source-plane flux of the source galaxy's inversion component,Σ_i s_i A_iover each of its mappers, usinginversion.linear_obj_galaxy_dictfor mapper → galaxy andmesh_geometry.areas_for_magnificationfor the areas. Returns0.0when the fit has no inversion or no mapper belongs to the source galaxy;NaN(+ one warning) when a mesh geometry publishes noareas_for_magnification.Changed
autolens.analysis.latent.total_source_flux(fit, magzero=None, xp=np)— now light-profile flux +_pixelized_source_flux.autolens.analysis.latent.total_source_flux_mujy(fit, magzero, xp=np)— same sum, then the µJy conversion.autolens.analysis.latent.magnification(fit, magzero, xp=np)— unchanged in form; finite for pixelized sources as a consequence.Removed
Migration
magnificationlatent (e.g.euclid_strong_lens_modeling_pipeline's catalogue) will start receiving real values for pixelized stages; archivedvis_pixrows carrying the0.0sentinel must be re-derived.Generated by the PyAutoLabs agent workflow.
🤖 Generated with Claude Code
https://claude.ai/code/session_011kyfKgDB1rMkcQsn19ow4T