passed to a unique `Model` for each `Gaussian`. This means all three `Gaussian`'s will be fitted wih the same value of `centre`. """ centre_shared_prior = af.GaussianPrior(mean=50.0, sigma=30.0) """ We now set up three `Collection`'s, each of which contain a `Gaussian` that is used to fit each of the datasets we loaded above. All three of these `Collection`'s use the `centre_shared_prior`. This means all three `Gaussian` model-components use the same value of `centre` when model-fitting is performed reducing the dimensionality of parameter space from N=9 (e.g. 3 parameters per Gaussian) to N=7. Our graphical model therefore consists of three `Gaussians` with local parameters (a unique `normalization` and `sigma`) for each `Gaussian` and a global parameter for the graphical model (the `centre` of all three `Gaussians`). """ gaussian_0 = af.Model(m.Gaussian) gaussian_0.centre = centre_shared_prior gaussian_0.normalization = af.GaussianPrior(mean=10.0, sigma=10.0) gaussian_0.sigma = af.GaussianPrior( mean=10.0, sigma=10.0) # This prior is used by all 3 Gaussians! prior_model_0 = af.Collection(gaussian=gaussian_0) gaussian_1 = af.Model(m.Gaussian) gaussian_1.centre = centre_shared_prior gaussian_1.normalization = af.GaussianPrior(mean=10.0, sigma=10.0) gaussian_1.sigma = af.GaussianPrior( mean=10.0, sigma=10.0) # This prior is used by all 3 Gaussians! prior_model_1 = af.Collection(gaussian=gaussian_1)
def with_lens_light( settings_autofit: slam_util.SettingsAutoFit, analysis: Union[al.AnalysisImaging, al.AnalysisInterferometer], setup_hyper: al.SetupHyper, source_results: af.ResultsCollection, light_results: af.ResultsCollection, lens_bulge: af.Model(al.lp.LightProfile) = af.Model(al.lp.EllSersic), lens_disk: af.Model(al.lp.LightProfile) = None, lens_envelope: af.Model(al.lp.LightProfile) = None, dark: af.Model(al.mp.MassProfile) = af.Model(al.mp.EllNFWMCRLudlow), smbh: af.Model(al.mp.MassProfile) = None, einstein_mass_range: Optional[Tuple[float, float]] = (0.01, 5.0), end_with_hyper_extension: bool = False, ) -> af.ResultsCollection: """ The SLaM MASS LIGHT DARK PIPELINE for fitting imaging data with a lens light component. Parameters ---------- analysis The analysis class which includes the `log_likelihood_function` and can be customized for the SLaM model-fit. setup_hyper The setup of the hyper analysis if used (e.g. hyper-galaxy noise scaling). source_results The results of the SLaM SOURCE PARAMETRIC PIPELINE or SOURCE INVERSION PIPELINE which ran before this pipeline. light_results The results of the SLaM LIGHT PARAMETRIC PIPELINE which ran before this pipeline. mass The `MassProfile` used to fit the lens galaxy mass in this pipeline. smbh The `MassProfile` used to fit the a super massive black hole in the lens galaxy. lens_bulge The `LightMassProfile` `Model` used to represent the light and stellar mass distribution of the lens galaxy's bulge (set to None to omit a bulge). lens_disk The `LightMassProfile` `Model` used to represent the light and stellar mass distribution of the lens galaxy's disk (set to None to omit a disk). lens_envelope The `LightMassProfile` `Model` used to represent the light and stellar mass distribution of the lens galaxy's envelope (set to None to omit an envelope). dark The `MassProfile` `Model` used to represent the dark matter distribution of the lens galaxy's (set to None to omit dark matter). einstein_mass_range The values a the estimate of the Einstein Mass in the LIGHT PIPELINE is multiplied by to set the lower and upper limits of the profile's mass-to-light ratio. end_with_hyper_extension If `True` a hyper extension is performed at the end of the pipeline. If this feature is used, you must be certain you have manually passed the new hyper images geneted in this search to the next pipelines. """ """ __Model + Search + Analysis + Model-Fit (Search 1)__ In search 1 of the MASS LIGHT DARK PIPELINE we fit a lens model where: - The lens galaxy light and stellar mass is modeled using light and mass profiles [Priors on light model parameters initialized from LIGHT PIPELINE]. - The lens galaxy dark mass is modeled using a dark mass distribution [No prior initialization]. - The source galaxy's light is parametric or an inversion depending on the previous pipeline [Model and priors initialized from SOURCE PIPELINE]. This search aims to accurately estimate the lens mass model, using the improved mass model priors and source model of the SOURCE PIPELINE and LIGHT PIPELINE. The `mass_to_light_ratio` prior of each light and stellar profile is set using the Einstein Mass estimate of the SOURCE PIPELINE, specifically using values which are 1% and 500% this estimate. The dark matter mass profile has the lens and source redshifts added to it, which are used to determine its mass from the mass-to-concentration relation of Ludlow et al. """ lens_bulge = slam_util.pass_light_and_mass_profile_priors( model=lens_bulge, result_light_component=light_results.last.model.galaxies.lens.bulge, result=light_results.last, einstein_mass_range=einstein_mass_range, ) lens_disk = slam_util.pass_light_and_mass_profile_priors( model=lens_disk, result_light_component=light_results.last.model.galaxies.lens.disk, result=light_results.last, einstein_mass_range=einstein_mass_range, ) lens_envelope = slam_util.pass_light_and_mass_profile_priors( model=lens_envelope, result_light_component=light_results.last.model.galaxies.lens.envelope, result=light_results.last, einstein_mass_range=einstein_mass_range, ) dark.mass_at_200 = af.LogUniformPrior(lower_limit=1e10, upper_limit=1e15) dark.redshift_object = light_results.last.instance.galaxies.lens.redshift dark.redshift_source = light_results.last.instance.galaxies.source.redshift if smbh is not None: smbh.centre = lens_bulge.centre source = slam_util.source__from_result_model_if_parametric( result=source_results.last, setup_hyper=setup_hyper ) model = af.Collection( galaxies=af.Collection( lens=af.Model( al.Galaxy, redshift=light_results.last.instance.galaxies.lens.redshift, bulge=lens_bulge, disk=lens_disk, envelope=lens_envelope, dark=dark, shear=source_results.last.model.galaxies.lens.shear, smbh=smbh, hyper_galaxy=setup_hyper.hyper_galaxy_lens_from_result( result=light_results.last ), ), source=source, ), hyper_image_sky=setup_hyper.hyper_image_sky_from_result( result=light_results.last, as_model=True ), hyper_background_noise=setup_hyper.hyper_background_noise_from_result( result=light_results.last ), ) search = af.DynestyStatic( path_prefix=settings_autofit.path_prefix, name="mass_light_dark[1]_light[parametric]_mass[light_dark]_source", unique_tag=settings_autofit.unique_tag, number_of_cores=settings_autofit.number_of_cores, session=settings_autofit.session, nlive=100, ) result_1 = search.fit(model=model, analysis=analysis, info=settings_autofit.info) """ __Hyper Extension__ The above search may be extended with a hyper-search, if the SetupHyper has one or more of the following inputs: - The source is using an `Inversion`. - One or more `HyperGalaxy`'s are included. - The background sky is included via `hyper_image_sky` input. - The background noise is included via the `hyper_background_noise`. """ if end_with_hyper_extension: result_1 = extensions.hyper_fit( setup_hyper=setup_hyper, result=result_1, analysis=analysis, include_hyper_image_sky=True, ) return af.ResultsCollection([result_1])
- Uses a parametric `EllSersic` bulge for the source's light (omitting a disk / envelope). - Uses an `EllIsothermal` model for the lens's total mass distribution with an `ExternalShear`. __Settings__: - Mass Centre: Fix the mass profile centre to (0.0, 0.0) (this assumption will be relaxed in the MASS TOTAL PIPELINE). """ analysis = al.AnalysisImaging(dataset=imaging) source_parametric_results = slam.source_parametric.no_lens_light( path_prefix=path_prefix, unique_tag=dataset_name, analysis=analysis, setup_hyper=setup_hyper, mass=af.Model(al.mp.EllIsothermal), shear=af.Model(al.mp.ExternalShear), source_bulge=af.Model(al.lp.EllSersic), mass_centre=(0.0, 0.0), redshift_lens=0.5, redshift_source=1.0, ) """ __MASS TOTAL PIPELINE (no lens light)__ The MASS TOTAL PIPELINE (no lens light) uses one search to fits a complex lens mass model to a high level of accuracy, using the lens mass model and source model of the SOURCE PIPELINE to initialize the model priors. In this example it: - Uses an `EllPowerLaw` model for the lens's total mass distribution [priors initialized from SOURCE PARAMETRIC PIPELINE + The centre if unfixed from (0.0, 0.0)].
def with_lens_light( settings_autofit: af.SettingsSearch, analysis: Union[al.AnalysisImaging, al.AnalysisInterferometer], setup_hyper: al.SetupHyper, lens_bulge: Optional[af.Model] = af.Model(al.lp.EllSersic), lens_disk: Optional[af.Model] = af.Model(al.lp.EllExponential), lens_envelope: Optional[af.Model] = None, mass: af.Model = af.Model(al.mp.EllIsothermal), shear: af.Model(al.mp.ExternalShear) = af.Model(al.mp.ExternalShear), source_bulge: Optional[af.Model] = af.Model(al.lp.EllSersic), source_disk: Optional[af.Model] = None, source_envelope: Optional[af.Model] = None, redshift_lens: float = 0.5, redshift_source: float = 1.0, mass_centre: Optional[Tuple[float, float]] = None, ) -> af.ResultsCollection: """ The SlaM SOURCE PARAMETRIC PIPELINE for fitting imaging data with a lens light component. Parameters ---------- analysis The analysis class which includes the `log_likelihood_function` and can be customized for the SLaM model-fit. setup_hyper The setup of the hyper analysis if used (e.g. hyper-galaxy noise scaling). lens_bulge The `LightProfile` `Model` used to represent the light distribution of the lens galaxy's bulge (set to None to omit a bulge). lens_disk The `LightProfile` `Model` used to represent the light distribution of the lens galaxy's disk (set to None to omit a disk). lens_envelope The `LightProfile` `Model` used to represent the light distribution of the lens galaxy's envelope (set to None to omit an envelope). mass The `MassProfile` fitted by this pipeline. shear The model used to represent the external shear in the mass model (set to None to turn off shear). bulge_prior_model : af.Model(lp.LightProfile) source_bulge The `LightProfile` `Model` used to represent the light distribution of the source galaxy's bulge (set to None to omit a bulge). source_disk The `LightProfile` `Model` used to represent the light distribution of the source galaxy's disk (set to None to omit a disk). source_envelope The `LightProfile` `Model` used to represent the light distribution of the source galaxy's envelope (set to None to omit an envelope). redshift_lens The redshift of the lens galaxy fitted, used by the pipeline for converting arc-seconds to kpc, masses to solMass, etc. redshift_source The redshift of the source galaxy fitted, used by the pipeline for converting arc-seconds to kpc, masses to solMass, etc. mass_centre If input, a fixed (y,x) centre of the mass profile is used which is not treated as a free parameter by the non-linear search. """ """ __Model + Search + Analysis + Model-Fit (Search 1)__ In search 1 of the SOURCE PARAMETRIC PIPELINE we fit a lens model where: - The lens galaxy light is modeled using parametric bulge + disk + envelope [no prior initialization]. - The lens's mass and source galaxy are omitted from the fit. This search aims to produce a somewhat accurate lens light subtracted image for the next search which fits the the lens mass model and source model. """ lens = af.Model( al.Galaxy, redshift=redshift_lens, bulge=lens_bulge, disk=lens_disk, envelope=lens_envelope, ) model = af.Collection(galaxies=af.Collection(lens=lens)) search = af.DynestyStatic( name="source_parametric[1]_light[parametric]", **settings_autofit.search_dict, nlive=75, ) result_1 = search.fit(model=model, analysis=analysis, **settings_autofit.fit_dict) """ __Model + Search + Analysis + Model-Fit (Search 2)__ In search 2 of the SOURCE PARAMETRIC PIPELINE we fit a lens model where: - The lens galaxy light is modeled using a parametric bulge + disk + envelope [fixed to result of Search 1]. - The lens galaxy mass is modeled using a total mass distribution [no prior initialization]. - The source galaxy's light is a parametric bulge + disk + envelope [no prior initialization]. This search aims to accurately estimate the lens mass model and source model. """ if mass_centre is not None: mass.centre = mass_centre model = af.Collection(galaxies=af.Collection( lens=af.Model( al.Galaxy, redshift=redshift_lens, bulge=result_1.instance.galaxies.lens.bulge, disk=result_1.instance.galaxies.lens.disk, envelope=result_1.instance.galaxies.lens.envelope, mass=mass, shear=shear, ), source=af.Model( al.Galaxy, redshift=redshift_source, bulge=source_bulge, disk=source_disk, envelope=source_envelope, ), )) search = af.DynestyStatic( name="source_parametric[2]_light[fixed]_mass[total]_source[parametric]", **settings_autofit.search_dict, nlive=200, walks=10, ) result_2 = search.fit(model=model, analysis=analysis, **settings_autofit.fit_dict) """ __Model + Search + Analysis + Model-Fit (Search 3)__ In search 2 of the SOURCE PARAMETRIC PIPELINE we fit a lens model where: - The lens galaxy light is modeled using a parametric bulge + disk + envelope [priors are not initialized from previous searches]. - The lens galaxy mass is modeled using a total mass distribution [priors initialized from search 2]. - The source galaxy's light is a parametric bulge + disk + envelope [priors initialized from search 2]. This search aims to accurately estimate the lens light model, mass model and source model. """ model = af.Collection(galaxies=af.Collection( lens=af.Model( al.Galaxy, redshift=redshift_lens, bulge=lens_bulge, disk=lens_disk, envelope=lens_envelope, mass=result_2.model.galaxies.lens.mass, shear=result_2.model.galaxies.lens.shear, ), source=af.Model( al.Galaxy, redshift=redshift_source, bulge=result_2.model.galaxies.source.bulge, disk=result_2.model.galaxies.source.disk, envelope=result_2.model.galaxies.source.envelope, ), )) search = af.DynestyStatic( name= "source_parametric[3]_light[parametric]_mass[total]_source[parametric]", **settings_autofit.search_dict, nlive=250, walks=10, ) result_3 = search.fit(model=model, analysis=analysis, **settings_autofit.fit_dict) """ __Hyper Extension__ The above search is extended with a hyper-search if the SetupHyper has one or more of the following inputs: - The background sky is included via `hyper_image_sky`. - The background noise is included via the `hyper_background_noise`. - The source galaxy includes a `HyperGalaxy` for scaling the noise. """ result_3 = extensions.hyper_fit( setup_hyper=setup_hyper, result=result_3, analysis=analysis, include_hyper_image_sky=True, ) return af.ResultsCollection([result_1, result_2, result_3])
- The lens galaxy's total mass distribution is an `EllIsothermal` with `ExternalShear` [7 parameters]. - An `EllSersic` `LightProfile` for the source galaxy's light [7 parameters]. The number of free parameters and therefore the dimensionality of non-linear parameter space is N=12. NOTE: **PyAutoLens** assumes that the lens galaxy centre is near the coordinates (0.0", 0.0"). If for your dataset the lens is not centred at (0.0", 0.0"), we recommend that you either: - Reduce your data so that the centre is (`autolens_workspace/notebooks/preprocess`). - Manually override the lens model priors (`autolens_workspace/notebooks/imaging/modeling/customize/priors.py`). """ lens = af.Model(al.Galaxy, redshift=0.5, mass=al.mp.EllIsothermal, shear=al.mp.ExternalShear) source = af.Model(al.Galaxy, redshift=1.0, bulge=al.lp.EllSersic) model = af.Collection(galaxies=af.Collection(lens=lens, source=source)) """ __Search__ The lens model is fitted to the data using a non-linear search. In this example, we use the nested sampling algorithm Dynesty (https://dynesty.readthedocs.io/en/latest/). The folder `autolens_workspace/notebooks/imaging/modeling/customize/non_linear_searches` gives an overview of the non-linear searches **PyAutoLens** supports. If you are unclear of what a non-linear search is, checkout chapter 2 of the **HowToLens** lectures. The `name` and `path_prefix` below specify the path where results ae stored in the output folder:
def test__hyper_model_inversion_from__adds_hyper_galaxies(): model = af.Collection(galaxies=af.Collection( galaxy_0=af.Model(ag.Galaxy, redshift=0.5), galaxy_1=af.Model( ag.Galaxy, redshift=1.0, bulge=ag.lp.EllSersic, pixelization=ag.pix.Rectangular, regularization=ag.reg.Constant, ), )) instance = model.instance_from_prior_medians() path_galaxy_tuples = [ ( ("galaxies", "galaxy_0"), ag.Galaxy(redshift=0.5, hyper_galaxy=ag.HyperGalaxy(contribution_factor=1)), ), ( ("galaxies", "galaxy_1"), ag.Galaxy(redshift=1.0, hyper_galaxy=ag.HyperGalaxy(contribution_factor=2)), ), ] hyper_galaxy_image_path_dict = { ("galaxies", "galaxy_0"): ag.Array2D.ones(shape_native=(3, 3), pixel_scales=1.0), ("galaxies", "galaxy_1"): ag.Array2D.full(fill_value=2.0, shape_native=(3, 3), pixel_scales=1.0), } result = mock.MockResult( instance=instance, path_galaxy_tuples=path_galaxy_tuples, hyper_galaxy_image_path_dict=hyper_galaxy_image_path_dict, ) setup_hyper = ag.SetupHyper() setup_hyper.hyper_galaxy_names = ["galaxy_0"] model = ag.util.model.hyper_inversion_model_from(result=result, setup_hyper=setup_hyper) assert isinstance(model.galaxies.galaxy_0, af.Model) assert model.galaxies.galaxy_0.redshift == 0.5 assert model.galaxies.galaxy_0.hyper_galaxy.contribution_factor == 1 assert model.galaxies.galaxy_1.hyper_galaxy is None setup_hyper = ag.SetupHyper() setup_hyper.hyper_galaxy_names = ["galaxy_0", "galaxy_1"] model = ag.util.model.hyper_inversion_model_from(result=result, setup_hyper=setup_hyper) assert isinstance(model.galaxies.galaxy_0, af.Model) assert model.galaxies.galaxy_0.redshift == 0.5 assert model.galaxies.galaxy_0.hyper_galaxy.contribution_factor == 1 assert isinstance(model.galaxies.galaxy_1, af.Model) assert model.galaxies.galaxy_1.redshift == 1.0 assert model.galaxies.galaxy_1.hyper_galaxy.contribution_factor == 2
""" redshift_lens = 0.5 redshift_source = 1.0 """ __Model + Search + Analysis + Model-Fit (Search 1)__ In search 1 we fit a lens model where: - The lens galaxy's light is a parametric `EllSersic` bulge [7 parameters]. - The lens galaxy's mass and source galaxy are omitted. The number of free parameters and therefore the dimensionality of non-linear parameter space is N=11. """ model = af.Collection(galaxies=af.Collection( lens=af.Model(al.Galaxy, redshift=0.5, bulge=af.Model(al.lp.EllSersic)))) search = af.DynestyStatic( path_prefix=path_prefix, name="search[1]_light[parametric]", unique_tag=dataset_name, nlive=50, ) analysis = al.AnalysisImaging(dataset=imaging) result_1 = search.fit(model=model, analysis=analysis) """ __Model + Search + Analysis + Model-Fit (Search 2)__ We use the results of search 1 to create the lens model fitted in search 2, where:
) """ __Model (Search 1)__ We compose our lens model using `Model` objects, which represent the galaxies we fit to our data. In the first search our lens model is: - The lens galaxy's total mass distribution is an `EllIsothermal` with `ExternalShear` [7 parameters]. - The source-galaxy's light uses a `DelaunayBrightness` pixelization with fixed resolution 30 x 30 pixels (0 parameters). - This pixelization is regularized using a `Constant` scheme which smooths every source pixel equally [1 parameter]. The number of free parameters and therefore the dimensionality of non-linear parameter space is N=8. """ lens = af.Model(al.Galaxy, redshift=0.5, mass=al.mp.EllIsothermal) source = af.Model( al.Galaxy, redshift=1.0, pixelization=al.pix.DelaunayMagnification(shape=(30, 30)), regularization=al.reg.Constant, ) model = af.Collection(galaxies=af.Collection(lens=lens, source=source)) """ __Search + Analysis + Model-Fit (Search 1)__ We now create the non-linear search, analysis and perform the model-fit using this model. You may wish to inspect the results of the search 1 model-fit to ensure a fast non-linear search has been provided that provides a reasonably accurate lens model.
xvalues=xvalues, line=chi_squared_map, title="Chi-Squared Map", ylabel="Chi-Squareds", color="k", output_path=paths.image_path, output_filename="chi_squared_map", ) """ Lets now repeat the fit of the previous tutorial, but with visualization. """ import gaussian as g model = af.Model(g.Gaussian) emcee = af.Emcee(path_prefix=path.join("howtofit", "chapter_1"), name="tutorial_4_visualization") analysis = Analysis(data=data, noise_map=noise_map) result = emcee.fit(model=model, analysis=analysis) print( "Emcee has begun running - checkout the autofit_workspace/output/howtofit/tutorial_4_visualization" " folder for live output of the results." "This Jupyter notebook cell with progress once Emcee has completed - this could take a few minutes!" ) print("Emcee has finished run - you may now continue the notebook.")
pixel_scales=image.pixel_scales) positions_solver = al.PositionsSolver(grid=grid, pixel_scale_precision=0.025) """ __Model (Search 1)__ In search 1 we fit a lens model where: - The lens galaxy's total mass distribution is an `EllIsothermal` [5 parameters]. - The intermediate source galaxy is a point `Point` [2 parameters]. - The second source galaxy is included, so its redshift is used to perform multi-plane ray-tracing, but no model components are included [0 parameters]. The number of free parameters and therefore the dimensionality of non-linear parameter space is N=9. """ lens = af.Model(al.Galaxy, redshift=0.5, mass=al.mp.EllIsothermal) source_0 = af.Model(al.Galaxy, redshift=1.0, point_0=al.ps.Point) source_1 = af.Model(al.Galaxy, redshift=2.0) model = af.Collection( galaxies=af.Collection(lens=lens, source_0=source_0, source_1=source_1)) """ __Search + Analysis + Model-Fit (Search 1)__ We now create the non-linear search, analysis and perform the model-fit using this model. You may wish to inspect the results of the search 1 model-fit to ensure a fast non-linear search has been provided that provides a reasonably accurate lens model. """ search = af.DynestyStatic( path_prefix=path_prefix,
The SOURCE PARAMETRIC PIPELINE (with lens light) uses three searches to initialize a robust model for the source galaxy's light, which in this example: - Uses a parametric `EllSersic` bulge. - Uses an `EllIsothermal` model for the lens's total mass distribution with an `ExternalShear`. __Settings__: - Mass Centre: Fix the mass profile centre to (0.0, 0.0) (this assumption will be relaxed in the MASS LIGHT DARK PIPELINE). """ analysis = al.AnalysisImaging(dataset=imaging) bulge = af.Model(al.lp.EllSersic) bulge.centre = (0.0, 0.0) source_parametric_results = slam.source_parametric.with_lens_light( path_prefix=path_prefix, unique_tag=dataset_name, analysis=analysis, setup_hyper=setup_hyper, lens_bulge=bulge, lens_disk=None, mass=af.Model(al.mp.EllIsothermal), shear=af.Model(al.mp.ExternalShear), source_bulge=af.Model(al.lp.EllSersic), mass_centre=(0.0, 0.0), redshift_lens=redshift_lens, redshift_source=redshift_source,
pixel_scales=imaging.pixel_scales, radius=3.0) imaging = imaging.apply_mask(mask=mask) """ A plot of the `Imaging` object reveals how the noise-map and signal-to-noise map have been rescaled. """ imaging_plotter = aplt.ImagingPlotter(imaging=imaging) imaging_plotter.subplot_imaging() """ __Model + Search + Analysis__ The code below performs the normal steps to set up a model-fit. We omit comments of this code as you should be familiar with it and it is not specific to this example! """ bulge = af.Model(al.lp.EllSersic) disk = af.Model(al.lp.EllExponential) bulge.centre = disk.centre lens = af.Model( al.Galaxy, redshift=0.5, bulge=bulge, disk=disk, mass=al.mp.EllIsothermal, shear=al.mp.ExternalShear, ) source = af.Model(al.Galaxy, redshift=1.0, bulge=al.lp.EllSersic) model = af.Collection(galaxies=af.Collection(lens=lens, source=source))
def make_gaussian_1(): return af.Model(af.Gaussian)
def make_model(gaussian_1): return af.Collection( gaussian_1=gaussian_1, gaussian_2=af.Model(af.Gaussian), )
redshift_lens = 0.5 redshift_source = 1.0 """ __Model + Search + Analysis + Model-Fit (Search 1)__ In search 1 we fit a lens model where: - The lens galaxy's total mass distribution is an `EllIsothermal` with `ExternalShear` [7 parameters]. - The source galaxy's light is a parametric `EllSersic` [7 parameters]. The number of free parameters and therefore the dimensionality of non-linear parameter space is N=14. """ model = af.Collection(galaxies=af.Collection( lens=af.Model(al.Galaxy, redshift=0.5, mass=al.mp.EllIsothermal, shear=al.mp.ExternalShear), source=af.Model(al.Galaxy, redshift=1.0, bulge=al.lp.EllSersic), )) search = af.DynestyStatic( path_prefix=path_prefix, name="search[1]_mass[sie]_source[parametric]", unique_tag=dataset_name, nlive=50, ) analysis = al.AnalysisInterferometer(dataset=interferometer) result_1 = search.fit(model=model, analysis=analysis) """
Every point-source dataset in the `PointSourceDict` has a name. Its `name` pairs the dataset to the `PointSource` in the model below. Specifically, because the name of the dataset is `point_0`, there must be a corresponding `PointSource` model component in the model below with the name `point_0` for the model-fit to be possible. In this example, where there is just one source, named pairing appears unecessary. However, point-source datasets may have many source galaxies in them, and name pairing ensures every point source in the model is compared against its point source dataset. **PyAutoLens** assumes that the lens galaxy centre is near the coordinates (0.0", 0.0"). If for your dataset the lens is not centred at (0.0", 0.0"), we recommend that you either: - Reduce your data so that the centre is (`autolens_workspace/notebooks/preprocess`). - Manually override the lens model priors (`autolens_workspace/notebooks/imaging/modeling/customize/priors.py`). """ lens = af.Model(al.Galaxy, redshift=0.5, mass=al.mp.EllIsothermal) source = af.Model(al.Galaxy, redshift=1.0, point_0=al.ps.PointSource) model = af.Collection(galaxies=af.Collection(lens=lens, source=source)) """ __PositionsSolver__ For point-source modeling we also need to define our `PositionsSolver`. This object determines the multiple-images of a mass model for a point source at location (y,x) in the source plane, by iteratively ray-tracing light rays to the source-plane. Checkout the script ? for a complete description of this object, we will use the default `PositionSolver` in this example with a `point_scale_precision` half the value of the position noise-map, which should be sufficiently good enough precision to fit the lens model accurately. """ grid = al.Grid2D.uniform(shape_native=image.shape_native,
chi-squared, likelihood, etc of every individual fit to part of our point source dataset. """ fit = al.FitPointDict(point_dict=point_dict, tracer=tracer, point_solver=solver) print(fit["point_0"].positions.residual_map) print(fit["point_0"].positions.chi_squared_map) print(fit["point_0"].positions.log_likelihood) """ __Model__ We first compose the model, in the same way described in the `modeling.py` overview script: """ lens_galaxy_model = af.Model(al.Galaxy, redshift=0.5, bulge=al.lp.EllSersic, mass=al.mp.EllIsothermal) source_galaxy_model = af.Model(al.Galaxy, redshift=1.0, point_0=al.ps.Point) galaxies = af.Collection(lens=lens_galaxy_model, source=source_galaxy_model) model = af.Collection(galaxies=galaxies) """ __Non-linear Search__ We again choose the non-linear search `dynesty` (https://github.com/joshspeagle/dynesty). """ search = af.DynestyStatic(name="overview_point_source") """ __Analysis__
The x coordinates in the original reference frame of the data. """ transformed_xvalues = np.subtract(xvalues, self.centre) return np.multiply( np.divide(self.normalization, self.sigma * np.sqrt(2.0 * np.pi)), np.exp(-0.5 * np.square(np.divide(transformed_xvalues, self.sigma))), ) """ We've again extended the `Gaussian` class to have a method `profile_1d_via_xvalues_from`. Given an input set of x coordinates this computes the normalization of the `Gaussian` at every point, which we again plot a realization of our Gaussian. Note how we are now referring to this as our `model_data`. """ model = af.Model(Gaussian) gaussian = model.instance_from_vector(vector=[60.0, 20.0, 15.0]) model_data = gaussian.profile_1d_via_xvalues_from(xvalues=xvalues) plt.plot(xvalues, model_data, color="r") plt.title("1D Gaussian model.") plt.xlabel("x values of profile") plt.ylabel("Profile Normalization") plt.show() plt.clf() """ It is often more informative to plot the `data` and `model_data` on the same plot for comparison. """ plt.errorbar(x=xvalues,
def test__hyper_model_noise_from(): model = af.Collection(galaxies=af.Collection( galaxy=af.Model( ag.Galaxy, redshift=0.5, pixelization=ag.pix.Rectangular, regularization=ag.reg.Constant, ), galaxy_1=af.Model(ag.Galaxy, redshift=1.0, bulge=ag.lp.EllSersic), )) instance = model.instance_from_prior_medians() result = mock.MockResult(instance=instance) model = ag.util.model.hyper_noise_model_from(setup_hyper=ag.SetupHyper(), result=result) assert model is None model = ag.util.model.hyper_noise_model_from(result=result, setup_hyper=None) assert model == None model = ag.util.model.hyper_noise_model_from( setup_hyper=ag.SetupHyper( hyper_image_sky=ag.hyper_data.HyperImageSky, hyper_background_noise=ag.hyper_data.HyperBackgroundNoise, ), result=result, include_hyper_image_sky=True, ) assert model.galaxies.galaxy.pixelization.cls is ag.pix.Rectangular assert model.galaxies.galaxy.regularization.cls is ag.reg.Constant assert model.galaxies.galaxy.pixelization.prior_count == 0 assert model.galaxies.galaxy.regularization.prior_count == 0 assert model.galaxies.galaxy_1.bulge.intensity == pytest.approx( 1.0, 1.0e-4) assert isinstance(model.hyper_image_sky, af.Model) assert isinstance(model.hyper_background_noise, af.Model) assert model.hyper_image_sky.cls == ag.hyper_data.HyperImageSky assert model.hyper_background_noise.cls == ag.hyper_data.HyperBackgroundNoise model = af.Collection(galaxies=af.Collection( galaxy=af.Model(ag.Galaxy, redshift=0.5), galaxy_1=af.Model(ag.Galaxy, redshift=1.0, bulge=ag.lp.EllSersic), )) instance = model.instance_from_prior_medians() result = mock.MockResult(instance=instance) model = ag.util.model.hyper_noise_model_from(result=result, setup_hyper=ag.SetupHyper()) assert model == None
ecolor="k", elinewidth=1, capsize=2) plt.show() plt.close() """ __Model__ Next, we create our model, which in this case corresponds to a `Gaussian` + `Exponential`. In model.py, you will have noted the `Gaussian` has 3 parameters (centre, normalization and sigma) and Exponential 3 parameters (centre, normalization and rate). These are the free parameters of our model that the `NonLinearSearch` fits for, meaning the non-linear parameter space has dimensionality = 6. In the complex example tutorial, we used a `Model` to create and customize the `Gaussian` and `Exponential` models. """ gaussian = af.Model(m.Gaussian) exponential = af.Model(m.Exponential) """ Checkout `autofit_workspace/config/priors/model.json`, this config file defines the default priors of the `Gaussian` and `Exponential` model components. We can manually customize the priors of our model used by the non-linear search. """ gaussian.centre = af.UniformPrior(lower_limit=0.0, upper_limit=100.0) gaussian.normalization = af.UniformPrior(lower_limit=0.0, upper_limit=1e2) gaussian.sigma = af.UniformPrior(lower_limit=0.0, upper_limit=30.0) exponential.centre = af.UniformPrior(lower_limit=0.0, upper_limit=100.0) exponential.normalization = af.UniformPrior(lower_limit=0.0, upper_limit=1e2) exponential.rate = af.UniformPrior(lower_limit=0.0, upper_limit=10.0) """ We can now compose the overall model using a `Collection`, which takes the model components we defined above.
y=data, yerr=noise_map, color="k", ecolor="k", elinewidth=1, capsize=2, ) plt.show() plt.close() """ __Model + Analysis__ We create the model and analysis, which in this example is a single `Gaussian` and therefore has dimensionality N=3. """ model = af.Model(m.Gaussian) model.centre = af.UniformPrior(lower_limit=0.0, upper_limit=100.0) model.normalization = af.UniformPrior(lower_limit=1e-2, upper_limit=1e2) model.sigma = af.UniformPrior(lower_limit=0.0, upper_limit=30.0) analysis = a.Analysis(data=data, noise_map=noise_map) """ __Search__ We now create and run the `LBFGS` object which acts as our non-linear search. We manually specify all of the LBFGS settings, descriptions of which are provided at the following webpage: https://docs.scipy.org/doc/scipy/reference/optimize.minimize-lbfgsb.html
def make_model(): return af.Collection(galaxies=af.Collection( lens=af.Model(al.Galaxy, redshift=0.5, light=al.lp.EllSersic), source=af.Model(al.Galaxy, redshift=1.0, light=al.lp.EllSersic), ))
""" __Pickle Files__ We can pass strings specifying the path and filename of .pickle files stored on our hard-drive to the `search.fit()` method, which will make them accessible to the aggregator to aid interpretation of results. Our simulated strong lens datasets have a `true_tracer.pickle` file which we pass in below, which we use in the `Aggregator` tutorials to check if the model-fit recovers its true input parameters. """ pickle_files = [path.join(dataset_path, "true_tracer.pickle")] """ Model: We set up the model as per usual """ model = af.Collection(galaxies=af.Collection( lens=af.Model(al.Galaxy, redshift=0.5, mass=al.mp.EllIsothermal), source=af.Model(al.Galaxy, redshift=1.0, bulge=al.lp.EllSersic), )) """ In all examples so far, results were written to the `autofit_workspace/output` folder with a path and folder named after a unique identifier, which was derived from the non-linear search and model. This unique identifier plays a vital role in the database: it is used to ensure every entry in the database is unique. In this example, results are written directly to the `database.sqlite` file after the model-fit is complete and only stored in the output folder during the model-fit. This can be important for performing large model-fitting tasks on high performance computing facilities where there may be limits on the number of files allowed, or there are too many results to make navigating the output folder manually feasible. The `unique_tag` below uses the `dataset_name` to alter the unique identifier, which as we have seen is also generated depending on the search settings and model. In this example, all three model fits use an identical search and model, so this `unique_tag` is key for ensuring 3 separate sets of results for each model-fit are
def test_config_error(): model = af.Model(SomeWeirdClass) with pytest.raises(ConfigException): print(Identifier([model]))
def no_lens_light( path_prefix: str, analysis: Union[al.AnalysisImaging, al.AnalysisInterferometer], setup_hyper: al.SetupHyper, mass: af.Model(al.mp.MassProfile) = af.Model(al.mp.EllIsothermal), shear: af.Model(al.mp.ExternalShear) = af.Model(al.mp.ExternalShear), source_bulge: af.Model(al.lp.LightProfile) = af.Model(al.lp.EllSersic), source_disk: af.Model(al.lp.LightProfile) = None, source_envelope: af.Model(al.lp.LightProfile) = None, redshift_lens: float = 0.5, redshift_source: float = 1.0, mass_centre: Optional[Tuple[float, float]] = None, unique_tag: Optional[str] = None, session: Optional[bool] = None, ) -> af.ResultsCollection: """ The SlaM SOURCE PARAMETRIC PIPELINE for fitting imaging data without a lens light component. Parameters ---------- path_prefix The prefix of folders between the output path and the search folders. analysis The analysis class which includes the `log_likelihood_function` and can be customized for the SLaM model-fit. setup_hyper The setup of the hyper analysis if used (e.g. hyper-galaxy noise scaling). mass The `MassProfile` fitted by this pipeline. shear The model used to represent the external shear in the mass model (set to None to turn off shear). source_bulge The `LightProfile` `Model` used to represent the light distribution of the source galaxy's bulge (set to None to omit a bulge). source_disk The `LightProfile` `Model` used to represent the light distribution of the source galaxy's disk (set to None to omit a disk). source_envelope The `LightProfile` `Model` used to represent the light distribution of the source galaxy's envelope (set to None to omit an envelope). redshift_lens The redshift of the lens galaxy fitted, used by the pipeline for converting arc-seconds to kpc, masses to solMass, etc. redshift_source The redshift of the source galaxy fitted, used by the pipeline for converting arc-seconds to kpc, masses to solMass, etc. mass_centre If input, a fixed (y,x) centre of the mass profile is used which is not treated as a free parameter by the non-linear search. unique_tag The unique tag for this model-fit, which will be given a unique entry in the sqlite database and also acts as the folder after the path prefix and before the search name. This is typically the name of the dataset. """ """ __Model + Search + Analysis + Model-Fit (Search 1)__ In search 1 of the SOURCE PARAMETRIC PIPELINE we fit a lens model where: - The lens galaxy mass is modeled using a total mass distribution [no prior initialization]. - The source galaxy's light is a parametric bulge + disk + envelope [no prior initialization]. This search aims to accurately estimate the lens mass model and source model. """ if mass_centre is not None: mass.centre = mass_centre model = af.Collection(galaxies=af.Collection( lens=af.Model( al.Galaxy, redshift=redshift_lens, mass=mass, shear=shear), source=af.Model( al.Galaxy, redshift=redshift_source, bulge=source_bulge, disk=source_disk, envelope=source_envelope, ), )) search = af.DynestyStatic( path_prefix=path_prefix, name="source_parametric[1]_mass[total]_source[parametric]", unique_tag=unique_tag, session=session, nlive=200, walks=10, ) result_1 = search.fit(model=model, analysis=analysis) """ __Hyper Extension__ The above search is extended with a hyper-search if the SetupHyper has one or more of the following inputs: - The background sky is included via `hyper_image_sky`. - The background noise is included via the `hyper_background_noise`. - The source galaxy includes a `HyperGalaxy` for scaling the noise. """ result_1 = extensions.hyper_fit( setup_hyper=setup_hyper, result=result_1, analysis=analysis, include_hyper_image_sky=True, ) return af.ResultsCollection([result_1])
We now compose the graphical model that we fit, using the `Model` and `Collection` objects you are now familiar with. """ from autofit import graphical as g import profiles as p """ We begin by setting up a shared prior for `centre`, like the previous tutorial. """ centre_shared_prior = af.GaussianPrior(mean=50.0, sigma=30.0) model_list = [] for model_index in range(len(data_list)): gaussian = af.Model(p.Gaussian) gaussian.centre = centre_shared_prior # This prior is used by all 3 Gaussians! # gaussian.normalization = af.UniformPrior(lower_limit=0.0, upper_limit=1e2) # gaussian.sigma = af.UniformPrior(lower_limit=0.0, upper_limit=25.0) gaussian.normalization = af.GaussianPrior(mean=3.0, sigma=5.0, lower_limit=0.0) gaussian.sigma = af.GaussianPrior(mean=10.0, sigma=10.0, lower_limit=0.0) model_list.append(gaussian) """ __Analysis Factors__ Now we have our `Analysis` classes and graphical model, we can compose our `AnalysisFactor`'s.
light, which in this example: - Uses a parametric `EllSersic` bulge for the source's light (omitting a disk / envelope). - Uses an `EllIsothermal` model for the lens's total mass distribution with an `ExternalShear`. __Settings__: - Mass Centre: Fix the mass profile centre to (0.0, 0.0) (this assumption will be relaxed in the MASS TOTAL PIPELINE). """ analysis = al.AnalysisImaging(dataset=imaging) source_parametric_results = slam.source_parametric.no_lens_light( settings_autofit=settings_autofit, analysis=analysis, setup_hyper=setup_hyper, mass=af.Model(al.mp.EllIsothermal), shear=af.Model(al.mp.ExternalShear), source_bulge=af.Model(al.lp.EllSersic), mass_centre=(0.0, 0.0), redshift_lens=0.5, redshift_source=1.0, ) """ __MASS TOTAL PIPELINE (no lens light)__ The MASS TOTAL PIPELINE (no lens light) uses one search to fits a complex lens mass model to a high level of accuracy, using the lens mass model and source model of the SOURCE PIPELINE to initialize the model priors. In this example it: - Uses an `EllPowerLaw` model for the lens's total mass distribution [The centre if unfixed from (0.0, 0.0)]. - Uses the `EllSersic` model representing a bulge for the source's light. - Carries the lens redshift, source redshift and `ExternalShear` of the SOURCE PIPELINE through to the MASS TOTAL PIPELINE.
def make_model(): return af.Model(af.Gaussian)
self, centre=30.0, # <- **PyAutoFit** recognises these constructor arguments normalization=1.0, # <- are the Gaussian`s model parameters. sigma=5.0, ): self.centre = centre self.normalization = normalization self.sigma = sigma """ __Model__ To instantiate a Python class as a model component using the `af.Model` object: """ model = af.Model(Gaussian) """ To overwrite the priors of one or more parameters from the default value assumed via configuration files: """ model = af.Model(Gaussian) model.centre = af.UniformPrior(lower_limit=0.0, upper_limit=1.0) model.normalization = af.LogUniformPrior(lower_limit=1e-4, upper_limit=1e4) model.sigma = af.GaussianPrior(mean=0.0, sigma=1.0, lower_limit=0.0, upper_limit=1e5) """ To fix a free parameter to a specific value (reducing the dimensionality of parameter space by 1): """ model = af.Model(Gaussian) model.centre = 0.0
radius=2.6) imaging = imaging.apply_mask(mask=mask) analysis = al.AnalysisImaging(dataset=imaging) imaging_plotter = aplt.ImagingPlotter(imaging=imaging, visuals_2d=aplt.Visuals2D(mask=mask)) imaging_plotter.subplot_imaging() """ __Model__ We are going to use the same result of search 1 from the previous tutorial. Thus, we set up an identical model such that we instantly load the result from hard-disk. """ bulge = af.Model(al.lp.EllSersic) mass = af.Model(al.mp.EllIsothermal) bulge.centre_0 = 0.0 bulge.centre_1 = 0.0 mass.centre_0 = 0.0 mass.centre_1 = 0.0 mass.elliptical_comps = bulge.elliptical_comps bulge.sersic_index = 4.0 lens = af.Model(al.Galaxy, redshift=0.5, bulge=bulge, mass=mass,