From 398bfb9a0712ce6bbb95bf4f52b546a173a44e11 Mon Sep 17 00:00:00 2001 From: Jammy2211 Date: Thu, 28 May 2026 14:18:47 +0100 Subject: [PATCH] docs: raw-flux latent guides + workspace config updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Companion to PyAutoLabs/PyAutoLens#557. Wires the three new raw-flux latents (total_lens_flux, total_lensed_source_flux, total_source_flux) into: - config/latent.yaml — explicit enablement; one-line silencer for the autogalaxy cross-library default (total_galaxy_0_flux: false) - scripts/guides/units/flux.py — new section demonstrating reading raw flux directly from latent.csv and converting to muJy in post - scripts/guides/results/latent_variables.py — updated catalogue section (now 8 latents grouped by raw / muJy / dimensionless) plus soft-fail vs raise reframing Refs PyAutoLabs/PyAutoLens#556 --- config/latent.yaml | 37 +++++++++--- scripts/guides/results/latent_variables.py | 66 ++++++++++++++-------- scripts/guides/units/flux.py | 54 ++++++++++++++++++ 3 files changed, 126 insertions(+), 31 deletions(-) diff --git a/config/latent.yaml b/config/latent.yaml index 11ff087af..cc5323b63 100644 --- a/config/latent.yaml +++ b/config/latent.yaml @@ -1,15 +1,31 @@ # Workspace overrides for the library lensing latent toggles. The -# PyAutoLens library defaults every key to `false` so existing fits stay -# unchanged on upgrade and unaware of `magzero`. Enabling them here -# means a workspace fit produces real latent output as long as the user -# also passes `magzero` to `al.AnalysisImaging(...)` when one is needed. +# PyAutoLens library defaults the three raw-flux keys to `true` (they +# need no instrument inputs) and the µJy / dimensionless variants to +# `false`. Enabling the µJy ones here means a workspace fit produces +# real microjansky output as long as the user also passes `magzero` to +# `al.AnalysisImaging(...)` — without `magzero` they return NaN and emit +# one warning per process. # # Run `scripts/guides/results/latent_variables.py` for a tutorial on -# what each key means and how to extend the catalogue with custom -# latents in your own scripts. +# what each key means and `scripts/guides/units/flux.py` for how to +# convert a raw-flux latent to microjanskies in post. -# total_lens_flux_mujy — integrated lens-galaxy flux in microjanskies. -# Requires magzero. NaN when lens has no light profile. +# total_lens_flux — integrated lens-galaxy flux in the fit's raw image +# units. No instrument inputs required. NaN when lens has no light profile. +total_lens_flux: true + +# total_lensed_source_flux — image-plane source flux after lensing, in +# raw image units. No instrument inputs required. +total_lensed_source_flux: true + +# total_source_flux — source-plane intrinsic source flux in raw image +# units. Uses fit.tracer_linear_light_profiles_to_light_profiles so MGE / +# linear light profiles work correctly. No instrument inputs required. +total_source_flux: true + +# total_lens_flux_mujy — same as total_lens_flux but converted to +# microjanskies. Requires magzero on AnalysisImaging; NaN + one warning +# per process if missing. total_lens_flux_mujy: true # total_lensed_source_flux_mujy — image-plane source flux after lensing, @@ -29,3 +45,8 @@ magnification: true # zero-contour of the tangential eigenvalue field. # magzero is not required. effective_einstein_radius: true + +# autogalaxy library default (loaded by autoconf into the same `latent` +# conf node) — explicitly disabled here to silence the cross-library +# "unknown latent" warning that would otherwise fire on every fit. +total_galaxy_0_flux: false diff --git a/scripts/guides/results/latent_variables.py b/scripts/guides/results/latent_variables.py index 758da6b5a..f345ffbea 100644 --- a/scripts/guides/results/latent_variables.py +++ b/scripts/guides/results/latent_variables.py @@ -16,7 +16,7 @@ __Contents__ - - Lensing Latents in PyAutoLens: The five library-shipped latents and what each one means physically. + - Lensing Latents in PyAutoLens: The eight library-shipped latents and what each one means physically. - Toggling Latents: The workspace ``config/latent.yaml`` override. - Model Fit: A quick fit that produces real latent output for the loading section. - Loading Latent Results: Reading the latent samples via ``analysis.compute_latent_samples(result.samples)``. @@ -36,20 +36,38 @@ The library ships a flat registry of named latent functions at ``autolens.analysis.latent.LATENT_FUNCTIONS``, backed by the toggle file ``autolens/config/latent.yaml``. Each entry maps a snake-case latent name to a Python -function that takes a fit, magzero, and ``xp`` and returns a scalar value. The day-1 catalogue has five entries: +function that takes a fit, magzero, and ``xp`` and returns a scalar value. The catalogue splits into three +groups: raw-flux latents (no instrument inputs, default-on), microjansky variants (require ``magzero``, +default-off), and the dimensionless lensing latents (``magnification``, ``effective_einstein_radius``). - - ``total_lens_flux_mujy`` — total integrated flux of the lens galaxy in microjanskies. Sum of the lens's - image-plane contribution to ``fit.galaxy_image_dict[fit.tracer.galaxies[0]]``, converted via ``magzero``. - Useful for stellar-mass-light scaling and photometric inference. +Raw-flux latents — sum the relevant model image in the fit's raw image units. Same units as +``dataset.data.array`` (typically e- s^-1 for HST, MJy/sr for JWST). See +``scripts/guides/units/flux.py`` for how to convert to microjanskies or AB magnitudes in post. - - ``total_lensed_source_flux_mujy`` — total integrated source-galaxy flux in the image plane after lensing - (i.e. with magnification baked in). Sum of ``fit.galaxy_image_dict[fit.tracer.galaxies[-1]]``, converted - via ``magzero``. + - ``total_lens_flux`` — total integrated flux of the lens galaxy. Sum of + ``fit.galaxy_image_dict[fit.tracer.galaxies[0]].array``. Returns NaN when the lens has no light profile. - - ``total_source_flux_mujy`` — the source's intrinsic flux in the source plane (before lensing). Computed - from the source galaxy's light profile evaluated on the workspace's light-profile grid. Critically uses - ``fit.tracer_linear_light_profiles_to_light_profiles`` rather than ``fit.tracer`` so that MGE / linear - light profiles report the inversion-solved intensities rather than zero. + - ``total_lensed_source_flux`` — image-plane integrated flux of the source galaxy after lensing (with + magnification baked in). Sum of ``fit.galaxy_image_dict[fit.tracer.galaxies[-1]].array``. + + - ``total_source_flux`` — the source's intrinsic flux in the source plane (before lensing). Computed from + the source's light profile evaluated on the workspace's light-profile grid. Critically uses + ``fit.tracer_linear_light_profiles_to_light_profiles`` rather than ``fit.tracer`` so MGE / linear light + profiles report the inversion-solved intensities rather than zero. + +Microjansky variants — same image sources as the raw-flux trio, but with the AB-mag → µJy conversion baked +in. Each one requires ``magzero`` on the analysis; if it's missing, the latent returns NaN and the library +emits a single warning per process per latent name (your search still completes — the cost is just an empty +column). + + - ``total_lens_flux_mujy`` — ``total_lens_flux`` in microjanskies. Useful for stellar-mass-light scaling and + photometric inference. + + - ``total_lensed_source_flux_mujy`` — ``total_lensed_source_flux`` in microjanskies. + + - ``total_source_flux_mujy`` — ``total_source_flux`` in microjanskies. + +Dimensionless lensing latents — no instrument inputs, no µJy variant. - ``magnification`` — dimensionless ratio of ``total_lensed_source_flux_mujy / total_source_flux_mujy``. This is the empirical flux-amplification factor implied by the lens model and source light profile. Source- @@ -64,18 +82,19 @@ tangential critical curve — the critical curve isn't circular for non-spherical mass models, but its enclosed area is the right physical quantity for mass-within-Einstein-radius estimates. -All five default to ``false`` in the library yaml (so existing fits stay unchanged on upgrade), and the four -flux-derived latents require ``magzero`` to be passed to ``al.AnalysisImaging(...)`` — if it's missing the -latent computation raises ``ValueError``. ``magnification`` and ``effective_einstein_radius`` don't need -``magzero``. +The raw-flux latents default to ``true`` in the library yaml — they cost essentially nothing and produce a +universally useful column. The µJy variants and the two dimensionless latents default to ``false`` so existing +fits and instrument-naive workflows stay unchanged on upgrade. """ """ __Toggling Latents__ -The library defaults every latent to ``false`` for the regression-safety reasons described above. To opt in, -edit your workspace's ``config/latent.yaml`` and set the keys you want to ``true``. This workspace ships such -a file at ``autolens_workspace/config/latent.yaml`` with all five lensing latents enabled. +The library defaults the three raw-flux latents to ``true`` and everything else to ``false`` for the +regression-safety reasons described above. To opt in to the µJy variants, dimensionless lensing latents, or to +disable a default-on raw-flux latent, edit your workspace's ``config/latent.yaml`` and set the keys you want. +This workspace ships such a file at ``autolens_workspace/config/latent.yaml`` with all eight lensing latents +enabled. Workspace ``config/`` values shadow the library defaults — PyAutoFit's ``conf.instance`` searches the workspace ``config/`` directory first, so toggling a latent in your workspace yaml is enough to enable it without modifying @@ -91,8 +110,9 @@ ``simple__no_lens_light`` dataset. We use an Isothermal lens mass and an MGE source — fast enough to run in test mode while still producing a real posterior over the magnification and Einstein-radius latents. -We pass ``magzero=25.0`` to ``al.AnalysisImaging`` for the flux-derived latents. The Einstein-radius and -magnification latents don't need it, but the others would raise without it. +We pass ``magzero=25.0`` to ``al.AnalysisImaging`` so the three µJy latents populate with real values +(without it they'd be NaN and the library would log a single warning per latent name per process). The raw-flux +trio, Einstein-radius and magnification latents don't need ``magzero``. """ dataset_name = "simple__no_lens_light" dataset_path = Path("dataset") / "imaging" / dataset_name @@ -226,8 +246,8 @@ def compute_latent_variables(self, parameters, model): """ A fit that uses ``AnalysisImagingWithMassAxisRatio`` produces a ``latent.csv`` with one extra column -(``mass_axis_ratio``) on top of the five library defaults. We don't run a second fit here — the pattern above -is the full recipe. +(``mass_axis_ratio``) on top of the eight library defaults (raw-flux + µJy + dimensionless lensing). We don't +run a second fit here — the pattern above is the full recipe. """ """ diff --git a/scripts/guides/units/flux.py b/scripts/guides/units/flux.py index 8042b38c9..5217aec60 100644 --- a/scripts/guides/units/flux.py +++ b/scripts/guides/units/flux.py @@ -25,6 +25,7 @@ - **Zero Point:** In astronomy, a zero point refers to a reference value used in photometry and spectroscopy to. - **Total Flux:** A key quantity for computing the magnitudes of galaxies is the total flux of a light profile. +- **Latent Variables:** Reading the same total flux directly from the `latent.csv` of a completed fit. __Zero Point__ @@ -239,7 +240,60 @@ - The HST PHOTNU value, in units of Jy (e s^-1), which converts to Janskys, which is often used by SED fitting software. +__Latent Variables: Total Flux Directly from the Fit__ +The examples above all computed total flux by hand: build a light profile, sample it on a grid, sum the image, then +apply the zero point. PyAutoLens does exactly this automatically as part of every fit and records the result as a +latent variable in the `latent/samples.csv` file beside the search output. You can skip the manual recipe entirely +and just read the column. + +Three lensing flux latents ship default-on (they need no instrument inputs and run on every fit unless disabled in +`config/latent.yaml`): + +- `total_lens_flux` — total integrated flux of the lens galaxy (the sum of `fit.tracer.galaxies[0]`'s model image), + in the *raw* image units the fit was performed in. For HST data in e- s^-1, this is e- s^-1; for JWST data in + MJy/sr, this is MJy/sr. + +- `total_lensed_source_flux` — image-plane integrated flux of the source galaxy after lensing. This is the source + flux as observed: stretched, multiplied, and distorted by the lens. Same raw units. + +- `total_source_flux` — source-plane intrinsic flux of the source galaxy: the flux the source would have if the + lens weren't there. Computed via `fit.tracer_linear_light_profiles_to_light_profiles` so that linear light + profiles (MGEs, pixelizations) work correctly. The ratio + `total_lensed_source_flux / total_source_flux` is the integrated magnification (also recorded directly as the + `magnification` latent). + +To convert any of these to AB magnitudes or microjanskies, apply the same zero-point recipe used above. Suppose +you have an HST F814W fit with the F814W zero point of 25.943; reading the lens galaxy flux from your result and +converting goes: +""" +from autogalaxy.imaging.model.latent import ( + ab_mag_via_flux_from, + flux_mujy_via_ab_mag_from, +) + +# Stand-in for what you'd read from `latent.csv` — in a real script this is one column of one row, e.g. +# total_lens_flux = pd.read_csv(search.paths.output_path / "latent" / "samples.csv")["total_lens_flux"].iloc[-1] +total_lens_flux = 1234.5 # e- s^-1 + +zero_point_f814w = 25.943 +ab_mag_lens = ab_mag_via_flux_from(flux=total_lens_flux, magzero=zero_point_f814w) +flux_mujy_lens = flux_mujy_via_ab_mag_from(ab_mag=ab_mag_lens) + +""" +The two helpers used above are the same ones the library uses internally to populate the `_mujy` variants of the +latents (`total_lens_flux_mujy`, `total_lensed_source_flux_mujy`, `total_source_flux_mujy`). Those variants are +default-off because they need a `magzero` you supply per-instrument. If you have a single fixed zero-point you can +flip them on by: + +1. Setting `total_lens_flux_mujy: true` (and friends) in your project's `config/latent.yaml`. +2. Passing `magzero=` when constructing the analysis: + `analysis = al.AnalysisImaging(dataset=dataset, magzero=25.943)`. + +The latent dispatcher then writes the converted µJy columns into `latent/samples.csv` directly, so you don't have +to run the conversion in post. If you enable the `_mujy` latents but forget the `magzero` keyword, the columns are +populated with NaN and a single warning per process notes that the conversion was skipped — the fit itself is +unaffected. Finish. """