Module deeplenstronomy.image_generator

Generate images from the organized user inputs.

Expand source code
"""Generate images from the organized user inputs."""

from astropy.cosmology import FlatLambdaCDM
from lenstronomy.SimulationAPI.sim_api import SimAPI
from lenstronomy.LensModel.Solver import lens_equation_solver
import numpy as np

import deeplenstronomy.distributions as distributions

from deeplenstronomy.utils import dict_select, dict_select_choose, select_params


class ImageGenerator():
    def __init__(self, return_planes=False, solve_lens_equation=False):
        """
        This is an internal class which calls lenstronomy functions based on parsed user inputs.
        
        Args:
            return_planes (bool): Automatically passed from deeplenstronomy.make_dataset args
            solve_lens_equation (bool): Automatically passed from deeplenstronomy.make_dataset args

        """
        self.return_planes = return_planes
        self.solve_lens_equation = solve_lens_equation
        return
    
    def sim_image(self, info_dict):
        """
        Simulate an image based on specifications in sim_dict
        
        Args:
            info_dict (dict): A single element from the list produced interanlly by input_reader.Organizer.breakup(). 
                Contains all the properties of a single image to generate.
        """
        output_image = []
        if self.return_planes:
            output_source, output_lens, output_point_source, output_noise = [], [], [], []
        output_metadata = []
        
        #set the cosmology
        cosmology_info = ['H0', 'Om0', 'Tcmb0', 'Neff', 'm_nu', 'Ob0']
        cosmo = FlatLambdaCDM(**dict_select_choose(list(info_dict.values())[0], cosmology_info))
        
        for band, sim_dict in info_dict.items():
            ### Geometry-independent image properties
            
            # Single Band Info
            single_band_info = ['read_noise', 'pixel_scale', 'ccd_gain', 'exposure_time',
                                'sky_brightness', 'seeing', 'magnitude_zero_point',
                                'num_exposures', 'data_count_unit', 'background_noise']
            kwargs_single_band = dict_select_choose(sim_dict, single_band_info)
            
            # Extinction
            extinction_class = None  #figure this out later
            
            # Numerics -- only use single number kwargs
            numerics_info = ['supersampling_factor', 'compute_mode', 'supersampling_convolution',
                             'supersampling_kernel_size', 'point_source_supersampling_factor', 
                             'convolution_kernel_size']
            kwargs_numerics = dict_select_choose(sim_dict, numerics_info)
            
            ### Geometry-dependent image properties
            
            # Dictionary for physical model
            kwargs_model = {'lens_model_list': [],  # list of lens models to be used
                            'lens_redshift_list': [],  # list of redshift of the deflections
                            'lens_light_model_list': [],  # list of unlensed light models to be used
                            'source_light_model_list': [],  # list of extended source models to be used
                            'source_redshift_list': [],  # list of redshfits of the sources in same order as source_light_model_list
                            'point_source_model_list': [], # list of point source models
                            'cosmo': cosmo,
                            'z_source': 0.0}

            # Lists for model kwargs
            kwargs_source_list, kwargs_lens_model_list, kwargs_lens_light_list, kwargs_point_source_list = [], [], [], []
            
            for plane_num in range(1, sim_dict['NUMBER_OF_PLANES'] + 1):
                
                for obj_num in range(1, sim_dict['PLANE_{0}-NUMBER_OF_OBJECTS'.format(plane_num)] + 1):
                    
                    prefix = 'PLANE_{0}-OBJECT_{1}-'.format(plane_num, obj_num)
                    
                    ### Point sources
                    if sim_dict[prefix + 'HOST'] != 'None':
                        
                        # Foreground objects
                        if sim_dict[prefix + 'HOST'] == 'Foreground':
                            kwargs_model['point_source_model_list'].append('UNLENSED')
                            ps_info = ['PLANE_{0}-OBJECT_{1}-{2}'.format(plane_num, obj_num, x) for x in ['ra_image', 'dec_image', 'magnitude']]
                            ps_dict_info = dict_select(sim_dict, ps_info)
                            kwargs_point_source_list.append({'ra_image': [ps_dict_info[prefix + 'ra_image']], 'dec_image': [ps_dict_info[prefix + 'dec_image']], 'magnitude': [ps_dict_info[prefix + 'magnitude']]})
                        # Real point sources
                        else:
                            if plane_num < sim_dict['NUMBER_OF_PLANES']:
                                # point sources in the lens
                                kwargs_model['point_source_model_list'].append('LENSED_POSITION')
                                ps_info = ['PLANE_{0}-OBJECT_{1}-{2}'.format(plane_num, obj_num, x) for x in ['ra', 'dec', 'magnitude']]
                                ps_dict_info = dict_select(sim_dict, ps_info)
                                kwargs_point_source_list.append({'ra_image': [ps_dict_info[prefix + 'ra']],
                                                                 'dec_image': [ps_dict_info[prefix + 'dec']],
                                                                 'magnitude': [ps_dict_info[prefix + 'magnitude']]})
                            elif plane_num == sim_dict['NUMBER_OF_PLANES']:
                                # point sources in the source plane
                                kwargs_model['point_source_model_list'].append('SOURCE_POSITION')
                                ps_info = ['PLANE_{0}-OBJECT_{1}-{2}'.format(plane_num, obj_num, x) for x in ['ra', 'dec', 'magnitude']]
                                ps_dict_info = dict_select(sim_dict, ps_info)
                                kwargs_point_source_list.append({'ra_source': ps_dict_info['PLANE_{0}-OBJECT_{1}-ra'.format(plane_num, obj_num)], 
                                                                 'dec_source': ps_dict_info['PLANE_{0}-OBJECT_{1}-dec'.format(plane_num, obj_num)], 
                                                                 'magnitude': ps_dict_info['PLANE_{0}-OBJECT_{1}-magnitude'.format(plane_num, obj_num)]})
                            else:
                                #should never get here
                                assert False
                                
                        # the number of profiles will be zero for point sources, so just skip ahead
                        continue
                    
                    ### Model keywords
                    # All planes except last one - treat as lens
                    if plane_num < sim_dict['NUMBER_OF_PLANES']:
                        for light_profile_num in range(1, sim_dict[prefix + 'NUMBER_OF_LIGHT_PROFILES'] +1):
                            kwargs_model['lens_light_model_list'].append(sim_dict[prefix + 'LIGHT_PROFILE_{0}-NAME'.format(light_profile_num)])
                            #kwargs_model['lens_redshift_list'].append(sim_dict[prefix + 'REDSHIFT'])
                            kwargs_lens_light_list.append(select_params(sim_dict, prefix + 'LIGHT_PROFILE_{0}-'.format(light_profile_num)))
                        for mass_profile_num in range(1, sim_dict[prefix + 'NUMBER_OF_MASS_PROFILES'] +1):
                            kwargs_model['lens_model_list'].append(sim_dict[prefix + 'MASS_PROFILE_{0}-NAME'.format(mass_profile_num)])
                            kwargs_model['lens_redshift_list'].append(sim_dict[prefix + 'REDSHIFT'])
                            mass_params = select_params(sim_dict, prefix + 'MASS_PROFILE_{0}-'.format(mass_profile_num))
                            kwargs_lens_model_list.append(mass_params)
                            if 'sigma_v' in mass_params.keys(): # save simga_v locations so that we can calculate theta_E for the metadata
                                output_metadata.append({'PARAM_NAME':  prefix + 'MASS_PROFILE_{0}-sigma_v-{1}'.format(mass_profile_num, band),
                                                        'PARAM_VALUE': mass_params['sigma_v'],
                                                        'LENS_MODEL_IDX': len(kwargs_lens_model_list) - 1})
                        for shear_profile_num in range(1, sim_dict[prefix + 'NUMBER_OF_SHEAR_PROFILES'] +1):
                            kwargs_model['lens_model_list'].append(sim_dict[prefix + 'SHEAR_PROFILE_{0}-NAME'.format(shear_profile_num)])
                            kwargs_model['lens_redshift_list'].append(sim_dict[prefix + 'REDSHIFT'])
                            mass_params = select_params(sim_dict, prefix + 'SHEAR_PROFILE_{0}-'.format(shear_profile_num))
                            kwargs_lens_model_list.append(select_params(sim_dict, prefix + 'SHEAR_PROFILE_{0}-'.format(shear_profile_num)))
                                                   
                    # Last Plane - treat as source
                    elif plane_num == sim_dict['NUMBER_OF_PLANES']:
                        kwargs_model['z_source'] = sim_dict[prefix + 'REDSHIFT']
                        for light_profile_num in range(1, sim_dict[prefix + 'NUMBER_OF_LIGHT_PROFILES'] +1):
                            kwargs_model['source_light_model_list'].append(sim_dict[prefix + 'LIGHT_PROFILE_{0}-NAME'.format(light_profile_num)])
                            kwargs_model['source_redshift_list'].append(sim_dict[prefix + 'REDSHIFT'])
                            kwargs_source_list.append(select_params(sim_dict, prefix + 'LIGHT_PROFILE_{0}-'.format(light_profile_num)))
                        
                    else:
                        # Should never get here
                        assert False

            # Make image
            sim = SimAPI(numpix=sim_dict['numPix'], 
                         kwargs_single_band=kwargs_single_band, 
                         kwargs_model=kwargs_model)

            imSim = sim.image_model_class(kwargs_numerics)
            
            kwargs_lens_light_list, kwargs_source_list, kwargs_point_source_list = sim.magnitude2amplitude(kwargs_lens_light_mag=kwargs_lens_light_list,
                                                                                                           kwargs_source_mag=kwargs_source_list,
                                                                                                           kwargs_ps_mag=kwargs_point_source_list)
            
            kwargs_lens_model_list = sim.physical2lensing_conversion(kwargs_mass=kwargs_lens_model_list)
            # Save theta_E (and sigma_v if used)
            for ii in range(len(output_metadata)):
                output_metadata.append({'PARAM_NAME': output_metadata[ii]['PARAM_NAME'].replace('sigma_v', 'theta_E'),
                                        'PARAM_VALUE': kwargs_lens_model_list[output_metadata[ii]['LENS_MODEL_IDX']]['theta_E'],
                                        'LENS_MODEL_IDX': output_metadata[ii]['LENS_MODEL_IDX']})
                
            try:
                image = imSim.image(kwargs_lens=kwargs_lens_model_list,
                                    kwargs_lens_light=kwargs_lens_light_list,
                                    kwargs_source=kwargs_source_list,
                                    kwargs_ps=kwargs_point_source_list)
            except Exception:
                # Some sort of lenstronomy error
                print("kwargs_numerics", kwargs_numerics)
                print("kwargs_single_band", kwargs_single_band)
                print("kwargs_model", kwargs_model)
                print("kwargs_lens_model_list", kwargs_lens_model_list)
                print("kwargs_lens_light_list", kwargs_lens_light_list)
                print("kwargs_source_list", kwargs_source_list)
                print("kwargs_point_source_list", kwargs_point_source_list)
                assert False
                                
            # Solve lens equation if desired
            if self.solve_lens_equation:
                solver = lens_equation_solver.LensEquationSolver(imSim.LensModel)
                x_mins, y_mins = solver.image_position_from_source(sourcePos_x=kwargs_source_list[0]['center_x'],
                                                                   sourcePos_y=kwargs_source_list[0]['center_y'],
                                                                   kwargs_lens=kwargs_lens_model_list)
                num_source_images = len(x_mins)
            
            # Add noise
            image_noise = np.zeros(np.shape(image))
            for noise_source_num in range(1, sim_dict['NUMBER_OF_NOISE_SOURCES'] + 1):
                image_noise += self._generate_noise(sim_dict['NOISE_SOURCE_{0}-NAME'.format(noise_source_num)],
                                                    np.shape(image),
                                                    select_params(sim_dict, 'NOISE_SOURCE_{0}-'.format(noise_source_num)))
            image += image_noise
                
            # Combine with other bands
            output_image.append(image)

            # Store plane-separated info if requested
            if self.return_planes:
                output_lens.append(imSim.lens_surface_brightness(kwargs_lens_light_list))
                output_source.append(imSim.source_surface_brightness(kwargs_source_list, kwargs_lens_model_list))
                output_point_source.append(imSim.point_source(kwargs_point_source_list, kwargs_lens_model_list))
                output_noise.append(image_noise)
        
        # Return the desired information in a dictionary
        return_dict = {'output_image': np.array(output_image),
                       'output_lens_plane': None,
                       'output_source_plane': None,
                       'output_point_source_plane': None,
                       'output_noise_plane': None,
                       'x_mins': None,
                       'y_mins': None,
                       'num_source_images': None,
                       'additional_metadata': output_metadata}
        if self.return_planes:
            return_dict['output_lens_plane'] = np.array(output_lens)
            return_dict['output_source_plane'] = np.array(output_source)
            return_dict['output_point_source_plane'] = np.array(output_point_source)
            return_dict['output_noise_plane'] = np.array(output_noise)
        if self.solve_lens_equation:
            return_dict['x_mins'] = x_mins
            return_dict['y_mins'] = y_mins
            return_dict['num_source_images'] = num_source_images

        return return_dict

    def _generate_noise(self, name, shape, params):
        """
        Add noise to image based on input yaml by targeting specified distribution.
        
        :param name: name of the distribution to target
        :param shape: shape of image to add noise to
        :param params: dictionary of additional parameters needed by distributions.name()
        :return: noise_image: noise from targeted distribution for the image
        """
        return eval('distributions.{0}(shape, **params)'.format(name.lower()))

    

                        

Classes

class ImageGenerator (return_planes=False, solve_lens_equation=False)

This is an internal class which calls lenstronomy functions based on parsed user inputs.

Args

return_planes : bool
Automatically passed from deeplenstronomy.make_dataset args
solve_lens_equation : bool
Automatically passed from deeplenstronomy.make_dataset args
Expand source code
class ImageGenerator():
    def __init__(self, return_planes=False, solve_lens_equation=False):
        """
        This is an internal class which calls lenstronomy functions based on parsed user inputs.
        
        Args:
            return_planes (bool): Automatically passed from deeplenstronomy.make_dataset args
            solve_lens_equation (bool): Automatically passed from deeplenstronomy.make_dataset args

        """
        self.return_planes = return_planes
        self.solve_lens_equation = solve_lens_equation
        return
    
    def sim_image(self, info_dict):
        """
        Simulate an image based on specifications in sim_dict
        
        Args:
            info_dict (dict): A single element from the list produced interanlly by input_reader.Organizer.breakup(). 
                Contains all the properties of a single image to generate.
        """
        output_image = []
        if self.return_planes:
            output_source, output_lens, output_point_source, output_noise = [], [], [], []
        output_metadata = []
        
        #set the cosmology
        cosmology_info = ['H0', 'Om0', 'Tcmb0', 'Neff', 'm_nu', 'Ob0']
        cosmo = FlatLambdaCDM(**dict_select_choose(list(info_dict.values())[0], cosmology_info))
        
        for band, sim_dict in info_dict.items():
            ### Geometry-independent image properties
            
            # Single Band Info
            single_band_info = ['read_noise', 'pixel_scale', 'ccd_gain', 'exposure_time',
                                'sky_brightness', 'seeing', 'magnitude_zero_point',
                                'num_exposures', 'data_count_unit', 'background_noise']
            kwargs_single_band = dict_select_choose(sim_dict, single_band_info)
            
            # Extinction
            extinction_class = None  #figure this out later
            
            # Numerics -- only use single number kwargs
            numerics_info = ['supersampling_factor', 'compute_mode', 'supersampling_convolution',
                             'supersampling_kernel_size', 'point_source_supersampling_factor', 
                             'convolution_kernel_size']
            kwargs_numerics = dict_select_choose(sim_dict, numerics_info)
            
            ### Geometry-dependent image properties
            
            # Dictionary for physical model
            kwargs_model = {'lens_model_list': [],  # list of lens models to be used
                            'lens_redshift_list': [],  # list of redshift of the deflections
                            'lens_light_model_list': [],  # list of unlensed light models to be used
                            'source_light_model_list': [],  # list of extended source models to be used
                            'source_redshift_list': [],  # list of redshfits of the sources in same order as source_light_model_list
                            'point_source_model_list': [], # list of point source models
                            'cosmo': cosmo,
                            'z_source': 0.0}

            # Lists for model kwargs
            kwargs_source_list, kwargs_lens_model_list, kwargs_lens_light_list, kwargs_point_source_list = [], [], [], []
            
            for plane_num in range(1, sim_dict['NUMBER_OF_PLANES'] + 1):
                
                for obj_num in range(1, sim_dict['PLANE_{0}-NUMBER_OF_OBJECTS'.format(plane_num)] + 1):
                    
                    prefix = 'PLANE_{0}-OBJECT_{1}-'.format(plane_num, obj_num)
                    
                    ### Point sources
                    if sim_dict[prefix + 'HOST'] != 'None':
                        
                        # Foreground objects
                        if sim_dict[prefix + 'HOST'] == 'Foreground':
                            kwargs_model['point_source_model_list'].append('UNLENSED')
                            ps_info = ['PLANE_{0}-OBJECT_{1}-{2}'.format(plane_num, obj_num, x) for x in ['ra_image', 'dec_image', 'magnitude']]
                            ps_dict_info = dict_select(sim_dict, ps_info)
                            kwargs_point_source_list.append({'ra_image': [ps_dict_info[prefix + 'ra_image']], 'dec_image': [ps_dict_info[prefix + 'dec_image']], 'magnitude': [ps_dict_info[prefix + 'magnitude']]})
                        # Real point sources
                        else:
                            if plane_num < sim_dict['NUMBER_OF_PLANES']:
                                # point sources in the lens
                                kwargs_model['point_source_model_list'].append('LENSED_POSITION')
                                ps_info = ['PLANE_{0}-OBJECT_{1}-{2}'.format(plane_num, obj_num, x) for x in ['ra', 'dec', 'magnitude']]
                                ps_dict_info = dict_select(sim_dict, ps_info)
                                kwargs_point_source_list.append({'ra_image': [ps_dict_info[prefix + 'ra']],
                                                                 'dec_image': [ps_dict_info[prefix + 'dec']],
                                                                 'magnitude': [ps_dict_info[prefix + 'magnitude']]})
                            elif plane_num == sim_dict['NUMBER_OF_PLANES']:
                                # point sources in the source plane
                                kwargs_model['point_source_model_list'].append('SOURCE_POSITION')
                                ps_info = ['PLANE_{0}-OBJECT_{1}-{2}'.format(plane_num, obj_num, x) for x in ['ra', 'dec', 'magnitude']]
                                ps_dict_info = dict_select(sim_dict, ps_info)
                                kwargs_point_source_list.append({'ra_source': ps_dict_info['PLANE_{0}-OBJECT_{1}-ra'.format(plane_num, obj_num)], 
                                                                 'dec_source': ps_dict_info['PLANE_{0}-OBJECT_{1}-dec'.format(plane_num, obj_num)], 
                                                                 'magnitude': ps_dict_info['PLANE_{0}-OBJECT_{1}-magnitude'.format(plane_num, obj_num)]})
                            else:
                                #should never get here
                                assert False
                                
                        # the number of profiles will be zero for point sources, so just skip ahead
                        continue
                    
                    ### Model keywords
                    # All planes except last one - treat as lens
                    if plane_num < sim_dict['NUMBER_OF_PLANES']:
                        for light_profile_num in range(1, sim_dict[prefix + 'NUMBER_OF_LIGHT_PROFILES'] +1):
                            kwargs_model['lens_light_model_list'].append(sim_dict[prefix + 'LIGHT_PROFILE_{0}-NAME'.format(light_profile_num)])
                            #kwargs_model['lens_redshift_list'].append(sim_dict[prefix + 'REDSHIFT'])
                            kwargs_lens_light_list.append(select_params(sim_dict, prefix + 'LIGHT_PROFILE_{0}-'.format(light_profile_num)))
                        for mass_profile_num in range(1, sim_dict[prefix + 'NUMBER_OF_MASS_PROFILES'] +1):
                            kwargs_model['lens_model_list'].append(sim_dict[prefix + 'MASS_PROFILE_{0}-NAME'.format(mass_profile_num)])
                            kwargs_model['lens_redshift_list'].append(sim_dict[prefix + 'REDSHIFT'])
                            mass_params = select_params(sim_dict, prefix + 'MASS_PROFILE_{0}-'.format(mass_profile_num))
                            kwargs_lens_model_list.append(mass_params)
                            if 'sigma_v' in mass_params.keys(): # save simga_v locations so that we can calculate theta_E for the metadata
                                output_metadata.append({'PARAM_NAME':  prefix + 'MASS_PROFILE_{0}-sigma_v-{1}'.format(mass_profile_num, band),
                                                        'PARAM_VALUE': mass_params['sigma_v'],
                                                        'LENS_MODEL_IDX': len(kwargs_lens_model_list) - 1})
                        for shear_profile_num in range(1, sim_dict[prefix + 'NUMBER_OF_SHEAR_PROFILES'] +1):
                            kwargs_model['lens_model_list'].append(sim_dict[prefix + 'SHEAR_PROFILE_{0}-NAME'.format(shear_profile_num)])
                            kwargs_model['lens_redshift_list'].append(sim_dict[prefix + 'REDSHIFT'])
                            mass_params = select_params(sim_dict, prefix + 'SHEAR_PROFILE_{0}-'.format(shear_profile_num))
                            kwargs_lens_model_list.append(select_params(sim_dict, prefix + 'SHEAR_PROFILE_{0}-'.format(shear_profile_num)))
                                                   
                    # Last Plane - treat as source
                    elif plane_num == sim_dict['NUMBER_OF_PLANES']:
                        kwargs_model['z_source'] = sim_dict[prefix + 'REDSHIFT']
                        for light_profile_num in range(1, sim_dict[prefix + 'NUMBER_OF_LIGHT_PROFILES'] +1):
                            kwargs_model['source_light_model_list'].append(sim_dict[prefix + 'LIGHT_PROFILE_{0}-NAME'.format(light_profile_num)])
                            kwargs_model['source_redshift_list'].append(sim_dict[prefix + 'REDSHIFT'])
                            kwargs_source_list.append(select_params(sim_dict, prefix + 'LIGHT_PROFILE_{0}-'.format(light_profile_num)))
                        
                    else:
                        # Should never get here
                        assert False

            # Make image
            sim = SimAPI(numpix=sim_dict['numPix'], 
                         kwargs_single_band=kwargs_single_band, 
                         kwargs_model=kwargs_model)

            imSim = sim.image_model_class(kwargs_numerics)
            
            kwargs_lens_light_list, kwargs_source_list, kwargs_point_source_list = sim.magnitude2amplitude(kwargs_lens_light_mag=kwargs_lens_light_list,
                                                                                                           kwargs_source_mag=kwargs_source_list,
                                                                                                           kwargs_ps_mag=kwargs_point_source_list)
            
            kwargs_lens_model_list = sim.physical2lensing_conversion(kwargs_mass=kwargs_lens_model_list)
            # Save theta_E (and sigma_v if used)
            for ii in range(len(output_metadata)):
                output_metadata.append({'PARAM_NAME': output_metadata[ii]['PARAM_NAME'].replace('sigma_v', 'theta_E'),
                                        'PARAM_VALUE': kwargs_lens_model_list[output_metadata[ii]['LENS_MODEL_IDX']]['theta_E'],
                                        'LENS_MODEL_IDX': output_metadata[ii]['LENS_MODEL_IDX']})
                
            try:
                image = imSim.image(kwargs_lens=kwargs_lens_model_list,
                                    kwargs_lens_light=kwargs_lens_light_list,
                                    kwargs_source=kwargs_source_list,
                                    kwargs_ps=kwargs_point_source_list)
            except Exception:
                # Some sort of lenstronomy error
                print("kwargs_numerics", kwargs_numerics)
                print("kwargs_single_band", kwargs_single_band)
                print("kwargs_model", kwargs_model)
                print("kwargs_lens_model_list", kwargs_lens_model_list)
                print("kwargs_lens_light_list", kwargs_lens_light_list)
                print("kwargs_source_list", kwargs_source_list)
                print("kwargs_point_source_list", kwargs_point_source_list)
                assert False
                                
            # Solve lens equation if desired
            if self.solve_lens_equation:
                solver = lens_equation_solver.LensEquationSolver(imSim.LensModel)
                x_mins, y_mins = solver.image_position_from_source(sourcePos_x=kwargs_source_list[0]['center_x'],
                                                                   sourcePos_y=kwargs_source_list[0]['center_y'],
                                                                   kwargs_lens=kwargs_lens_model_list)
                num_source_images = len(x_mins)
            
            # Add noise
            image_noise = np.zeros(np.shape(image))
            for noise_source_num in range(1, sim_dict['NUMBER_OF_NOISE_SOURCES'] + 1):
                image_noise += self._generate_noise(sim_dict['NOISE_SOURCE_{0}-NAME'.format(noise_source_num)],
                                                    np.shape(image),
                                                    select_params(sim_dict, 'NOISE_SOURCE_{0}-'.format(noise_source_num)))
            image += image_noise
                
            # Combine with other bands
            output_image.append(image)

            # Store plane-separated info if requested
            if self.return_planes:
                output_lens.append(imSim.lens_surface_brightness(kwargs_lens_light_list))
                output_source.append(imSim.source_surface_brightness(kwargs_source_list, kwargs_lens_model_list))
                output_point_source.append(imSim.point_source(kwargs_point_source_list, kwargs_lens_model_list))
                output_noise.append(image_noise)
        
        # Return the desired information in a dictionary
        return_dict = {'output_image': np.array(output_image),
                       'output_lens_plane': None,
                       'output_source_plane': None,
                       'output_point_source_plane': None,
                       'output_noise_plane': None,
                       'x_mins': None,
                       'y_mins': None,
                       'num_source_images': None,
                       'additional_metadata': output_metadata}
        if self.return_planes:
            return_dict['output_lens_plane'] = np.array(output_lens)
            return_dict['output_source_plane'] = np.array(output_source)
            return_dict['output_point_source_plane'] = np.array(output_point_source)
            return_dict['output_noise_plane'] = np.array(output_noise)
        if self.solve_lens_equation:
            return_dict['x_mins'] = x_mins
            return_dict['y_mins'] = y_mins
            return_dict['num_source_images'] = num_source_images

        return return_dict

    def _generate_noise(self, name, shape, params):
        """
        Add noise to image based on input yaml by targeting specified distribution.
        
        :param name: name of the distribution to target
        :param shape: shape of image to add noise to
        :param params: dictionary of additional parameters needed by distributions.name()
        :return: noise_image: noise from targeted distribution for the image
        """
        return eval('distributions.{0}(shape, **params)'.format(name.lower()))

Methods

def sim_image(self, info_dict)

Simulate an image based on specifications in sim_dict

Args

info_dict : dict
A single element from the list produced interanlly by input_reader.Organizer.breakup(). Contains all the properties of a single image to generate.
Expand source code
def sim_image(self, info_dict):
    """
    Simulate an image based on specifications in sim_dict
    
    Args:
        info_dict (dict): A single element from the list produced interanlly by input_reader.Organizer.breakup(). 
            Contains all the properties of a single image to generate.
    """
    output_image = []
    if self.return_planes:
        output_source, output_lens, output_point_source, output_noise = [], [], [], []
    output_metadata = []
    
    #set the cosmology
    cosmology_info = ['H0', 'Om0', 'Tcmb0', 'Neff', 'm_nu', 'Ob0']
    cosmo = FlatLambdaCDM(**dict_select_choose(list(info_dict.values())[0], cosmology_info))
    
    for band, sim_dict in info_dict.items():
        ### Geometry-independent image properties
        
        # Single Band Info
        single_band_info = ['read_noise', 'pixel_scale', 'ccd_gain', 'exposure_time',
                            'sky_brightness', 'seeing', 'magnitude_zero_point',
                            'num_exposures', 'data_count_unit', 'background_noise']
        kwargs_single_band = dict_select_choose(sim_dict, single_band_info)
        
        # Extinction
        extinction_class = None  #figure this out later
        
        # Numerics -- only use single number kwargs
        numerics_info = ['supersampling_factor', 'compute_mode', 'supersampling_convolution',
                         'supersampling_kernel_size', 'point_source_supersampling_factor', 
                         'convolution_kernel_size']
        kwargs_numerics = dict_select_choose(sim_dict, numerics_info)
        
        ### Geometry-dependent image properties
        
        # Dictionary for physical model
        kwargs_model = {'lens_model_list': [],  # list of lens models to be used
                        'lens_redshift_list': [],  # list of redshift of the deflections
                        'lens_light_model_list': [],  # list of unlensed light models to be used
                        'source_light_model_list': [],  # list of extended source models to be used
                        'source_redshift_list': [],  # list of redshfits of the sources in same order as source_light_model_list
                        'point_source_model_list': [], # list of point source models
                        'cosmo': cosmo,
                        'z_source': 0.0}

        # Lists for model kwargs
        kwargs_source_list, kwargs_lens_model_list, kwargs_lens_light_list, kwargs_point_source_list = [], [], [], []
        
        for plane_num in range(1, sim_dict['NUMBER_OF_PLANES'] + 1):
            
            for obj_num in range(1, sim_dict['PLANE_{0}-NUMBER_OF_OBJECTS'.format(plane_num)] + 1):
                
                prefix = 'PLANE_{0}-OBJECT_{1}-'.format(plane_num, obj_num)
                
                ### Point sources
                if sim_dict[prefix + 'HOST'] != 'None':
                    
                    # Foreground objects
                    if sim_dict[prefix + 'HOST'] == 'Foreground':
                        kwargs_model['point_source_model_list'].append('UNLENSED')
                        ps_info = ['PLANE_{0}-OBJECT_{1}-{2}'.format(plane_num, obj_num, x) for x in ['ra_image', 'dec_image', 'magnitude']]
                        ps_dict_info = dict_select(sim_dict, ps_info)
                        kwargs_point_source_list.append({'ra_image': [ps_dict_info[prefix + 'ra_image']], 'dec_image': [ps_dict_info[prefix + 'dec_image']], 'magnitude': [ps_dict_info[prefix + 'magnitude']]})
                    # Real point sources
                    else:
                        if plane_num < sim_dict['NUMBER_OF_PLANES']:
                            # point sources in the lens
                            kwargs_model['point_source_model_list'].append('LENSED_POSITION')
                            ps_info = ['PLANE_{0}-OBJECT_{1}-{2}'.format(plane_num, obj_num, x) for x in ['ra', 'dec', 'magnitude']]
                            ps_dict_info = dict_select(sim_dict, ps_info)
                            kwargs_point_source_list.append({'ra_image': [ps_dict_info[prefix + 'ra']],
                                                             'dec_image': [ps_dict_info[prefix + 'dec']],
                                                             'magnitude': [ps_dict_info[prefix + 'magnitude']]})
                        elif plane_num == sim_dict['NUMBER_OF_PLANES']:
                            # point sources in the source plane
                            kwargs_model['point_source_model_list'].append('SOURCE_POSITION')
                            ps_info = ['PLANE_{0}-OBJECT_{1}-{2}'.format(plane_num, obj_num, x) for x in ['ra', 'dec', 'magnitude']]
                            ps_dict_info = dict_select(sim_dict, ps_info)
                            kwargs_point_source_list.append({'ra_source': ps_dict_info['PLANE_{0}-OBJECT_{1}-ra'.format(plane_num, obj_num)], 
                                                             'dec_source': ps_dict_info['PLANE_{0}-OBJECT_{1}-dec'.format(plane_num, obj_num)], 
                                                             'magnitude': ps_dict_info['PLANE_{0}-OBJECT_{1}-magnitude'.format(plane_num, obj_num)]})
                        else:
                            #should never get here
                            assert False
                            
                    # the number of profiles will be zero for point sources, so just skip ahead
                    continue
                
                ### Model keywords
                # All planes except last one - treat as lens
                if plane_num < sim_dict['NUMBER_OF_PLANES']:
                    for light_profile_num in range(1, sim_dict[prefix + 'NUMBER_OF_LIGHT_PROFILES'] +1):
                        kwargs_model['lens_light_model_list'].append(sim_dict[prefix + 'LIGHT_PROFILE_{0}-NAME'.format(light_profile_num)])
                        #kwargs_model['lens_redshift_list'].append(sim_dict[prefix + 'REDSHIFT'])
                        kwargs_lens_light_list.append(select_params(sim_dict, prefix + 'LIGHT_PROFILE_{0}-'.format(light_profile_num)))
                    for mass_profile_num in range(1, sim_dict[prefix + 'NUMBER_OF_MASS_PROFILES'] +1):
                        kwargs_model['lens_model_list'].append(sim_dict[prefix + 'MASS_PROFILE_{0}-NAME'.format(mass_profile_num)])
                        kwargs_model['lens_redshift_list'].append(sim_dict[prefix + 'REDSHIFT'])
                        mass_params = select_params(sim_dict, prefix + 'MASS_PROFILE_{0}-'.format(mass_profile_num))
                        kwargs_lens_model_list.append(mass_params)
                        if 'sigma_v' in mass_params.keys(): # save simga_v locations so that we can calculate theta_E for the metadata
                            output_metadata.append({'PARAM_NAME':  prefix + 'MASS_PROFILE_{0}-sigma_v-{1}'.format(mass_profile_num, band),
                                                    'PARAM_VALUE': mass_params['sigma_v'],
                                                    'LENS_MODEL_IDX': len(kwargs_lens_model_list) - 1})
                    for shear_profile_num in range(1, sim_dict[prefix + 'NUMBER_OF_SHEAR_PROFILES'] +1):
                        kwargs_model['lens_model_list'].append(sim_dict[prefix + 'SHEAR_PROFILE_{0}-NAME'.format(shear_profile_num)])
                        kwargs_model['lens_redshift_list'].append(sim_dict[prefix + 'REDSHIFT'])
                        mass_params = select_params(sim_dict, prefix + 'SHEAR_PROFILE_{0}-'.format(shear_profile_num))
                        kwargs_lens_model_list.append(select_params(sim_dict, prefix + 'SHEAR_PROFILE_{0}-'.format(shear_profile_num)))
                                               
                # Last Plane - treat as source
                elif plane_num == sim_dict['NUMBER_OF_PLANES']:
                    kwargs_model['z_source'] = sim_dict[prefix + 'REDSHIFT']
                    for light_profile_num in range(1, sim_dict[prefix + 'NUMBER_OF_LIGHT_PROFILES'] +1):
                        kwargs_model['source_light_model_list'].append(sim_dict[prefix + 'LIGHT_PROFILE_{0}-NAME'.format(light_profile_num)])
                        kwargs_model['source_redshift_list'].append(sim_dict[prefix + 'REDSHIFT'])
                        kwargs_source_list.append(select_params(sim_dict, prefix + 'LIGHT_PROFILE_{0}-'.format(light_profile_num)))
                    
                else:
                    # Should never get here
                    assert False

        # Make image
        sim = SimAPI(numpix=sim_dict['numPix'], 
                     kwargs_single_band=kwargs_single_band, 
                     kwargs_model=kwargs_model)

        imSim = sim.image_model_class(kwargs_numerics)
        
        kwargs_lens_light_list, kwargs_source_list, kwargs_point_source_list = sim.magnitude2amplitude(kwargs_lens_light_mag=kwargs_lens_light_list,
                                                                                                       kwargs_source_mag=kwargs_source_list,
                                                                                                       kwargs_ps_mag=kwargs_point_source_list)
        
        kwargs_lens_model_list = sim.physical2lensing_conversion(kwargs_mass=kwargs_lens_model_list)
        # Save theta_E (and sigma_v if used)
        for ii in range(len(output_metadata)):
            output_metadata.append({'PARAM_NAME': output_metadata[ii]['PARAM_NAME'].replace('sigma_v', 'theta_E'),
                                    'PARAM_VALUE': kwargs_lens_model_list[output_metadata[ii]['LENS_MODEL_IDX']]['theta_E'],
                                    'LENS_MODEL_IDX': output_metadata[ii]['LENS_MODEL_IDX']})
            
        try:
            image = imSim.image(kwargs_lens=kwargs_lens_model_list,
                                kwargs_lens_light=kwargs_lens_light_list,
                                kwargs_source=kwargs_source_list,
                                kwargs_ps=kwargs_point_source_list)
        except Exception:
            # Some sort of lenstronomy error
            print("kwargs_numerics", kwargs_numerics)
            print("kwargs_single_band", kwargs_single_band)
            print("kwargs_model", kwargs_model)
            print("kwargs_lens_model_list", kwargs_lens_model_list)
            print("kwargs_lens_light_list", kwargs_lens_light_list)
            print("kwargs_source_list", kwargs_source_list)
            print("kwargs_point_source_list", kwargs_point_source_list)
            assert False
                            
        # Solve lens equation if desired
        if self.solve_lens_equation:
            solver = lens_equation_solver.LensEquationSolver(imSim.LensModel)
            x_mins, y_mins = solver.image_position_from_source(sourcePos_x=kwargs_source_list[0]['center_x'],
                                                               sourcePos_y=kwargs_source_list[0]['center_y'],
                                                               kwargs_lens=kwargs_lens_model_list)
            num_source_images = len(x_mins)
        
        # Add noise
        image_noise = np.zeros(np.shape(image))
        for noise_source_num in range(1, sim_dict['NUMBER_OF_NOISE_SOURCES'] + 1):
            image_noise += self._generate_noise(sim_dict['NOISE_SOURCE_{0}-NAME'.format(noise_source_num)],
                                                np.shape(image),
                                                select_params(sim_dict, 'NOISE_SOURCE_{0}-'.format(noise_source_num)))
        image += image_noise
            
        # Combine with other bands
        output_image.append(image)

        # Store plane-separated info if requested
        if self.return_planes:
            output_lens.append(imSim.lens_surface_brightness(kwargs_lens_light_list))
            output_source.append(imSim.source_surface_brightness(kwargs_source_list, kwargs_lens_model_list))
            output_point_source.append(imSim.point_source(kwargs_point_source_list, kwargs_lens_model_list))
            output_noise.append(image_noise)
    
    # Return the desired information in a dictionary
    return_dict = {'output_image': np.array(output_image),
                   'output_lens_plane': None,
                   'output_source_plane': None,
                   'output_point_source_plane': None,
                   'output_noise_plane': None,
                   'x_mins': None,
                   'y_mins': None,
                   'num_source_images': None,
                   'additional_metadata': output_metadata}
    if self.return_planes:
        return_dict['output_lens_plane'] = np.array(output_lens)
        return_dict['output_source_plane'] = np.array(output_source)
        return_dict['output_point_source_plane'] = np.array(output_point_source)
        return_dict['output_noise_plane'] = np.array(output_noise)
    if self.solve_lens_equation:
        return_dict['x_mins'] = x_mins
        return_dict['y_mins'] = y_mins
        return_dict['num_source_images'] = num_source_images

    return return_dict