From a68479b24c373f9a05cc388134482002464073ed Mon Sep 17 00:00:00 2001 From: Jammy2211 Date: Fri, 17 Jul 2026 09:00:23 +0100 Subject: [PATCH] Add intermediate= option to from_coolest from_coolest(..., intermediate=True) rebuilds COOLEST PEMD profiles as ag.mp.PowerLawIntermediate (theta_E passes through unchanged) instead of the default PowerLaw. Companion to the PyAutoGalaxy PowerLawIntermediate PR on this branch. Part of PyAutoLabs/PyAutoLens#616. Co-Authored-By: Claude Fable 5 --- autolens/interop/coolest.py | 7 ++++++ test_autolens/interop/test_coolest.py | 36 +++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/autolens/interop/coolest.py b/autolens/interop/coolest.py index a399fdcd0..726b98af0 100644 --- a/autolens/interop/coolest.py +++ b/autolens/interop/coolest.py @@ -271,6 +271,7 @@ def _parameters_from(coolest_profile) -> Dict: def from_coolest( file_path: str, cosmology: Optional[ag.cosmo.LensingCosmology] = None, + intermediate: bool = False, ) -> Tracer: """ Build a ``Tracer`` from the analytic profiles of a COOLEST JSON template @@ -290,6 +291,11 @@ def from_coolest( The cosmology of the returned ``Tracer``. Defaults to a ``FlatLambdaCDM`` built from the template's H0 / Om0 (or ``ag.cosmo.Planck15`` if the template has none). + intermediate + If True, PEMD profiles are built as ``ag.mp.PowerLawIntermediate`` + (whose ``einstein_radius`` is the template's ``theta_E`` unchanged) + instead of the default ``ag.mp.PowerLaw``. Both give the identical + mass distribution. """ _, _, _, JSONSerializer = _coolest_modules() @@ -340,6 +346,7 @@ def from_coolest( profile_type=coolest_profile.type, parameters=_parameters_from(coolest_profile), sigma_crit=sigma_crit, + intermediate=intermediate, ) galaxies.append( diff --git a/test_autolens/interop/test_coolest.py b/test_autolens/interop/test_coolest.py index c959aa33f..920ccab65 100644 --- a/test_autolens/interop/test_coolest.py +++ b/test_autolens/interop/test_coolest.py @@ -146,6 +146,42 @@ def test__round_trip__nfw_uses_sigma_crit_from_cosmology(tmp_path): assert nfw_default.kappa_s == pytest.approx(0.15, rel=1e-3) +def test__from_coolest__intermediate_returns_power_law_intermediate(tmp_path): + import autogalaxy as ag + + galaxies = [ + al.Galaxy( + redshift=0.5, + mass=al.mp.PowerLawIntermediate( + centre=(0.0, 0.0), + ell_comps=al.convert.ell_comps_from(axis_ratio=0.7, angle=45.0), + einstein_radius=1.2, + slope=2.1, + ), + ), + al.Galaxy(redshift=1.0, bulge=al.lp.SersicSph(intensity=0.5)), + ] + + file_path = interop_coolest.to_coolest( + galaxies=galaxies, file_path=str(tmp_path / "template") + ) + + tracer_back = interop_coolest.from_coolest( + file_path=file_path, intermediate=True + ) + + mass_back = [g for g in tracer_back.galaxies if g.redshift == 0.5][0].mass_0 + + assert isinstance(mass_back, ag.mp.PowerLawIntermediate) + assert mass_back.einstein_radius == pytest.approx(1.2, rel=1e-12) + + grid = al.Grid2DIrregular([[1.0, 0.5], [-0.3, 0.7]]) + tracer = al.Tracer(galaxies=galaxies) + assert np.asarray( + tracer_back.deflections_yx_2d_from(grid=grid) + ) == pytest.approx(np.asarray(tracer.deflections_yx_2d_from(grid=grid)), rel=1e-8) + + def test__round_trip__relative_file_path(tmp_path, monkeypatch): # The coolest JSONSerializer rejects relative paths — to_coolest / # from_coolest must absolutize them.