Skip to content

feat: accept bare MassField in the fields slot - #744

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/mass-field-bare-fields
Sep 18, 2026
Merged

Jammy2211 merged 1 commit into
mainfrom
feature/mass-field-bare-fields

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Summary

A model using fields=af.Model(al.MassField, ...) currently builds but fails when analysis constructs its tracer. Normalize a bare field to a one-element list across analysis, aggregation, Result and direct/sliced Tracer construction, before checking the mass/light geometry.

Closes #743.

API Changes

The public API is widened additively: fields=field joins the existing collection/list form. Collections remain the primary documented model form. No workspace migration or PyAutoGalaxy change is needed. See full details below.

The two forms have different identifiers by design because their prior paths differ. Before any source edits, a subprocess under shipped configuration reproduced:

Form Prior count Shear prior path Identifier
Collection 14 fields.field.shear.gamma_1 c5cf98ea7733689dc8c0ede6939c1d83
Flat 14 fields.shear.gamma_1 36a0be37c9667958bafca2f01e487f80

The new subprocess regression pins both identifiers, counts and shear paths, and checks that all galaxy prior paths match. Existing validation tests and both existing identifier tests remain unmodified.

Test Plan

  • Capture baseline before source edits.
  • Run flat-model witness red on source at 7197380.
  • Focused suite: 84 passed, including JSON byte parity, nonzero convergence, warnings, sliced-plane snapping, Result and aggregator paths.
  • Full NUMBA_CACHE_DIR=/tmp/numba_cache MPLCONFIGDIR=/tmp/matplotlib python -m pytest test_autolens/: 739 passed, 1 xfailed, 34 warnings in 156.77s.
  • Downstream smoke checks: all six workspaces passed (table below).
Workspace Passed Failed Skipped
autofit_workspace 10 0 0
autogalaxy_workspace 16 0 0
autolens_workspace 40 0 0
autolens_workspace_test 32 0 0
euclid_strong_lens_modeling_pipeline 9 0 0
HowToLens 50 0 0
  • Independent Sol review: CLEAN; end-to-end probes verified all five folds, identifier pins and geometry warning.
Red witness traceback (before source edits)
F                                                                        [100%]
=================================== FAILURES ===================================
___ test__tracer_via_instance_from__bare_field_is_folded_into_tracer_fields ____

analysis_imaging_7x7 = <autolens.imaging.model.analysis.AnalysisImaging object at 0x7f13c93241a0>

    def test__tracer_via_instance_from__bare_field_is_folded_into_tracer_fields(
        analysis_imaging_7x7,
    ):
        model = af.Collection(
            galaxies=af.Collection(
                lens=af.Model(al.Galaxy, redshift=0.5, mass=al.mp.Isothermal),
                source=af.Model(al.Galaxy, redshift=1.0, bulge=al.lp.Sersic),
            ),
            fields=af.Model(
                al.MassField, redshift=0.5, shear=af.Model(al.mp.ExternalShear)
            ),
        )
        instance = model.instance_from_prior_medians()
    
>       tracer = analysis_imaging_7x7.tracer_via_instance_from(instance=instance)

test_autolens/analysis/analysis/test_analysis_lens.py:168: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <autolens.imaging.model.analysis.AnalysisImaging object at 0x7f13c93241a0>
instance = <autofit.mapper.model.ModelInstance object at 0x7f13c9003bf0>

    def tracer_via_instance_from(
        self,
        instance: af.ModelInstance,
    ) -> Tracer:
        """
        Create a `Tracer` from the galaxies contained in a model instance.
    
        Parameters
        ----------
        instance
            An instance of the model that is fitted to the data by this analysis (whose parameters may have been set
            via a non-linear search).
    
        Returns
        -------
        Tracer
            An instance of the Tracer class that is used to then fit the dataset.
        """
        if hasattr(instance, "perturb"):
            instance.galaxies.subhalo = instance.perturb
    
        # TODO : Need to think about how we do this without building it into the model attribute names.
        # TODO : A Subhalo class that extends the Galaxy class maybe?
    
        if hasattr(instance.galaxies, "subhalo"):
            subhalo_centre = tracer_util.grid_2d_at_redshift_from(
                galaxies=instance.galaxies,
                redshift=instance.galaxies.subhalo.redshift,
                grid=aa.Grid2DIrregular(
                    values=[instance.galaxies.subhalo.mass.centre], xp=self._xp
                ),
                cosmology=self.cosmology,
                xp=self._xp,
            )
    
            instance.galaxies.subhalo.mass.centre = tuple(subhalo_centre.in_list[0])
    
        if hasattr(instance, "cosmology"):
            cosmology = instance.cosmology
        else:
            cosmology = self.cosmology
    
        galaxy_list = list(instance.galaxies)
    
        if hasattr(instance, "extra_galaxies"):
            if getattr(instance, "extra_galaxies", None) is not None:
                galaxy_list += list(instance.extra_galaxies)
    
        if hasattr(instance, "scaling_galaxies"):
            if getattr(instance, "scaling_galaxies", None) is not None:
                galaxy_list += list(instance.scaling_galaxies)
    
        # A model may declare an external field alongside its galaxies, as
        # `af.Collection(galaxies=..., fields=af.Collection(field=af.Model(al.MassField, ...)))`.
        # It is folded here rather than into `galaxy_list`, because a `MassField` is not a galaxy.
        fields = (
>           list(instance.fields)
            if getattr(instance, "fields", None) is not None
            else None
        )
E       TypeError: 'MassField' object is not iterable

autolens/analysis/analysis/lens.py:139: TypeError
---------------------------- Captured stdout setup -----------------------------
2026-09-18 09:15:55,494 - autoarray.dataset.imaging.dataset - INFO - IMAGING - Data masked, contains a total of 9 image-pixels
=========================== short test summary info ============================
FAILED test_autolens/analysis/analysis/test_analysis_lens.py::test__tracer_via_instance_from__bare_field_is_folded_into_tracer_fields
1 failed, 4 deselected in 2.52s

Full API Changes (for automation & release notes)

Changed Signature

  • autolens.Tracer(..., fields=...) and autolens.Tracer.sliced_tracer_from(..., fields=...) annotations now include a single MassField.

Changed Behaviour

  • The model's fields slot accepts one instantiated MassField as well as the existing collection; analysis, saved-result aggregation and Result.max_log_likelihood_fields normalize it to a list.
  • Direct and sliced tracer construction accept a bare MassField; tracer.fields remains a fresh plain list, never None.
  • Field normalization precedes MultiPlaneRedshiftWarning checks, preserving geometry diagnostics.

Migration

  • None required. fields=af.Collection(field=field) retains its prior paths, prior count and result identifier. Opting into fields=field shortens the prior paths and intentionally changes its result identifier.
  • The helper autolens.lens.tracer_util.fields_list_from is internal and is not exported in autolens.__init__ or API autosummary.

Generated by the PyAutoLabs agent workflow.

Heart RED development-shipping override

Human development-shipping override recorded for PyAutoLens #743 on 2026-09-18.

I authorize, raise pr and merge when CI is green. Then give me a prompt to apply this to euclid strong lens modeling pipeline (if not already done) and update the euclid_dr1 science project, including HPYPyAutoPull, whihc ill put in another codex chat

Current Heart RED: release validation FAILED (stage integrate).
Current YELLOW: manifest drift: remote-session blocks (generated) — 2 mismatch(es) vs PyAutoMind/repos.yaml.

Passed branch gates: 739 passed / 1 xfailed (full suite); 157 downstream smoke checks; independent Sol review CLEAN. Collection identifier reproduced and pinned unchanged; red witness captured before source edits.

Authorized: commit, push, pending-release PR; merge in this turn only if every CI workflow/matrix leg is green and other merge gates pass. No release or CI bypass; this feature does not repair Heart.

@Jammy2211 Jammy2211 added the pending-release PR queued for the next release build label Sep 18, 2026
@Jammy2211
Jammy2211 merged commit 478213e into main Sep 18, 2026
4 checks passed
@Jammy2211
Jammy2211 deleted the feature/mass-field-bare-fields branch September 18, 2026 09:25
@Jammy2211

Copy link
Copy Markdown
Collaborator Author

Euclid pipeline adoption: PyAutoLabs/euclid_strong_lens_modeling_pipeline#90 (bare single-field models; source-checkout deployment).

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.

feat: accept a bare MassField in the fields slot

1 participant