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
@Jammy2211 Jammy2211 removed the pending-release PR queued for the next release build label Sep 4, 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.

fix: total_source_flux_mujy wrong value for linear light profiles

1 participant