Repository navigation
feat: persist the interferometer primary beam through analysis save and aggregator rebuild #654
Description
Overview
Follow-up of PyAutoArray#644 (primary beam; hub #35, @HRSAstro). The beam is saved nowhere by AnalysisInterferometer.save_attributes, so an aggregator-rebuilt Interferometer / FitInterferometer loses it and the likelihood changes. Persist it as a trailing PRIMARY_BEAM HDU and pass it back into both rebuild constructors.
Plan
interferometer_hdu_list_from: append the beam (native float64, masked pixels 0) as a trailingPRIMARY_BEAMHDU in both the in-memory and array-free layouts; legacy indices unchanged.- Aggregator
_interferometer_from: detect the HDU by name (_has_hdu, never positional), passprimary_beam=intofrom_sparse_termsandaa.Interferometer. - PyAutoLens: docstring line + mirror round-trip test (reuses the autogalaxy functions, no source change).
- Tests: beamed round trips (in-memory, array-free) with identical beam arrays and identical log_likelihood / log_evidence / figure_of_merit, differing from the beamless fit; beamless writes no extra HDU (count pinned at 4) and reloads
primary_beam=None; old outputs without the HDU still load. - Tier: glance — merge mode: auto-merge on green if the Witness passes, post-merge summary (library-first: PyAutoGalaxy then PyAutoLens)
Detailed implementation plan
Affected Repositories
- PyAutoGalaxy (primary)
- PyAutoLens (docstring + mirror test)
Branch Survey
| Repository | Current Branch | Dirty? |
|---|---|---|
| galaxy/PyAutoGalaxy | main | clean |
| lens/PyAutoLens | main | clean (feature/point-source-image-overlay claimed by another task: PR #780 awaiting /prm; this task touches only test + docstring, separate branch) |
Suggested branch: feature/interferometer-primary-beam-persistence
Implementation Steps
See the prompt's "What" section (steps 1-4 with file:line anchors).
Key Files
autogalaxy/interferometer/model/analysis.py—interferometer_hdu_list_from(:76-218),save_attributes(:400-455)autogalaxy/aggregator/interferometer/interferometer.py—_interferometer_from(:161-235),_has_hdu(:50-59)test_autogalaxy/interferometer/model/test_analysis_interferometer.py— round-trip patterns (:148, :172-255, :258-285)autolens/interferometer/model/analysis.py(:336-339),test_autolens/interferometer/model/test_analysis_interferometer.py(:220)
Original Prompt
Click to expand starting prompt
Persist the interferometer primary beam through analysis save and aggregator rebuild
Type: feature
Target: PyAutoGalaxy
Repos:
- PyAutoGalaxy
- PyAutoLens
Difficulty: small
Autonomy: safe
Priority: medium
Parent: complete/2026/10/interferometer-primary-beam.md
Status: formalised
Consequence: glance
Witness: a test asserting an Interferometer with a primary beam saved by AnalysisInterferometer and rebuilt by the aggregator carries an identical primary_beam_slim
Review-minutes: 3
Unattended: ready
Filed: 2026-10-21
What (survey of main 2026-10-21, PyAutoArray at 034a616f incl. #644/#645)
The beam is saved nowhere today. interferometer_hdu_list_from (autogalaxy/interferometer/model/analysis.py:76-218) writes one FITS: in-memory branch HDUs MASK, DATA, NOISE_MAP, UV_WAVELENGTHS (:117-126); array-free branch MASK, NUFFT_PRECISION_OPERATOR, DIRTY_IMAGE, DIRTY_BEAM, SPARSE_TERMS_SCALARS (:129-217). save_attributes (:400-455) writes image/dataset.fits and transformer_class. The aggregator _interferometer_from (autogalaxy/aggregator/interferometer/interferometer.py:161-235) rebuilds via from_sparse_terms (:206-213) or aa.Interferometer(...) (:215-231); _hdu() falls back to legacy positional indices, so a new HDU must be detected with _has_hdu. PyAutoLens reuses both functions (no source change). FitInterferometer passes the dataset's transformer and sparse_operator to DatasetInterface, so passing primary_beam= back into the constructor is sufficient.
analysis.py: helper_primary_beam_native_from(dataset)→ None or the float64 native array (masked pixels 0) ofprimary_beam_slimonreal_space_mask; append it as a trailingPRIMARY_BEAMHDU in both branches (legacy indices 0-3 unchanged); docstrings.aggregator/interferometer/interferometer.py:_primary_beam_from(hdu_list)via_has_hdu; passprimary_beam=intofrom_sparse_termsandaa.Interferometer; docstrings.- Tests in
test_autogalaxy/interferometer/model/test_analysis_interferometer.py(extend the round-trip patterns at :148, :172-255, :258-285 with a Gaussian beam spanning ~0.3-1 oninterferometer_7): (a) in-memory beamed round trip — PRIMARY_BEAM present,primary_beam_slimandtransformer.primary_beam_slimidentical,FitInterferometer.log_likelihoodequal (rel 1e-10) for light-profile and pixelization galaxies, and different from the beamless fit; (b) array-free beamed round trip viafrom_stream(primary_beam=)—sparse_operator.primary_beam_slimidentical, log_evidence / figure_of_merit equal; (c) beamless writes no PRIMARY_BEAM HDU, HDU count pinned at 4, reload givesprimary_beam is None; (d) old outputs without the HDU still load withprimary_beam=Nonefor both layouts. - PyAutoLens: docstring line at
autolens/interferometer/model/analysis.py:336-339and a mirror beamed round-trip test next totest_autolens/interferometer/model/test_analysis_interferometer.py:220(optional, do it).
Not in scope: the pre-existing gap that an in-memory dataset with apply_sparse_operator comes back without the operator (likelihood still matches via the beamed transformer); the forced-numba fallback and repeated P=0 warning (PyAutoArray side, separate small prompt if wanted).
Activity
Jammy2211 commentedon Oct 21, 2026
Library PR created: #655 (head f7f6d79). Workspace impact: none. PyAutoLens docstring + mirror test deferred (checkout claimed by another task). Heart YELLOW acknowledged by the human 2026-10-21. Tier glance: auto-merge on green if the Witness passes.
Jammy2211 commentedon Oct 21, 2026
Shipped: #655 merged (glance tier, auto-merged on green: docs-build, unittest 3.12 / 3.13 / nojax all pass; Witness round-trip tests in-run). Pending release. Deferred follow-up: PyAutoLens docstring line + mirror round-trip test once its checkout claim clears.