From 50d673269c19de4bc89c2c29d4a41beb0683c986 Mon Sep 17 00:00:00 2001 From: Jammy2211 Date: Sat, 19 Sep 2026 15:51:59 +0100 Subject: [PATCH] test: pin MassField retention in chained lens models --- docs/general/model_cookbook.md | 17 ++++++++ .../analysis/test_chaining_fields.py | 42 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 test_autolens/analysis/test_chaining_fields.py diff --git a/docs/general/model_cookbook.md b/docs/general/model_cookbook.md index 08f16c6ba..09b155187 100644 --- a/docs/general/model_cookbook.md +++ b/docs/general/model_cookbook.md @@ -631,6 +631,23 @@ The following example notebooks show how to compose and fit these models: When performing non-linear search chaining, the inferred model of one phase can be linked to the model. +For a model with a separate external field, carry the mass and field together: + +```python +mass, field = al.util.chaining.mass_and_fields_from( + mass=af.Model(al.mp.PowerLaw), + mass_result=result_1.model.galaxies.lens.mass, + fields_result=result_1.model.fields, +) +model_2 = af.Collection( + galaxies=af.Collection(lens=af.Model(al.Galaxy, redshift=0.5, mass=mass), source=source), + fields=field, +) +``` + +`result_1.model.fields` passes posterior priors into the next stage; use +`result_1.instance.fields` to fix the field to the previous fit's values. + The following example notebooks show how to compose and fit these models: diff --git a/test_autolens/analysis/test_chaining_fields.py b/test_autolens/analysis/test_chaining_fields.py new file mode 100644 index 000000000..af46c6dbb --- /dev/null +++ b/test_autolens/analysis/test_chaining_fields.py @@ -0,0 +1,42 @@ +import autofit as af +import autolens as al + + +def test_chained_mass_and_fields_keep_external_shear_in_model_and_tracer(): + stage_1 = af.Collection( + galaxies=af.Collection( + lens=af.Model(al.Galaxy, redshift=0.5, mass=af.Model(al.mp.Isothermal)), + source=af.Model(al.Galaxy, redshift=1.0, bulge=af.Model(al.lp.Sersic)), + ), + fields=af.Model( + al.MassField, redshift=0.5, shear=af.Model(al.mp.ExternalShear) + ), + ) + + mass, field = al.util.chaining.mass_and_fields_from( + mass=af.Model(al.mp.PowerLaw), + mass_result=stage_1.galaxies.lens.mass, + fields_result=stage_1.fields, + ) + stage_2 = af.Collection( + galaxies=af.Collection( + lens=af.Model(al.Galaxy, redshift=0.5, mass=mass), + source=stage_1.galaxies.source, + ), + fields=field, + ) + + assert ("fields", "shear", "gamma_1") in stage_2.unique_prior_paths + + instance = stage_2.instance_from_prior_medians() + tracer = al.Tracer(galaxies=instance.galaxies, fields=instance.fields) + assert len(tracer.fields) == 1 + assert isinstance(tracer.fields[0], al.MassField) + + _, fixed_field = al.util.chaining.mass_and_fields_from( + mass=af.Model(al.mp.PowerLaw), + mass_result=stage_1.galaxies.lens.mass, + fields_result=stage_1.instance_from_prior_medians().fields, + ) + fixed_stage = af.Collection(galaxies=stage_2.galaxies, fields=fixed_field) + assert ("fields", "shear", "gamma_1") not in fixed_stage.unique_prior_paths