# Lets look at the tracer's image-plane image - this is the image we'll be simulating. ray_tracing_plotters.plot_ray_tracing_subplot(tracer=tracer) # Now lets simulate the CCD data, remembering that we use a special image-plane image which ensures edge-effects don't # degrade our modeling of the telescope optics (e.g. the PSF convolution). simulated_ccd = ccd.CCDData.simulate( array=tracer.image_plane_image_for_simulation, pixel_scale=pixel_scale, exposure_time=300.0, psf=psf, background_sky_level=0.1, add_noise=True) # Lets plot the simulated CCD data before we output it to files. ccd_plotters.plot_ccd_subplot(ccd_data=simulated_ccd) # Now, lets output this simulated ccd-data to the data folder (we'll model it in the workspace's example multi-plane # pipeline). path = '{}/../'.format(os.path.dirname(os.path.realpath(__file__))) # Check a folder of the lens_name exists in the data folder for the images to be output. If it doesn't make it. if not os.path.exists(path + '/data/example/' + lens_name): os.makedirs(path + '/data/example/' + lens_name) image = ccd.output_ccd_data_to_fits( ccd_data=simulated_ccd, image_path=path + '/data/example/' + lens_name + '/image.fits', psf_path=path + '/data/example/' + lens_name + '/psf.fits', noise_map_path=path + '/data/example/' + lens_name + '/noise_map.fits', overwrite=True)
image_plane_grid_stack=image_plane_grid_stack) ccd_simulated = ccd.CCDData.simulate( array=tracer.image_plane_image_for_simulation, pixel_scale=0.1, exposure_time=300.0, psf=psf, background_sky_level=0.1, add_noise=True) return ccd_simulated # Simulate the image and set it up. ccd_data = simulate() ccd_plotters.plot_ccd_subplot(ccd_data=ccd_data) # Lets first run the phase without black magic, which is performed using the standard lines of code we're used to. # A word of warning, this phase takes >1 hour to run... so if you get bored, skip the run cell below continue to the # phase with black magic (afterall, the whole point of this tutorial is how slow MultiNest can run, so theres no harm # if the slow run speed bores you to tears :P). phase_normal = ph.LensSourcePlanePhase( 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='7_no_black_magic') # We're going to use the time module to time how long each MultiNest run takes. However, if you resume the MultiNest
source_galaxies=[source_galaxy], image_plane_grid_stack=image_plane_grid_stack) image_simulated = ccd.CCDData.simulate( array=tracer.image_plane_image_for_simulation, pixel_scale=0.1, exposure_time=300.0, psf=psf, background_sky_level=0.1, add_noise=True) return image_simulated ccd_data = simulate() ccd_plotters.plot_ccd_subplot(ccd_data=ccd_data) # When it comes to determining an appropriate mask for this image, the best approach is to set up a mask using the mask # module and pass it to a ccd plotter. You can then check visually if the mask is an appropriate size or not. # Below, we choose an inner radius that cuts into our lensed source galaxy - clearly this isn't a good mask. mask = msk.Mask.circular_annular(shape=ccd_data.shape, pixel_scale=ccd_data.pixel_scale, inner_radius_arcsec=1.4, outer_radius_arcsec=2.4) ccd_plotters.plot_ccd_subplot(ccd_data=ccd_data, mask=mask, extract_array_from_mask=True, zoom_around_mask=True) # So, lets decrease the inner radius to correct for this mask = msk.Mask.circular_annular(shape=ccd_data.shape,
# spans its dynamic range. array_plotters.plot_array(array=image, title='SLACS1430+4105 Image', norm='linear', norm_min=0.0, norm_max=0.3) # We can also load the full set of ccd data (image, noise-map, PSF) and use the ccd_plotters to make the figures above. from autolens.data import ccd from autolens.data.plotters import ccd_plotters psf_path = path + '/data/example/' + lens_name + '/psf.fits' noise_map_path = path + '/data/example/' + lens_name + '/noise_map.fits' ccd_data = ccd.load_ccd_data_from_fits(image_path=image_path, psf_path=psf_path, noise_map_path=noise_map_path, pixel_scale=0.03) # These plotters can be customized using the exact same functions as above. ccd_plotters.plot_noise_map(ccd_data=ccd_data, title='SLACS1430+4105 Noise-Map', norm='log') # Of course, as we've seen in many other examples, a sub-plot of the ccd data can be plotted. This can also take the # customization inputs above, but it should be noted that the options are applied to all images, and thus will most # likely degrade a number of the sub-plot images. ccd_plotters.plot_ccd_subplot(ccd_data=ccd_data, norm='symmetric_log', linthresh=0.05, linscale=0.02)
image_plane_grid_stack=image_plane_grid_stack) return ccd.CCDData.simulate(array=tracer.image_plane_image_for_simulation, pixel_scale=0.05, exposure_time=300.0, psf=psf, background_sky_level=0.1, add_noise=True) # Lets quickly remind ourselves of the image, and the 3.0" circular mask we'll use to mask it. ccd_data = simulate() mask = msk.Mask.circular(shape=ccd_data.shape, pixel_scale=ccd_data.pixel_scale, radius_arcsec=3.0) ccd_plotters.plot_ccd_subplot(ccd_data=ccd_data, mask=mask) # The lines of code below do everything we're used to, that is, setup an image and its grid stack, mask it, trace it # via a tracer, setup the rectangular mapper, etc. lens_galaxy = g.Galaxy(mass=mp.EllipticalIsothermal( centre=(0.0, 0.0), axis_ratio=0.8, phi=45.0, einstein_radius=1.6)) lens_data = ld.LensData(ccd_data=ccd_data, mask=mask) tracer = ray_tracing.TracerImageSourcePlanes( lens_galaxies=[lens_galaxy], source_galaxies=[g.Galaxy()], image_plane_grid_stack=lens_data.grid_stack) rectangular = pix.Rectangular(shape=(50, 50)) mapper = rectangular.mapper_from_grid_stack_and_border(
# However, as our fit and ray-tracing becomes more complex, it is useful to know how to decompose their different # attributes to extract different things about them. For example, we made our source-galaxy above with two light # profiles, a 'bulge' and 'disk. We can plot the image-plane image of each component individually, if we know how to # break-up the different components of the fit and tracer. profile_plotters.plot_intensities( light_profile=fit.tracer.source_plane.galaxies[0].bulge, grid=fit.tracer.source_plane.grid_stack.regular, title='Bulge Image-Plane Image') profile_plotters.plot_intensities( light_profile=fit.tracer.source_plane.galaxies[0].disk, grid=fit.tracer.source_plane.grid_stack.regular, title='Disk Image-Plane Image') # The fit also has the lensing image, so we can plot the image using the fit too, if we so desire ccd_plotters.plot_ccd_subplot(ccd_data=lens_data.ccd_data) # And, we're done, not just with the tutorial, but the chapter! # To end, I want to quickly talk about code-design and structure. Yeah, I know, as a scientist, you don't like code # and certaintly don't want to think about code! However, the point is, with PyAutoLens, you don't need to! # Think about it - throughout this chapter, we never talk about anything like it was code. We didn't refer to # 'variables', 'parameters' and 'functions' did we? Instead, we talked about 'galaxies', 'planes' and a 'tracer'. These # are the things that, as scientists, we use to visualize a strong lens system. # Software that abstracts the underlying code in this way follows what is called an 'object-oriented design', and it is # our hope with PyAutoLens that we've made the way you use it (that is, in coding speak, its 'interface') intuitive. # However, if you do enjoy code, variables, functions, and parameters, you're probably ready to take a look at the # PyAutoLens source-code. This can be found in the 'autolens' folder. At team PyAutoLens, we take a lot of pride
pixel_scale=0.1, psf_path=path + '/data/example/' + lens_name + '/psf.fits', noise_map_path=path + '/data/example/' + lens_name + '/noise_map.fits') # The phase can be passed a mask, which we setup below as a 3.0" circle. mask = msk.Mask.circular(shape=ccd_data.shape, pixel_scale=ccd_data.pixel_scale, radius_arcsec=3.0) # We can also specify a set of positions, which must be traced within a threshold value or else the mass model is positions = ccd.load_positions(positions_path=path + '/data/' + lens_name + '/positions.dat') # resampled (see howtolens/chapter_2_lens_modeling/tutorial_7_masking_and_positions.ipynb) ccd_plotters.plot_ccd_subplot(ccd_data=ccd_data, mask=mask, positions=positions) # We're going to model our lens galaxy using a light profile (an elliptical Sersic) and mass profile # (a singular isothermal ellipsoid). We load these profiles from the 'light_profiles (lp)' and 'mass_profiles (mp)'. # To setup our model galaxies, we use the 'galaxy_model' module and GalaxyModel class. # A GalaxyModel represents a galaxy where the parameters of its associated profiles are # variable and fitted for by the analysis. lens_galaxy_model = gm.GalaxyModel(light=lp.EllipticalSersic, mass=mp.EllipticalIsothermal) source_galaxy_model = gm.GalaxyModel(light=lp.EllipticalSersic) # To perform the analysis, we set up a phase using the 'phase' module (imported as 'ph'). # A phase takes our galaxy models and fits their parameters using a non-linear search (in this case, MultiNest). phase = ph.LensSourcePlanePhase(
tracer = ray_tracing.TracerImageSourcePlanes( lens_galaxies=[lens_galaxy], source_galaxies=[source_galaxy], image_plane_grid_stack=image_plane_grid_stack) return ccd.CCDData.simulate(array=tracer.image_plane_image_for_simulation, pixel_scale=0.05, exposure_time=300.0, psf=psf, background_sky_level=0.1, add_noise=True) # Lets have a quick look at the image. ccd_data = simulate() ccd_plotters.plot_ccd_subplot(ccd_data=ccd_data) # So, what is a border? In the image-plane, a border is the set of exterior pixels in a mask that are at, well, its # border. Lets plot the image with a circular mask, and tell our imaging plotter to plot the border as well. mask_circular = msk.Mask.circular(shape=ccd_data.shape, pixel_scale=ccd_data.pixel_scale, radius_arcsec=2.5) ccd_plotters.plot_ccd_subplot(ccd_data=ccd_data, mask=mask_circular, should_plot_border=True) # As you can see, for a circular mask, the border *is* the edge of our mask (the ring of black dots we're used to seeing # whenever we plot a mask). For an annular mask, not every pixel on the edge of the mask is necessarily a part of its # border! mask_annular = msk.Mask.circular_annular(shape=ccd_data.shape, pixel_scale=ccd_data.pixel_scale,
# and that you place your datas in the 'AutoLens/workspace/datas' directory. # (for this tutorial, we'll use the 'AutoLens/workspace/howtolens/preparing_data' directory. The folder 'datas' contains # the example datas-sets we'll use in this tutorial). path = 'path/to/AutoLens/workspace/howtolens/chapter_2_lens_modeling/' # <----- You must include this slash on the end path = '/home/jammy/PyCharm/Projects/AutoLens/workspace/howtolens/loading_and_preparing_data/' simulate_data.simulate_all_images() # This will populate the 'data' folder. # First, lets load a datas-set using the 'load_imaging_from_fits' function of the regular module (import as 'im'). This # datas-set represents a good datas-reduction - it conforms to all the formatting standards I describe in this tutorial! ccd_data = ccd.load_ccd_data_from_fits( image_path=path + 'data/image/image.fits', noise_map_path=path + 'data/image/noise_map.fits', psf_path=path + 'data/image/psf.fits', pixel_scale=0.1) ccd_plotters.plot_ccd_subplot(ccd_data=ccd_data) # If your datas comes in one .fits file spread across multiple hdus, you can specify the hdus of each regular instead. ccd_data = ccd.load_ccd_data_from_fits( image_path=path + 'data/image/multiple_hdus.fits', image_hdu=0, noise_map_path=path + 'data/image/multiple_hdus.fits', noise_map_hdu=1, psf_path=path + 'data/image/multiple_hdus.fits', psf_hdu=2, pixel_scale=0.1) ccd_plotters.plot_ccd_subplot(ccd_data=ccd_data) # Now, lets think about the format and datas-reduction of our datas. There are numerous reasons why the regular we just # looked at is a good datas-set for lens modeling. I strongly recommend you reduce your datas to conform to the # standards discussed below - it'll make your time using PyAutoLens a lot simpler.