def test_subplot_fit_imaging_is_output(masked_imaging_fit_x2_plane_7x7, include_2d_all, plot_path, plot_patch): fit_imaging_plotter = aplt.FitImagingPlotter( fit=masked_imaging_fit_x2_plane_7x7, include_2d=include_2d_all, mat_plot_2d=aplt.MatPlot2D( output=aplt.Output(plot_path, format="png")), ) fit_imaging_plotter.subplot_fit_imaging() assert path.join(plot_path, "subplot_fit_imaging.png") in plot_patch.paths
def test__fit_quantities_are_output(masked_imaging_fit_x2_plane_7x7, include_2d_all, plot_path, plot_patch): fit_imaging_plotter = aplt.FitImagingPlotter( fit=masked_imaging_fit_x2_plane_7x7, include_2d=include_2d_all, mat_plot_2d=aplt.MatPlot2D( output=aplt.Output(path=plot_path, format="png")), ) fit_imaging_plotter.figures( image=True, noise_map=True, signal_to_noise_map=True, model_image=True, residual_map=True, normalized_residual_map=True, chi_squared_map=True, ) assert path.join(plot_path, "image.png") in plot_patch.paths assert path.join(plot_path, "noise_map.png") in plot_patch.paths assert path.join(plot_path, "signal_to_noise_map.png") in plot_patch.paths assert path.join(plot_path, "model_image.png") in plot_patch.paths assert path.join(plot_path, "residual_map.png") in plot_patch.paths assert path.join(plot_path, "normalized_residual_map.png") in plot_patch.paths assert path.join(plot_path, "chi_squared_map.png") in plot_patch.paths plot_patch.paths = [] fit_imaging_plotter.figures( image=True, noise_map=False, signal_to_noise_map=False, model_image=True, chi_squared_map=True, ) assert path.join(plot_path, "image.png") in plot_patch.paths assert path.join(plot_path, "noise_map.png") not in plot_patch.paths assert path.join(plot_path, "signal_to_noise_map.png") not in plot_patch.paths assert path.join(plot_path, "model_image.png") in plot_patch.paths assert path.join(plot_path, "residual_map.png") not in plot_patch.paths assert path.join(plot_path, "normalized_residual_map.png") not in plot_patch.paths assert path.join(plot_path, "chi_squared_map.png") in plot_patch.paths
def test__figures_of_plane(masked_imaging_fit_x2_plane_7x7, include_2d_all, plot_path, plot_patch): fit_imaging_plotter = aplt.FitImagingPlotter( fit=masked_imaging_fit_x2_plane_7x7, include_2d=include_2d_all, mat_plot_2d=aplt.MatPlot2D( output=aplt.Output(path=plot_path, format="png")), ) fit_imaging_plotter.figures_of_planes(subtracted_image=True, model_image=True, plane_image=True) assert path.join(plot_path, "subtracted_image_of_plane_0.png") in plot_patch.paths assert path.join(plot_path, "subtracted_image_of_plane_1.png") in plot_patch.paths assert path.join(plot_path, "model_image_of_plane_0.png") in plot_patch.paths assert path.join(plot_path, "model_image_of_plane_1.png") in plot_patch.paths assert path.join(plot_path, "plane_image_of_plane_0.png") in plot_patch.paths assert path.join(plot_path, "plane_image_of_plane_1.png") in plot_patch.paths plot_patch.paths = [] fit_imaging_plotter.figures_of_planes(subtracted_image=True, model_image=True, plane_image=True, plane_index=0) assert path.join(plot_path, "subtracted_image_of_plane_0.png") in plot_patch.paths assert (path.join(plot_path, "subtracted_image_of_plane_1.png") not in plot_patch.paths) assert path.join(plot_path, "model_image_of_plane_0.png") in plot_patch.paths assert path.join(plot_path, "model_image_of_plane_1.png") not in plot_patch.paths assert path.join(plot_path, "plane_image_of_plane_0.png") in plot_patch.paths assert path.join(plot_path, "plane_image_of_plane_1.png") not in plot_patch.paths
def test__subplot_of_planes(masked_imaging_fit_x2_plane_7x7, include_2d_all, plot_path, plot_patch): fit_imaging_plotter = aplt.FitImagingPlotter( fit=masked_imaging_fit_x2_plane_7x7, include_2d=include_2d_all, mat_plot_2d=aplt.MatPlot2D( output=aplt.Output(plot_path, format="png")), ) fit_imaging_plotter.subplot_of_planes() assert path.join(plot_path, "subplot_of_plane_0.png") in plot_patch.paths assert path.join(plot_path, "subplot_of_plane_1.png") in plot_patch.paths plot_patch.paths = [] fit_imaging_plotter.subplot_of_planes(plane_index=0) assert path.join(plot_path, "subplot_of_plane_0.png") in plot_patch.paths assert path.join(plot_path, "subplot_of_plane_1.png") not in plot_patch.paths
__Fit__ Now that our source-galaxy has a `Pixelization` and `Regularization`, we are able to fit the data using these in the same way as before, by simply passing the source galaxy to a `Tracer` and using this `Tracer` to create a `FitImaging` object. """ tracer = al.Tracer.from_galaxies(galaxies=[lens_galaxy, source_galaxy]) fit = al.FitImaging(imaging=imaging, tracer=tracer) """ __Inversion__ The fit has been performed using an `Inversion` for the source galaxy. We can see this by plotting the source-plane of the `FitImaging` using the `subplot_of_plane` mat_plot_2d. Note how the bottom-right panel shows a pixelized grid. """ fit_imaging_plotter = aplt.FitImagingPlotter(fit=fit) fit_imaging_plotter.subplot_of_planes(plane_index=1) """ __Alternative Pixelizations__ **PyAutoLens** supports many different pixel-grids. Below, we use a `VoronoiMagnification` pixelization, which defines the source-pixel centres in the image-plane and ray traces them to the source-plane. The source pixel-grid is therefore adapted to the mass-model magnification pattern, placing more source-pixel in the highly magnified regions of the source-plane. """ source_galaxy = al.Galaxy( redshift=1.0, pixelization=al.pix.VoronoiMagnification(shape=(40, 40)), regularization=al.reg.Constant(coefficient=1.0), )
for imaging in imaging_gen: print(imaging) imaging_plotter = aplt.ImagingPlotter(imaging=imaging) imaging_plotter.subplot_imaging() """ We now use the database to load a generator containing the fit of the maximum log likelihood lens model (and therefore tracer) to each dataset. """ fit_agg = al.agg.FitImagingAgg(aggregator=agg) fit_imaging_gen = fit_agg.max_log_likelihood_gen() for fit in fit_imaging_gen: fit_imaging_plotter = aplt.FitImagingPlotter(fit=fit) fit_imaging_plotter.subplot_fit_imaging() """ __Modification__ The `FitImagingAgg` allow us to modify the fit settings. By default, it uses the `SettingsImaging`, `SettingsPixelization` and `SettingsInversion` that were used during the model-fit. However, we can change these settings such that the fit is performed differently. For example, what if I wanted to see how the fit looks where the `Grid2D`'s `sub_size` is 4 (instead of the value of 2 that was used)? Or where the pixelization didn`t use a border? You can do this by passing the settings objects, which overwrite the ones used by the analysis. """ fit_agg = al.agg.FitImagingAgg( aggregator=agg,
regularization=al.reg.Constant(coefficient=1.0), ) tracer = al.Tracer.from_galaxies(galaxies=[lens_galaxy, source_galaxy]) # %% """ Then, like before, we pass the `MaskedImaging` and `Tracer` to a `FitImaging` object. Indeed, we see some pretty good looking residuals - we're certainly fitting the lensed source accurately! """ # %% fit = al.FitImaging(masked_imaging=masked_imaging, tracer=tracer) include_2d = aplt.Include2D(mask=True) fit_imaging_plotter = aplt.FitImagingPlotter(fit=fit, include_2d=include_2d) fit_imaging_plotter.subplot_fit_imaging() # %% """ And, we're done, here are a few questions to get you thinking about `Inversion``.: 1) The `Inversion` provides the maximum log likelihood solution to the observed image. Is there a problem with seeking the `best-fit`? Is there a risk that we're going to fit other things in the image than just the lensed source galaxy? What happens if you reduce the `regularization_coefficient` above to zero? 2) The exterior pixels in the `Rectangular` `Grid`.have no image-pixels in them. However, they are still given a reconstructed flux. If this value isn't` coming from a util to an image-pixel, where is it be coming from? """
sersic_index=1.5, ), light_3=al.lp.EllSersic( centre=(-0.3, -0.3), elliptical_comps=al.convert.elliptical_comps_from(axis_ratio=0.9, angle=85.0), intensity=0.4, effective_radius=0.1, sersic_index=2.0, ), ) tracer = al.Tracer.from_galaxies(galaxies=[lens_galaxy, source_galaxy]) true_fit = al.FitImaging(dataset=imaging, tracer=tracer) fit_imaging_plotter = aplt.FitImagingPlotter(fit=true_fit) fit_imaging_plotter.subplot_fit_imaging() fit_imaging_plotter.subplot_of_planes(plane_index=1) """ And indeed, we see an improved residual-map, chi-squared-map, and so forth. If the source morphology is complex, there is no way we chain searches to fit it perfectly. The non-linear parameter space simply becomes too complex. For this tutorial, this was true even though our source model could actually fit the data perfectly. For real lenses, the source may be *even more complex* giving us even less hope of getting a good fit. But fear not, **PyAutoLens** has you covered. In chapter 4, we'll introduce a completely new way to model the source galaxy, which addresses the problem faced here. """
search=af.DynestyStatic(path_prefix="howtolens", name="phase_t2_custom_priors", n_live_points=40), settings=settings, galaxies=af.CollectionPriorModel(lens=lens, source=source), ) print( "Dynesty has begun running - checkout the autolens_workspace/output/2_custom_priors" " folder for live output of the results, images and lens model." " This Jupyter notebook cell with progress once Dynesty has completed - this could take some time!" ) result = phase.run(dataset=imaging, mask=mask) fit_imaging_plotter = aplt.FitImagingPlotter(fit=result.max_log_likelihood_fit) fit_imaging_plotter.subplot_fit_imaging() print("Dynesty has finished run - you may now continue the notebook.") # %% """ And, we're done. This tutorial had some pretty difficult concepts to wrap your head around. However, I can`t emphasize enough how important it is that you develop an intuition for non-linear searches and the notion of a non-linear parameter space. Becoming good at lens modeling is all being able to navigate a complex, degenerate and highly non-linear parameter space! Luckily, we're going to keep thinking about this in the next set of tutorials, so if you're not feeling too confident yet, you will be soon! Before continuing to the next tutorial, I want you think about whether anything could go wrong when we search a non-linear parameter space. Is it possible that we won't find the highest log likelihood lens model? Why might this be?
) analysis = al.AnalysisImaging(dataset=imaging) print( "Dynesty has begun running - checkout the workspace/output" " folder for live output of the results, images and lens model." " This Jupyter notebook cell with progress once Dynesty has completed - this could take some time!" ) result_slow = search.fit(model=model, analysis=analysis) """ Lets check that we get a good model and fit to the data. """ fit_imaging_plotter = aplt.FitImagingPlotter(fit=result_slow.max_log_likelihood_fit) fit_imaging_plotter.subplot_fit_imaging() """ We can use the result to tell us how many iterations Dynesty took to convergence on the solution. """ print("Total Dynesty Iterations (If you skip running the search, this is ~ 500000):") print(result_slow.samples.total_samples) """ Now lets run the search with fast settings, so we can compare the total number of iterations required. """ search = af.DynestyStatic( path_prefix=path.join("howtolens", "chapter_2"), name="tutorial_searches_fast", unique_tag=dataset_name,
"Dynesty has begun running - checkout the workspace/output/5_linking_phases" " folder for live output of the results, images and lens model." " This Jupyter notebook cell with progress once Dynesty has completed - this could take some time!" ) phase1_result = phase1.run(dataset=imaging, mask=mask) print("Dynesty has finished run - you may now continue the notebook.") # %% """ And indeed, we get a reasonably good model and fit to the data - in a much shorter space of time! """ # %% fit_imaging_plotter = aplt.FitImagingPlotter( fit=phase1_result.max_log_likelihood_fit) fit_imaging_plotter.subplot_fit_imaging() # %% """ Now all we need to do is look at the results of phase 1 and tune our priors in phase 2 to those result. Lets setup a custom phase that does exactly that. GaussianPriors are a nice way to do this. They tell the `NonLinearSearch` where to look, but leave open the possibility that there might be a better solution nearby. In contrast, UniformPriors put hard limits on what values a parameter can or can`t take. It makes it more likely we'll accidently cut-out the global maxima solution. """ # %% lens = al.GalaxyModel(redshift=0.5, bulge=al.lp.EllipticalSersic,
return al.FitImaging(imaging=imaging, tracer=tracer) """ __Fit Problems__ Lets fit our first source which was simulated using the flattest light profile. One should note that this uses the highest regularization coefficient of our 3 fits (as determined by maximizing the Bayesian log evidence). """ fit_flat = fit_imaging_with_voronoi_magnification_pixelization( imaging=imaging_source_flat, mask=mask, coefficient=9.2 ) include_2d = aplt.Include2D(mapper_data_pixelization_grid=True, mask=True) fit_imaging_plotter = aplt.FitImagingPlotter(fit=fit_flat, include_2d=include_2d) fit_imaging_plotter.subplot_fit_imaging() fit_imaging_plotter.subplot_of_planes(plane_index=1) print(fit_flat.log_evidence) """ The fit was *excellent*. There were effectively no residuals in the fit, and the source has been reconstructed using lots of pixels! Nice! Now, lets fit the next source, which is more compact. """ fit_compact = fit_imaging_with_voronoi_magnification_pixelization( imaging=imaging_source_compact, mask=mask, coefficient=3.3 )
""" __Pixelization__ Okay, so lets look at our fit from the previous tutorial in more detail. we'll use a higher resolution 40 x 40 grid. """ source_galaxy = al.Galaxy( redshift=1.0, pixelization=al.pix.Rectangular(shape=(40, 40)), regularization=al.reg.Constant(coefficient=1.0), ) fit = perform_fit_with_source_galaxy(imaging=imaging, source_galaxy=source_galaxy) fit_imaging_plotter = aplt.FitImagingPlotter(fit=fit) fit_imaging_plotter.subplot_fit_imaging() """ __Regularization__ The source reconstruction looks excellent! However, the high quality of this solution was possible because I chose a `coefficient` for the regularization input of 1.0. If we reduce this `coefficient` to zero, the source reconstruction goes *very* weird. """ source_galaxy = al.Galaxy( redshift=1.0, pixelization=al.pix.Rectangular(shape=(40, 40)), regularization=al.reg.Constant(coefficient=0.0), )
print( "Dynesty has begun running - checkout the workspace/output/howtolens/chapter_2/tutorial_4_custom_priors" " folder for live output of the results, images and lens model." " This Jupyter notebook cell with progress once Dynesty has completed - this could take some time!" ) result_custom_priors = search.fit(model=model, analysis=analysis) print("Dynesty has finished run - you may now continue the notebook.") """ __Result__ Bam! We get a good model, which corresponds to the global maxima. By giving our non-linear search a helping hand and informing it of where to sample parameter space, we can increase the odds that we find the global maxima solution. """ fit_imaging_plotter = aplt.FitImagingPlotter( fit=result_custom_priors.max_log_likelihood_fit) fit_imaging_plotter.subplot_fit_imaging() """ __Discussion__ By tuning our priors to the lens we fit we increase the chance of inferring the global maxima lens model. The search may also fit the lens model a lot faster, given it spends less time searches regions of parameter space that do not correspond to good solutions. Before moving onto the next approach, lets think about the advantages and disadvantages of prior tuning: Advantages: - We have a higher chance of finding the globally maximum log likelihood solutions in parameter space. - The search took less time to run because the non-linear search explored less of parameter space.