예제 #1
0
def make_pipeline(test_name):
    phase1 = ph.LensPlanePhase(lens_galaxies=[gm.GalaxyModel(sersic=lp.EllipticalSersic)],
                               optimizer_class=nl.MultiNest, phase_name="{}/phase1".format(test_name))

    phase1.optimizer.const_efficiency_mode = True
    phase1.optimizer.n_live_points = 40
    phase1.optimizer.sampling_efficiency = 0.8

    phase1h = ph.LensLightHyperOnlyPhase(optimizer_class=nl.MultiNest, phase_name="{}/phase1h".format(test_name))

    class LensHyperPhase(ph.LensPlaneHyperPhase):
        def pass_priors(self, previous_results):
            phase1_results = previous_results[-1]
            phase1h_results = previous_results[-1].hyper
            self.lens_galaxies = phase1_results.variable.lens_galaxies
            self.lens_galaxies[0].hyper_galaxy = phase1h_results.constant.lens_galaxies[0].hyper_galaxy

    phase2 = LensHyperPhase(lens_galaxies=[], optimizer_class=nl.MultiNest,
                            phase_name="{}/phase2".format(test_name))

    phase2.optimizer.const_efficiency_mode = True
    phase2.optimizer.n_live_points = 40
    phase2.optimizer.sampling_efficiency = 0.8

    return pl.PipelineImaging(test_name, phase1, phase1h, phase2)
예제 #2
0
    def test__phase_can_receive_list_of_galaxy_models(self):
        phase = ph.LensPlanePhase(lens_galaxies=[
            gm.GalaxyModel(sersic=lp.EllipticalSersic,
                           sis=mp.SphericalIsothermal,
                           variable_redshift=True),
            gm.GalaxyModel(sis=mp.SphericalIsothermal, variable_redshift=True)
        ],
                                  optimizer_class=non_linear.MultiNest,
                                  phase_name='test_phase')

        instance = phase.optimizer.variable.instance_from_physical_vector([
            0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.8, 0.1, 0.2, 0.3, 0.4, 0.9,
            0.5, 0.7, 0.8
        ])

        assert instance.lens_galaxies[0].sersic.centre[0] == 0.2
        assert instance.lens_galaxies[0].sis.centre[0] == 0.1
        assert instance.lens_galaxies[0].sis.centre[1] == 0.2
        assert instance.lens_galaxies[0].sis.einstein_radius == 0.3
        assert instance.lens_galaxies[0].redshift == 0.4
        assert instance.lens_galaxies[1].sis.centre[0] == 0.9
        assert instance.lens_galaxies[1].sis.centre[1] == 0.5
        assert instance.lens_galaxies[1].sis.einstein_radius == 0.7
        assert instance.lens_galaxies[1].redshift == 0.8

        class LensPlanePhase2(ph.LensPlanePhase):
            # noinspection PyUnusedLocal
            def pass_models(self, previous_results):
                self.lens_galaxies[0].sis.einstein_radius = prior.Constant(
                    10.0)

        phase = LensPlanePhase2(lens_galaxies=[
            gm.GalaxyModel(sersic=lp.EllipticalSersic,
                           sis=mp.SphericalIsothermal,
                           variable_redshift=True),
            gm.GalaxyModel(sis=mp.SphericalIsothermal, variable_redshift=True)
        ],
                                optimizer_class=non_linear.MultiNest,
                                phase_name='test_phase')

        # noinspection PyTypeChecker
        phase.pass_models(None)

        instance = phase.optimizer.variable.instance_from_physical_vector([
            0.01, 0.02, 0.23, 0.04, 0.05, 0.06, 0.87, 0.1, 0.2, 0.4, 0.5, 0.5,
            0.7, 0.8
        ])
        instance += phase.optimizer.constant

        assert instance.lens_galaxies[0].sersic.centre[0] == 0.01
        assert instance.lens_galaxies[0].sis.centre[0] == 0.1
        assert instance.lens_galaxies[0].sis.centre[1] == 0.2
        assert instance.lens_galaxies[0].sis.einstein_radius == 10.0
        assert instance.lens_galaxies[0].redshift == 0.4
        assert instance.lens_galaxies[1].sis.centre[0] == 0.5
        assert instance.lens_galaxies[1].sis.centre[1] == 0.5
        assert instance.lens_galaxies[1].sis.einstein_radius == 0.7
        assert instance.lens_galaxies[1].redshift == 0.8
예제 #3
0
def make_pipeline(test_name):

    phase1 = ph.LensPlanePhase(
        lens_galaxies=dict(lens=gm.GalaxyModel(sersic=lp.EllipticalSersic)),
        optimizer_class=nl.MultiNest,
        phase_name="{}/phase1".format(test_name))

    phase1.optimizer.const_efficiency_mode = True
    phase1.optimizer.n_live_points = 40
    phase1.optimizer.sampling_efficiency = 0.8

    return pl.PipelineImaging(test_name, phase1)
예제 #4
0
    def test__tracer_for_instance__includes_cosmology(self, ccd_data):
        lens_galaxy = g.Galaxy()
        source_galaxy = g.Galaxy()

        phase = ph.LensPlanePhase(lens_galaxies=[lens_galaxy],
                                  cosmology=cosmo.FLRW,
                                  phase_name='test_phase')
        analysis = phase.make_analysis(ccd_data)
        instance = phase.constant
        tracer = analysis.tracer_for_instance(instance)
        padded_tracer = analysis.padded_tracer_for_instance(instance)

        assert tracer.image_plane.galaxies[0] == lens_galaxy
        assert tracer.cosmology == cosmo.FLRW
        assert padded_tracer.image_plane.galaxies[0] == lens_galaxy
        assert padded_tracer.cosmology == cosmo.FLRW

        phase = ph.LensSourcePlanePhase(lens_galaxies=[lens_galaxy],
                                        source_galaxies=[source_galaxy],
                                        cosmology=cosmo.FLRW,
                                        phase_name='test_phase')
        analysis = phase.make_analysis(ccd_data)
        instance = phase.constant
        tracer = analysis.tracer_for_instance(instance)
        padded_tracer = analysis.padded_tracer_for_instance(instance)

        assert tracer.image_plane.galaxies[0] == lens_galaxy
        assert tracer.source_plane.galaxies[0] == source_galaxy
        assert tracer.cosmology == cosmo.FLRW
        assert padded_tracer.image_plane.galaxies[0] == lens_galaxy
        assert padded_tracer.source_plane.galaxies[0] == source_galaxy
        assert padded_tracer.cosmology == cosmo.FLRW

        galaxy_0 = g.Galaxy(redshift=0.1)
        galaxy_1 = g.Galaxy(redshift=0.2)
        galaxy_2 = g.Galaxy(redshift=0.3)

        phase = ph.MultiPlanePhase(galaxies=[galaxy_0, galaxy_1, galaxy_2],
                                   cosmology=cosmo.WMAP7,
                                   phase_name='test_phase')
        analysis = phase.make_analysis(ccd_data)
        instance = phase.constant
        tracer = analysis.tracer_for_instance(instance)
        padded_tracer = analysis.padded_tracer_for_instance(instance)

        assert tracer.planes[0].galaxies[0] == galaxy_0
        assert tracer.planes[1].galaxies[0] == galaxy_1
        assert tracer.planes[2].galaxies[0] == galaxy_2
        assert tracer.cosmology == cosmo.WMAP7
        assert padded_tracer.planes[0].galaxies[0] == galaxy_0
        assert padded_tracer.planes[1].galaxies[0] == galaxy_1
        assert padded_tracer.planes[2].galaxies[0] == galaxy_2
        assert padded_tracer.cosmology == cosmo.WMAP7
예제 #5
0
    def test__results_of_phase_are_available_as_properties(self, ccd_data):
        clean_images()

        phase = ph.LensPlanePhase(
            optimizer_class=NLO,
            lens_galaxies=[g.Galaxy(light=lp.EllipticalSersic(intensity=1.0))],
            phase_name='test_phase')

        result = phase.run(data=ccd_data)

        assert hasattr(result, "most_likely_tracer")
        assert hasattr(result, "most_likely_padded_tracer")
        assert hasattr(result, "most_likely_fit")
        assert hasattr(result, "unmasked_model_image")
        assert hasattr(result, "unmasked_model_image_of_planes")
        assert hasattr(result, "unmasked_model_image_of_planes_and_galaxies")
예제 #6
0
    def test__fit_figure_of_merit__matches_correct_fit_given_galaxy_profiles(
            self, ccd_data):

        lens_galaxy = g.Galaxy(light=lp.EllipticalSersic(intensity=0.1))
        source_galaxy = g.Galaxy(
            pixelization=pix.Rectangular(shape=(4, 4)),
            regularization=reg.Constant(coefficients=(1.0, )))

        phase = ph.LensPlanePhase(lens_galaxies=[lens_galaxy],
                                  mask_function=ph.default_mask_function,
                                  cosmology=cosmo.FLRW,
                                  phase_name='test_phase')
        analysis = phase.make_analysis(data=ccd_data)
        instance = phase.constant
        fit_figure_of_merit = analysis.fit(instance=instance)

        mask = phase.mask_function(image=ccd_data.image)
        lens_data = li.LensData(ccd_data=ccd_data, mask=mask)
        tracer = analysis.tracer_for_instance(instance=instance)
        fit = lens_fit.LensProfileFit(lens_data=lens_data, tracer=tracer)

        assert fit.likelihood == fit_figure_of_merit

        phase = ph.LensSourcePlanePhase(lens_galaxies=[lens_galaxy],
                                        source_galaxies=[source_galaxy],
                                        mask_function=ph.default_mask_function,
                                        cosmology=cosmo.FLRW,
                                        phase_name='test_phase')
        analysis = phase.make_analysis(data=ccd_data)
        instance = phase.constant
        fit_figure_of_merit = analysis.fit(instance=instance)

        mask = phase.mask_function(image=ccd_data.image)
        lens_data = li.LensData(ccd_data=ccd_data, mask=mask)
        tracer = analysis.tracer_for_instance(instance=instance)
        fit = lens_fit.LensProfileInversionFit(lens_data=lens_data,
                                               tracer=tracer)

        assert fit.evidence == fit_figure_of_merit
예제 #7
0
def make_pipeline(pipeline_path=''):

    # Pipelines takes a path as input, which in conjunction with the pipeline name specify the directory structure of
    # its results in the output folder. In pipeline runners we'll pass the pipeline path
    # 'howtolens/c3_t1_lens_and_source', which means the results of this pipeline will go to the folder
    # 'output/howtolens/c3_t1_lens_and_source/pipeline_light_and_source'.

    # By default, the pipeline path is an empty string, such that without a pipeline path the results go to the output
    # directory 'output/pipeline_name', which in this case would be 'output/pipeline_light_and_source'.

    # In the example pipelines supplied with PyAutoLens in the workspace/pipeline/examples folder, you'll see that
    # we pass the name of our strong lens data to the pipeline path. This allows us to fit a large sample of lenses
    # using one pipeline and store all of their results in an ordered directory structure.

    pipeline_name = 'pipeline_light_and_source'
    pipeline_path = pipeline_path + pipeline_name

    ### PHASE 1 ###

    # In chapter 2, we learnt how to mask data for a phase. For pipelines, we are probably going to want to change our
    # mask between phases. Afterall, the bigger the mask, the slower the run-time, so during the early phases of most
    # pipelines we're probably not too bothered about fitting all of the image. Aggresive masking (which removes lots
    # of image-pixels) is thus an appealing way to get things running fast.

    # In this phase, we're only interested in fitting the lens's light, so we'll mask out the source-galaxy entirely.
    # This'll give us a nice speed up and ensure the source's light doesn't impact our light-profile fit (albeit,
    # given the lack of covariance above, it wouldn't be disastrous either way).

    # We want a mask that is shaped like the source-galaxy. The shape of the source is an 'annulus' (e.g. a ring),
    # so we're going to use an annular masks. For example, if an annulus is specified between an inner radius of 0.5"
    # and outer radius of 2.0", all pixels in two rings between 0.5" and 2.0" are included in the analysis.

    # But wait, we actually want the opposite of this. We want a masks where the pixels between 0.5" and 2.0" are not
    # included! They're the pixels the source is actually located. Therefore, we're going to use an 'anti-annular
    # mask', where the inner and outer radii are the regions we omit from the analysis. This means we need to specify
    # a third ring of the masks, even further out, such that data at these exterior edges of the image are also masked.

    # We can change a mask using the 'mask_function', which basically returns the new masks we want to use (you can
    # actually use on phases by themselves like in the previous chapter).

    def mask_function(image):
        return msk.Mask.circular_anti_annular(shape=image.shape,
                                              pixel_scale=image.pixel_scale,
                                              inner_radius_arcsec=0.5,
                                              outer_radius_arcsec=1.6,
                                              outer_radius_2_arcsec=2.5)

    # We next create the phase, using the same notation we learnt before (but noting the masks function is passed to
    # this phase ensuring the anti-annular masks above is used).

    phase1 = phase.LensPlanePhase(
        lens_galaxies=dict(lens=gm.GalaxyModel(light=lp.EllipticalSersic)),
        optimizer_class=nl.MultiNest,
        mask_function=mask_function,
        phase_name=pipeline_path + '/phase_1_lens_light_only')

    # We'll use the MultiNest black magic we covered in tutorial 7 of chapter 2 to get this phase to run fast.

    phase1.optimizer.const_efficiency_mode = True
    phase1.optimizer.n_live_points = 30
    phase1.optimizer.sampling_efficiency = 0.5

    ### PHASE 2 ###

    # In phase 2, we fit the source galaxy's light. Thus, we want to make 2 changes from the previous phase

    # 1) We want to fit the lens subtracted image calculated in phase 1, instead of the observed image.
    # 2) We want to mask the central regions of this image, where there are residuals due to the lens light subtraction.

    # We can use the mask function again, to modify the mask to an annulus. We'll use the same ring radii as before.

    def mask_function(image):
        return msk.Mask.circular_annular(shape=image.shape,
                                         pixel_scale=image.pixel_scale,
                                         inner_radius_arcsec=0.5,
                                         outer_radius_arcsec=3.)

    # To modify an image, we call a new function, 'modify image'. This function behaves like the pass-priors functions
    # before, whereby we create a python 'class' in a Phase to set it up.  This ensures it has access to the pipeline's
    # 'previous_results' (which you may have noticed was in the the pass_priors functions as well, but we ignored it
    # thus far).

    # To setup the modified image, we take the observed image data and subtract-off the model image from the
    # previous phase, which, if you're keeping track, is an image of the lens galaxy. However, if we just used the
    # 'model_image' in the fit, this would only include pixels that were masked. We want to subtract the lens off the
    # entire image - fortunately, PyAutoLens automatically generates a 'unmasked_lens_plane_model_image' as well!

    class LensSubtractedPhase(phase.LensSourcePlanePhase):
        def modify_image(self, image, previous_results):
            phase_1_results = previous_results[0]
            return image - phase_1_results.unmasked_lens_plane_model_image

    # The function above demonstrates the most important thing about pipelines - that every phase has access to the
    # results of all previous phases. This means we can feed information through the pipeline and therefore use the
    # results of previous phases to setup new phases. We'll see this again in phase 3.

    # We setup phase 2 as per usual. Note that we don't need to pass the modify image function.

    phase2 = LensSubtractedPhase(
        lens_galaxies=dict(lens=gm.GalaxyModel(mass=mp.EllipticalIsothermal)),
        source_galaxies=dict(source=gm.GalaxyModel(light=lp.EllipticalSersic)),
        optimizer_class=nl.MultiNest,
        mask_function=mask_function,
        phase_name=pipeline_path + '/phase_2_source_only')

    phase2.optimizer.const_efficiency_mode = True
    phase2.optimizer.n_live_points = 50
    phase2.optimizer.sampling_efficiency = 0.3

    ### PHASE 3 ###

    # Finally, in phase 3, we want to fit the lens and source simultaneously. Whilst we made a point of them not being
    # covariant above, there will be some level of covariance that will, at the very least, impact the errors we infer.
    # Furthermore, if we did go on to fit a more complex model (say, a decomposed light and dark matter model - yeah,
    # you can do that in PyAutoLens!), fitting the lens's light and mass simultaneously would be crucial.

    # We'll use the 'pass_priors' function that we all know and love to do this. However, we're going to use the
    # 'previous_results' argument that, in chapter 2, we ignored. This stores the results of the lens model of
    # phase 1 and 2, meaning we can use it to initialize phase 3's priors!

    class LensSourcePhase(phase.LensSourcePlanePhase):
        def pass_priors(self, previous_results):

            # The previous results is a 'list' in python. The zeroth index entry of the list maps to the results of
            # phase 1, the first entry to phase 2, and so on.

            phase_1_results = previous_results[0]
            phase_2_results = previous_results[1]

            # To link two priors together, we invoke the 'variable' attribute of the previous results. By invoking
            # 'variable', this means that:

            # 1) The parameter will be a free-parameter fitted for by the non-linear search.
            # 2) It will use a GaussianPrior based on the previous results as its initialization (we'll cover how this
            #    Gaussian is setup in tutorial 4, for now just imagine it links the results in a sensible way).

            # We can simple link every source galaxy parameter to its phase 2 inferred value, as follows

            self.source_galaxies.source.light.centre_0 = phase_2_results.variable.source.light.centre_0
            self.source_galaxies.source.light.centre_1 = phase_2_results.variable.source.light.centre_1
            self.source_galaxies.source.light.axis_ratio = phase_2_results.variable.source.light.axis_ratio
            self.source_galaxies.source.light.phi = phase_2_results.variable.source.light.phi
            self.source_galaxies.source.light.intensity = phase_2_results.variable.source.light.intensity
            self.source_galaxies.source.light.effective_radius = phase_2_results.variable.source.light.effective_radius
            self.source_galaxies.source.light.sersic_index = phase_2_results.variable.source.light.sersic_index

            # However, listing every parameter like this is ugly, and is combersome if we have a lot of parameters.

            # If, like in the above example, you are making all of the parameters of a lens or source galaxy variable,
            # you can simply set the source galaxy equal to one another, without specifying each parameter of every
            # light and mass profile.

            self.source_galaxies.source = phase_2_results.variable.source  # This is identical to lines 196-203 above.

            # For the lens galaxies, we have a slightly weird circumstance where the light profiles requires the
            # results of phase 1 and the mass profile the results of phase 2. When passing these as a 'variable', we
            # can split them as follows

            self.lens_galaxies.lens.light = phase_1_results.variable.lens.light
            self.lens_galaxies.lens.mass = phase_2_results.variable.lens.mass

    phase3 = LensSourcePhase(
        lens_galaxies=dict(lens=gm.GalaxyModel(light=lp.EllipticalSersic,
                                               mass=mp.EllipticalIsothermal)),
        source_galaxies=dict(source=gm.GalaxyModel(light=lp.EllipticalSersic)),
        optimizer_class=nl.MultiNest,
        phase_name=pipeline_path + '/phase_3_both')

    phase3.optimizer.const_efficiency_mode = True
    phase3.optimizer.n_live_points = 50
    phase3.optimizer.sampling_efficiency = 0.3

    return pipeline.PipelineImaging(pipeline_path, phase1, phase2, phase3)