diff --git a/config/latent.yaml b/config/latent.yaml index edba214e..66821cd8 100644 --- a/config/latent.yaml +++ b/config/latent.yaml @@ -1,14 +1,19 @@ # Workspace overrides for the library latent toggles. The PyAutoGalaxy -# library defaults every key to `false` (so existing fits stay unchanged -# on upgrade and unawares of `magzero`). Enabling them here means a -# workspace fit produces real latent output as long as the user also -# passes `magzero` to `ag.AnalysisImaging(...)`. +# library defaults `total_galaxy_0_flux` to `true` (no instrument inputs +# needed) and `total_galaxy_0_flux_mujy` to `false`. Enabling the µJy +# variant here means a workspace fit produces microjansky output as long +# as the user also passes `magzero` to `ag.AnalysisImaging(...)` — without +# `magzero` it returns NaN + 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_galaxy_0_flux_mujy` — total integrated flux of `fit.galaxies[0]` -# in microjanskies (magzero-converted). Requires `magzero` via Analysis -# kwargs; raises loudly if missing. +# `total_galaxy_0_flux` — total integrated flux of `fit.galaxies[0]` in +# the fit's raw image units. No instrument inputs required. +total_galaxy_0_flux: true + +# `total_galaxy_0_flux_mujy` — same flux converted to microjanskies via +# magzero. Requires `magzero` via Analysis kwargs; returns NaN + one +# warning per process if missing. total_galaxy_0_flux_mujy: true diff --git a/scripts/guides/results/latent_variables.py b/scripts/guides/results/latent_variables.py index 85ef872a..7824f95a 100644 --- a/scripts/guides/results/latent_variables.py +++ b/scripts/guides/results/latent_variables.py @@ -41,29 +41,36 @@ backed by the toggle file ``autogalaxy/config/latent.yaml``. Each entry maps a snake-case latent name to a Python function that takes a fit, magzero, and ``xp`` (numpy / jax.numpy) and returns a scalar value. -The day-1 catalogue contains a single concrete latent: +The catalogue contains two related latents that pair as a raw-flux / unit-converted couplet: - - ``total_galaxy_0_flux_mujy`` — total integrated flux of the first galaxy in the fit (``fit.galaxies[0]``), - converted from the fit's linear flux units to microjanskies via the ``magzero`` keyword argument passed - to ``ag.AnalysisImaging``. Returns NaN when galaxy 0 has no light profile. + - ``total_galaxy_0_flux`` — total integrated flux of the first galaxy in the fit (``fit.galaxies[0]``) in the + fit's raw image units (typically e- s^-1 for HST, MJy/sr for JWST). Requires no instrument inputs and + ships default-on in the library yaml. Returns NaN when galaxy 0 has no light profile. See + ``scripts/guides/units/flux.py`` for how to convert this raw flux to microjanskies or AB magnitudes in post. + + - ``total_galaxy_0_flux_mujy`` — the same total flux converted to microjanskies via the ``magzero`` keyword + argument passed to ``ag.AnalysisImaging``. Default-off in the library yaml — opt in only when you have a + stable per-instrument zero-point. If you enable it without supplying ``magzero`` the column populates with + NaN and the library emits a single warning per process (your fit completes uninterrupted). The catalogue is intentionally narrow at launch — the long-tail of useful galaxy latents will accrue over time as users contribute the ones their science needs. See the "Contributing Upstream" section at the end of this tutorial for how to add new ones. -Future library releases may extend the registry. The toggle layer below means new entries default to ``false`` -in the library yaml, so adding a latent never changes the behaviour of an existing fit — users opt in by -enabling the key in their workspace ``config/latent.yaml``. +Future library releases may extend the registry. The toggle layer below means new entries can default either +way safely: a new raw-flux latent that requires no inputs can default-on, while anything needing instrument +metadata defaults-off so existing instrument-naive fits stay unchanged on upgrade. """ """ __Toggling Latents__ -The library defaults every latent to ``false`` in ``autogalaxy/config/latent.yaml``. This is deliberate: the -flux-derived latents require a ``magzero`` value via ``AnalysisImaging(..., magzero=...)`` kwargs, and enabling -them by default would crash any existing fit that doesn't pass ``magzero``. To opt in, you create or edit your -workspace's ``config/latent.yaml`` and set the keys you want to ``true``. This workspace ships such a file at -``autogalaxy_workspace/config/latent.yaml`` with ``total_galaxy_0_flux_mujy: true``. +The library defaults ``total_galaxy_0_flux: true`` (no instrument inputs needed) and +``total_galaxy_0_flux_mujy: false`` (you need to supply ``magzero``) in ``autogalaxy/config/latent.yaml``. The +default-off µJy variant is deliberate: it requires a ``magzero`` value via ``AnalysisImaging(..., magzero=...)``, +and the workspace fit you're running may not have one to hand. To opt in to the µJy column, edit your +workspace's ``config/latent.yaml`` and set ``total_galaxy_0_flux_mujy: true``. This workspace ships such a file +at ``autogalaxy_workspace/config/latent.yaml`` with both keys ``true``. Workspace ``config/`` values shadow the library defaults — PyAutoFit's ``conf.instance`` searches the workspace ``config/`` directory first, then falls back to the library's bundled defaults. So toggling a latent in your @@ -81,9 +88,10 @@ imaging dataset that ships with the workspace. The model is a single galaxy with a Sersic bulge — keeping it small so the example runs in a reasonable time. -We pass ``magzero=25.0`` to ``ag.AnalysisImaging``. This is required by ``total_galaxy_0_flux_mujy`` (the flux -needs a photometric zero-point to convert into microjanskies). If you forget it, the latent computation will -raise ``ValueError`` with a message pointing here. +We pass ``magzero=25.0`` to ``ag.AnalysisImaging`` so ``total_galaxy_0_flux_mujy`` populates with a real value +rather than NaN. If you forget it, ``total_galaxy_0_flux_mujy`` will be NaN and the library will log a single +warning per process noting the conversion was skipped — the fit itself is unaffected, and the raw +``total_galaxy_0_flux`` column populates normally. """ dataset_name = "simple" dataset_path = Path("dataset") / "imaging" / dataset_name @@ -132,13 +140,14 @@ The returned object exposes the same API as the parameter ``Samples`` — ``median_pdf``, ``max_log_likelihood``, ``values_at_sigma_1``, and so on — but reports on the induced latent posterior rather than the parameter posterior. -Because ``total_galaxy_0_flux_mujy`` is the only enabled latent in this workspace, the returned instance only -exposes that single attribute. If you enable additional latents in the workspace yaml, they all appear as -attributes on the same instance. +Because both ``total_galaxy_0_flux`` and ``total_galaxy_0_flux_mujy`` are enabled in this workspace, the +returned instance exposes both attributes. If you enable additional latents in the workspace yaml, they all +appear as attributes on the same instance. """ latent_samples = analysis.compute_latent_samples(result.samples) median_instance = latent_samples.median_pdf() +print(f"Median PDF total_galaxy_0_flux: {median_instance.total_galaxy_0_flux}") print( f"Median PDF total_galaxy_0_flux_mujy: {median_instance.total_galaxy_0_flux_mujy}" ) diff --git a/scripts/guides/units/flux.py b/scripts/guides/units/flux.py index e59dc513..a27dad82 100644 --- a/scripts/guides/units/flux.py +++ b/scripts/guides/units/flux.py @@ -25,6 +25,7 @@ - **Zero Point:** Explanation of photometric zero points and their role in flux calibration. - **Mega Janskys / steradian (MJy/sr): James Webb Space Telescope:** Convert JWST NIRCam light profile intensities to AB magnitudes. +- **Latent Variables:** Reading the same total flux directly from the `latent.csv` of a completed fit. __Zero Point__ @@ -40,7 +41,7 @@ instrument that was used to observe the data. """ -# from autoconf import setup_notebook; setup_notebook() +# from autoconf import setup_notebook; setup_notebook() import numpy as np import autogalaxy as ag @@ -115,5 +116,50 @@ magnitude_ab = zero_point - 2.5 * np.log10(total_flux) """ +__Latent Variables: Total Flux Directly from the Fit__ + +The example above computed the total flux by hand: build a light profile, sample it on a grid, sum the image, then +apply the zero point. PyAutoGalaxy 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. + +The raw-flux latent ships default-on (it needs no instrument inputs and runs on every fit unless disabled in +`config/latent.yaml`): + +- `total_galaxy_0_flux` — total integrated flux of the first galaxy (`fit.galaxies[0]`), in the *raw* image + units the fit was performed in. For JWST data in MJy/sr, this is MJy/sr; for HST data in e- s^-1, this is + e- s^-1. + +To convert this to AB magnitudes or microjanskies, apply the same zero-point recipe used above. Suppose you +have a JWST F444W fit and want the AB magnitude of the galaxy; reading the column 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_galaxy_0_flux = pd.read_csv(search.paths.output_path / "latent" / "samples.csv")["total_galaxy_0_flux"].iloc[-1] +total_galaxy_0_flux = 1234.5 # MJy/sr + +# JWST F444W zero-point computed exactly as in the MJy/sr section above. +ab_mag_galaxy = ab_mag_via_flux_from(flux=total_galaxy_0_flux, magzero=zero_point) +flux_mujy_galaxy = flux_mujy_via_ab_mag_from(ab_mag=ab_mag_galaxy) + +""" +The two helpers used above are the same ones the library uses internally to populate the `_mujy` variant of the +latent (`total_galaxy_0_flux_mujy`). That variant is default-off because it needs a `magzero` you supply per +instrument. If you have a single fixed zero-point you can flip it on by: + +1. Setting `total_galaxy_0_flux_mujy: true` in your project's `config/latent.yaml`. +2. Passing `magzero=` when constructing the analysis: + `analysis = ag.AnalysisImaging(dataset=dataset, magzero=zero_point)`. + +The latent dispatcher then writes the converted µJy column into `latent/samples.csv` directly, so you don't +have to run the conversion in post. If you enable the `_mujy` latent but forget the `magzero` keyword, the +column is populated with NaN and a single warning per process notes that the conversion was skipped — the fit +itself is unaffected. + Finish. """