feat: first-class latent variable API in PyAutoGalaxy#441
Merged
Conversation
Add autogalaxy/imaging/model/latent.py with a registry-driven catalogue of latent variables, autogalaxy/config/latent.yaml as a user-toggle layer, and AnalysisImaging overrides (LATENT_KEYS property + compute_latent_variables method) so users get a curated default latent set without subclassing. Day-1 catalogue: total_galaxy_0_flux_mujy (total integrated flux of the first galaxy in the fit, magzero-converted to microjanskies). Helpers ab_mag_via_flux_from and flux_mujy_via_ab_mag_from are ported from euclid_strong_lens_modeling_pipeline/util.py. Refs: #439
added 2 commits
May 23, 2026 12:20
Existing AnalysisImaging users don't pass magzero today, but compute_latent_samples runs on every fit (latent_after_fit defaults to true in output.yaml). If the latent stays on by default, every existing fit would crash with ValueError once it tries to compute total_galaxy_0_flux_mujy without magzero. Default the latent off in the library config so existing fits remain green. Users who want the latent must enable it in their workspace config/latent.yaml AND pass magzero=<value> to AnalysisImaging. Test config (test_autogalaxy/config/latent.yaml) stays on so the existing tests continue to exercise the AnalysisImaging dispatch path.
Raise NotImplementedError when LATENT_KEYS is [] (the default-off case)
so PyAutoFit's existing `except NotImplementedError: return None` at
autofit/non_linear/analysis/analysis.py:304 cleanly skips the latent
pipeline. Otherwise the empty-tuple flow runs the batch loop, builds
Sample objects with empty kwargs, and calls simple_model_for_kwargs({})
— wasted work and fragile against future autofit changes.
Adds a test that confirms the explicit raise.
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
PyAutoGalaxy now has a first-class latent variable API. Users no longer need to subclass
AnalysisImagingand hand-writeLATENT_KEYS+compute_latent_variablesto get derived quantities intolatent.csv. A newautogalaxy/imaging/model/latent.pymodule owns the registry of named latent computations,autogalaxy/config/latent.yamllets users toggle individual latents on/off without editing Python, andAnalysisImagingoverrides PyAutoFit's stubbed hook to dispatch through the registry.Day-1 catalogue is one concrete latent —
total_galaxy_0_flux_mujy(total integrated flux of the first galaxy in the fit, magzero-converted to microjanskies). It defaults OFF inautogalaxy/config/latent.yamlbecause it requiresmagzeroto be passed viaAnalysisImaging(..., magzero=<value>); existing fits that don't passmagzerowould otherwise crash oncecompute_latent_samplesran. Users opt in by editing the yaml AND passingmagzero.This is the dependency root of the broader latent_refactor epic; PyAutoLens (next sub-prompt) will add the lensing-specific latents (magnification, effective Einstein radius, lensed source flux) on top of this infrastructure.
Closes #439.
API Changes
New public module
autogalaxy.imaging.model.latentwith helpers (ab_mag_via_flux_from,flux_mujy_via_ab_mag_from), theLATENT_FUNCTIONSregistry, thelatent_keys_enabled()reader, and one registered latent (total_galaxy_0_flux_mujy, disabled by default).AnalysisImaginggains aLATENT_KEYS@propertyand acompute_latent_variables(parameters, model)method — both new public surface. New config fileautogalaxy/config/latent.yaml. Note: autoconf lowercases yaml keys, so the latent name uses lowercasemujy(notmuJy) — this leaks through to thelatent.csvcolumn header.See full details below.
Test Plan
pytest test_autogalaxy/imaging/model/test_latent.py -x -v— 9/9 passpytest test_autogalaxy/— 917/917 pass (no regression)magzerocontinue to produce emptyLATENT_KEYS, socompute_latent_variablesreturns an empty tuple — no crash.config/latent.yaml, passmagzerovia Analysis kwargs, run anautogalaxy_workspacemodeling script, inspectoutput/.../latent/latent_summary.json.Full API Changes (for automation & release notes)
Added
autogalaxy.imaging.model.latent— new moduleautogalaxy.imaging.model.latent.ab_mag_via_flux_from(flux, magzero, xp=np)— flux → AB magnitudeautogalaxy.imaging.model.latent.flux_mujy_via_ab_mag_from(ab_mag, xp=np)— AB magnitude → flux in microjanskiesautogalaxy.imaging.model.latent.total_galaxy_0_flux_mujy(fit, magzero, xp=np)— concrete latent; returns NaN when galaxy 0 has no light profile; raisesValueErrorifmagzeroisNoneautogalaxy.imaging.model.latent.LATENT_FUNCTIONS: Dict[str, Callable]— flat registry of name → functionautogalaxy.imaging.model.latent.latent_keys_enabled(yaml_config=None) -> List[str]— readsconf.instance["latent"](or an explicit dict for tests); returns enabled keys filtered to those present inLATENT_FUNCTIONSautogalaxy.AnalysisImaging.LATENT_KEYS— new@propertyoverriding the inherited class-level[]; reads from config at call timeautogalaxy.AnalysisImaging.compute_latent_variables(parameters, model)— overrides PyAutoFit's stubbed hook; returns a tuple positionally aligned withLATENT_KEYSautogalaxy/config/latent.yaml— new config file with one toggle (total_galaxy_0_flux_mujy: falseby default)Changed Behaviour
LATENT_KEYSis[]andcompute_latent_variablesreturns(). The latent pipeline runs but produces no output, matching today's behaviour.AnalysisImaginginstances producelatent.csv/latent_summary.jsonoutputs containingtotal_galaxy_0_flux_mujycolumns, provided the user also passesmagzeroviaAnalysisImaging(..., magzero=<value>). Ifmagzerois absent when the latent is enabled, the computation raisesValueErrorloudly (no silentNaN).Migration
None required. Existing code continues to work unchanged. To opt into the new latent: set
total_galaxy_0_flux_mujy: truein your workspace'sconfig/latent.yamland passmagzerowhen constructingAnalysisImaging.For the follow-up workspace tutorial: workspaces should mirror
autogalaxy/config/latent.yamlinto<workspace>/config/latent.yamlso users have a clear opt-in surface.🤖 Generated with Claude Code