Jammy2211 / PyAutoLens

PyAutoLens: Open Source Strong Gravitational Lensing
https://pyautolens.readthedocs.io/
MIT License
164 stars 32 forks source link

Pass Lens Light Model Based on Previous Pipeline #128

Closed Jammy2211 closed 3 years ago

Jammy2211 commented 4 years ago

I am redesigning pipelines such that you model the source -> lens light -> lens mass. The idea is the lens light pipeline should run irrespective of how the source pipeline was setup, and the mass pipeline irrespective of the source and lens light pipelines.

For example, in the mass pipeline, if the light model used in previous pipelines has 1 EllipticalSersic, it should use this model (with priors initialized from the fit in the previous phase). If the lens were 2 Sersics, a bulge + disk, it should use this.

We need an elegent way to setup a lens galaxy model in a mass pipeline using the result source model from the previous lens light pipeline.

For now, I have written a rather shoddy function to do this:

def lens_from_result(result, fix_lens_light):

    if hasattr(result, "light"):

        if fix_lens_light:

            light = result.instance.galaxies.lens.light

        else:

            light = result.model.galaxies.lens.light

        return aast.GalaxyModel(redshift=result.instance.galaxies.lens.redshift,
                                light=light)

    elif hasattr(result, "sersic"):

        if fix_lens_light:

            sersic = result.instance.galaxies.lens.sersic

        else:

            sersic = result.model.galaxies.lens.sersic

        return aast.GalaxyModel(redshift=result.instance.galaxies.lens.redshift,
                                sersic=sersic)

    elif hasattr(result, "bulge"):

        if fix_lens_light:

            bulge = result.instance.galaxies.lens.bulge
            disk = result.instance.galaxies.lens.disk

        else:

            bulge = result.model.galaxies.lens.bulge
            disk = result.model.galaxies.lens.disk

        return aast.GalaxyModel(redshift=result.instance.galaxies.lens.redshift, bulge=bulge, disk=disk)

The problem with the above code is the lens light must have attributes called "light", "bulge" and "disk". We want a function that automatically scans the properties of the result and determines the GalaxyModel whereby all light profiles are passed as models (with their original attribute name).

The fix_lens_light bool changes if the lens light is passed as a model or instance.

rhayes777 commented 4 years ago

You can now index a Promise with a type to obtain an iterable comprising all models and instances with that type.

For example, result.instance.galaxies.lens[LightProfile][0] would give the light profile associated with the lens regardless of its name.

Jammy2211 commented 4 years ago

The issue is probaly my understanding of autofit and promises.

I have created integration tests to show what we want to do and illustrating the issue, checkout:

test_autolens/integration/tests/result_passing/lens_light/

The following 4 integration tests behave as expected:

instance_via_phase_specify_light.py model_via_phase_specify_light.py instance_via_af_last_specify_light.py model_via_af_last_specify_light.py

The following 2 integrationo tests, which attempt to pass the lens light without specifying it, do not work and are illustrated in:

instance_via_af_last_dont_specify_light.py model_via_af_last_dont_specify_light.py