Skip to content

fix: total_source_flux_mujy wrong value for linear light profiles#536

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/latent-source-flux-linear-fix
May 23, 2026
Merged

fix: total_source_flux_mujy wrong value for linear light profiles#536
Jammy2211 merged 1 commit into
mainfrom
feature/latent-source-flux-linear-fix

Conversation

@Jammy2211
Copy link
Copy Markdown
Collaborator

Summary

total_source_flux_mujy (shipped in #534) returns wrong values for fits using linear light profiles (any lp_linear.* or MGE basis). For linear profiles fit.tracer.galaxies[-1] carries unsolved profiles — image_2d_from returns zeros because intensities are filled by the inversion at fit time, not propagated back into the source-plane profile objects. magnification inherits the bug via its source-flux denominator.

Fix: read from fit.tracer_linear_light_profiles_to_light_profiles (which rebuilds the tracer with intensities filled in from the inversion). For non-linear fits this property short-circuits to self.model_obj — pure no-op pass-through, no behaviour change.

Discovered while planning the Euclid pipeline migration (PyAutoLabs/euclid_strong_lens_modeling_pipeline#17). Euclid had already coded the workaround locally at util.py:378 — this PR lifts it into the library so other lens projects with linear profiles get correct values without each one re-discovering the issue.

Closes #535.

API Changes

None — internal change only. Function signatures, registry keys, config layout, and AnalysisImaging wiring are all unchanged. Only the body of total_source_flux_mujy is modified (one extra attribute access). magnification automatically returns correct values via the fix.

Test Plan

  • pytest test_autolens/analysis/test_latent.py -x -v — 18/18 pass (including the new test_total_source_flux_mujy_uses_converted_tracer_for_linear_profiles).
  • pytest test_autolens/ — 312/312 pass (no regression).
  • Empirical JIT-path validation: euclid uses this exact pattern (util.py:378) under LATENT_BATCH_MODE = "jit" in production.
Stress-test notes

Why the fix is safe:

  1. Non-linear fits: autogalaxy/abstract_fit.py:214model_obj_linear_light_profiles_to_light_profiles early-returns self.model_obj when linear_light_profile_intensity_dict is None. Pure pass-through.

  2. Linear-profile fits: append_linear_light_profiles_to_model(...) rebuilds the tracer with intensities filled in. The intensity dict is populated as a side-effect of the inversion that already runs to produce figure_of_merit — no extra inversion solve.

  3. JIT path: euclid empirically validates this — util.py:378 runs under JIT in production. The property's Python branches (if linear_light_profile_intensity_dict is None) are structural (static across samples), so JAX traces them cleanly.

  4. total_lens_flux_mujy / total_lensed_source_flux_mujy are unchanged: they read fit.galaxy_image_dict[...] which already merges galaxy_linear_obj_data_dict_from for linear-obj galaxies via FitImaging.galaxy_image_dict. Correct for both linear and non-linear.

  5. effective_einstein_radius is unchanged: light-profile-independent (depends on mass model only).

  6. Performance: O(1) attribute access for non-linear fits; one tracer rebuild per compute_latent_variables call for linear fits. Inside JIT, the rebuild is traced once and reused per sample.

🤖 Generated with Claude Code

For fits using linear light profiles (any lp_linear.* or MGE basis),
`fit.tracer.galaxies[-1]` carries unsolved profiles — image_2d_from
returns zeros because the linear intensities are filled in by the
inversion at fit time, not propagated back into the source-plane
profile objects. The library's `total_source_flux_mujy` therefore
returned wrong values for any linear-profile fit, and `magnification`
inherited the bug via its source-flux denominator.

Read from `fit.tracer_linear_light_profiles_to_light_profiles` instead:
the property invokes `append_linear_light_profiles_to_model(...)`
which rebuilds the tracer with intensities filled in from the
inversion's `linear_light_profile_intensity_dict` (already cached as
a side-effect of computing figure_of_merit). For non-linear fits the
property short-circuits to `self.model_obj` (== `fit.tracer`), so the
change is a no-op pass-through and existing tests using
`al.lp.Sersic(intensity=...)` continue to pass.

Empirical proof this is JIT-safe: euclid_strong_lens_modeling_pipeline
uses this exact pattern (util.py:378) inside `compute_latent_variables`
under `LATENT_BATCH_MODE = "jit"`.

Add a regression test that builds a fit fixture where the un-solved
tracer returns zeros and the converted tracer returns a non-zero image,
asserting the function reads from the converted one. Existing
`total_source_flux_mujy` / `magnification` fixtures gain the new
attribute for the no-op pass-through path.

Discovered while planning #17 (Euclid pipeline migration); fix unblocks
that work.

Refs: #535
@Jammy2211 Jammy2211 added the pending-release PR queued for the next release build label May 23, 2026
@Jammy2211 Jammy2211 merged commit 6551e6c into main May 23, 2026
6 checks passed
@Jammy2211 Jammy2211 deleted the feature/latent-source-flux-linear-fix branch May 23, 2026 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pending-release PR queued for the next release build

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: total_source_flux_mujy wrong value for linear light profiles

1 participant