def test_setup(self):

        cosmo = None
        lens_model = LensModel(['EPL'])
        grid_radius_arcsec = None
        grid_resolution = None
        source_fwhm_parsec = 30.
        source_light_model = 'SINGLE_GAUSSIAN'
        z_source = 2.
        source_x, source_y = 0., 0.
        dx, dy, amp_scale, size_scale = None, None, None, None
        gridx, gridy, source_model, kwargs_source, grid_resolution, grid_radius_arcsec = setup_mag_finite(cosmo, lens_model, grid_radius_arcsec, grid_resolution,
                                                                                                          source_fwhm_parsec, source_light_model,
                                                                                                          z_source, source_x, source_y, dx, dy,
                                                                                                          amp_scale, size_scale)
        npt.assert_equal(True, len(source_model.func_list)==1)
        npt.assert_equal(True, grid_resolution is not None)
        npt.assert_equal(True, grid_radius_arcsec is not None)

        grid_resolution = 0.001
        grid_radius_arcsec = 0.05
        dx, dy, amp_scale, size_scale = 0., 0.1, 1., 1.
        source_light_model = 'DOUBLE_GAUSSIAN'
        gridx, gridy, source_model, kwargs_source, grid_resolution, grid_radius_arcsec = setup_mag_finite(cosmo, lens_model, grid_radius_arcsec, grid_resolution,
                                                                                                          source_fwhm_parsec, source_light_model,
                                                                                                          z_source, source_x, source_y, dx, dy,
                                                                                                          amp_scale, size_scale)
        npt.assert_equal(True, len(source_model.func_list) == 2)
        npt.assert_equal(kwargs_source[1]['center_y'], kwargs_source[0]['center_y'] + dy)
        npt.assert_equal(kwargs_source[1]['center_x'], kwargs_source[0]['center_x'] + dx)
        npt.assert_equal(True, grid_resolution == 0.001)
        npt.assert_equal(True, grid_radius_arcsec == 0.05)

        source_light_model = 'trash'
        npt.assert_raises(Exception, setup_mag_finite,
                          cosmo,
                          lens_model,
                          grid_radius_arcsec,
                          grid_resolution,
                          source_fwhm_parsec,
                          source_light_model,
                          z_source,
                          source_x,
                          source_y, dx,
                          dy,
                          amp_scale,
                          size_scale
                          )
    def magnification_finite_adaptive(self, x_image, y_image, source_x, source_y, kwargs_lens,
                                      source_fwhm_parsec, z_source,
                                      cosmo=None, grid_resolution=None,
                                      grid_radius_arcsec=None, axis_ratio=0.5,
                                      tol=0.001, step_size=0.05,
                                      use_largest_eigenvalue=True,
                                      source_light_model='SINGLE_GAUSSIAN',
                                      dx=None, dy=None, size_scale=None, amp_scale=None,
                                      fixed_aperture_size=False):
        """
        This method computes image magnifications with a finite-size background source assuming a Gaussian or a
        double Gaussian source light profile. It can be much faster that magnification_finite for lens models with many
        deflectors and a compact source. This is because most pixels in a rectangular window around a lensed
        image of a compact source do not map onto the source, and therefore don't contribute to the integrated flux in
        the image plane.

        Rather than ray tracing through a rectangular grid, this routine accelerates the computation of image
        magnifications with finite-size sources by ray tracing through an elliptical region oriented such that
        tracks the surface brightness of the lensed image. The aperture size is initially quite small,
        and increases in size until the flux inside of it (and hence the magnification) converges. The orientation of
        the elliptical aperture is computed from the magnification tensor evaluated at the image coordinate.

        If for whatever reason you prefer a circular aperture to the elliptical approximation using the hessian
        eigenvectors, you can just set axis_ratio = 1.

        To use the eigenvalues of the hessian matrix to estimate the optimum axis ratio, set axis_ratio = 0.

        The default settings for the grid resolution and ray tracing window size work well for sources with fwhm between
        0.5 - 100 pc.

        :param x_image: a list or array of x coordinates [units arcsec]
        :param y_image: a list or array of y coordinates [units arcsec]
        :param source_x: float, source position
        :param source_y: float, source position
        :param kwargs_lens: keyword arguments for the lens model
        :param source_fwhm_parsec: the size of the background source [units parsec]
        :param z_source: the source redshift
        :param cosmo: (optional) an instance of astropy.cosmology; if not specified, a default cosmology will be used
        :param grid_resolution: the grid resolution in units arcsec/pixel; if not specified, an appropriate value will
         be estimated from the source size
        :param grid_radius_arcsec: (optional) the size of the ray tracing region in arcsec; if not specified, an appropriate value
         will be estimated from the source size
        :param axis_ratio: the axis ratio of the ellipse used for ray tracing; if axis_ratio = 0, then the eigenvalues
         the hessian matrix will be used to estimate an appropriate axis ratio. Be warned: if the image is highly
         magnified it will tend to curve out of the resulting ellipse
        :param tol: tolerance for convergence in the magnification
        :param step_size: sets the increment for the successively larger ray tracing windows
        :param use_largest_eigenvalue: bool; if True, then the major axis of the ray tracing ellipse region
         will be aligned with the eigenvector corresponding to the largest eigenvalue of the hessian matrix
        :param source_light_model: the model for backgourn source light; currently implemented are 'SINGLE_GAUSSIAN' and
         'DOUBLE_GAUSSIAN'.
        :param dx: used with source model 'DOUBLE_GAUSSIAN', the offset of the second source light profile from the first
         [arcsec]
        :param dy: used with source model 'DOUBLE_GAUSSIAN', the offset of the second source light profile from the first
         [arcsec]
        :param size_scale: used with source model 'DOUBLE_GAUSSIAN', the size of the second source light profile relative
         to the first
        :param amp_scale: used with source model 'DOUBLE_GAUSSIAN', the peak brightness of the second source light profile
         relative to the first
        :param fixed_aperture_size: bool, if True the flux is computed inside a fixed aperture size with radius
         grid_radius_arcsec
        :return: an array of image magnifications
        """

        grid_x_0, grid_y_0, source_model, kwargs_source, grid_resolution, grid_radius_arcsec = setup_mag_finite(cosmo,
                                                                                                                self._lensModel,
                                                                                                                grid_radius_arcsec,
                                                                                                                grid_resolution,
                                                                                                                source_fwhm_parsec,
                                                                                                                source_light_model,
                                                                                                                z_source,
                                                                                                                source_x,
                                                                                                                source_y,
                                                                                                                dx, dy,
                                                                                                                amp_scale,
                                                                                                                size_scale)
        grid_x_0, grid_y_0 = grid_x_0.ravel(), grid_y_0.ravel()

        minimum_magnification = 1e-5

        magnifications = []

        for xi, yi in zip(x_image, y_image):

            if axis_ratio == 1:
                grid_r = np.hypot(grid_x_0, grid_y_0)
            else:
                w1, w2, v11, v12, v21, v22 = self.hessian_eigenvectors(xi, yi, kwargs_lens)
                _v = [np.array([v11, v12]), np.array([v21, v22])]
                _w = [abs(w1), abs(w2)]
                if use_largest_eigenvalue:
                    idx = int(np.argmax(_w))
                else:
                    idx = int(np.argmin(_w))
                v = _v[idx]

                rotation_angle = np.arctan(v[1] / v[0]) - np.pi / 2
                grid_x, grid_y = util.rotate(grid_x_0, grid_y_0, rotation_angle)

                if axis_ratio == 0:
                    sort = np.argsort(_w)
                    q = _w[sort[0]] / _w[sort[1]]
                    grid_r = np.hypot(grid_x, grid_y / q).ravel()
                else:
                    grid_r = np.hypot(grid_x, grid_y / axis_ratio).ravel()

            flux_array = np.zeros_like(grid_x_0)
            step = step_size * grid_radius_arcsec

            r_min = 0
            if fixed_aperture_size:
                r_max = grid_radius_arcsec
            else:
                r_max = step
            magnification_current = 0.

            while True:

                flux_array = self._magnification_adaptive_iteration(flux_array, xi, yi, grid_x_0, grid_y_0, grid_r,
                                                                    r_min, r_max, self._lensModel, kwargs_lens,
                                                                    source_model, kwargs_source)
                new_magnification = np.sum(flux_array) * grid_resolution ** 2
                diff = abs(new_magnification - magnification_current) / new_magnification

                if r_max >= grid_radius_arcsec:
                    break
                elif diff < tol and new_magnification > minimum_magnification:
                    break
                else:
                    r_min += step
                    r_max += step
                    magnification_current = new_magnification

            magnifications.append(new_magnification)

        return np.array(magnifications)
Beispiel #3
0
def plot_quasar_images(lens_model,
                       x_image,
                       y_image,
                       source_x,
                       source_y,
                       kwargs_lens,
                       source_fwhm_parsec,
                       z_source,
                       cosmo=None,
                       grid_resolution=None,
                       grid_radius_arcsec=None,
                       source_light_model='SINGLE_GAUSSIAN',
                       dx=None,
                       dy=None,
                       size_scale=None,
                       amp_scale=None):
    """
    This function plots the surface brightness in the image plane of a background source modeled as either a single
    Gaussian or two Gaussian light profiles. The flux is computed inside a circular aperture with radius
    grid_radius_arcsec. If grid_radius_arcsec is not specified a default value will be assumed.

    :param lens_model: an instance of LensModel
    :param x_image: a list or array of x coordinates [units arcsec]
    :param y_image: a list or array of y coordinates [units arcsec]
    :param kwargs_lens: keyword arguments for the lens model
    :param source_fwhm_parsec: the size of the background source [units parsec]
    :param z_source: the source redshift
    :param cosmo: (optional) an instance of astropy.cosmology; if not specified, a default cosmology will be used
    :param grid_resolution: the grid resolution in units arcsec/pixel; if not specified, an appropriate value will
    be estimated from the source size
    :param grid_radius_arcsec: (optional) the size of the ray tracing region in arcsec; if not specified, an appropriate value
    will be estimated from the source size
    :param source_light_model: the model for background source light; currently implemented are 'SINGLE_GAUSSIAN' and
    'DOUBLE_GAUSSIAN'.
    :param dx: used with source model 'DOUBLE_GAUSSIAN', the offset of the second source light profile from the first
    [arcsec]
    :param dy: used with source model 'DOUBLE_GAUSSIAN', the offset of the second source light profile from the first
    [arcsec]
    :param size_scale: used with source model 'DOUBLE_GAUSSIAN', the size of the second source light profile relative
    to the first
    :param amp_scale: used with source model 'DOUBLE_GAUSSIAN', the peak brightness of the second source light profile
    relative to the first
    :return: Four images of the background source in the image plane
    """

    lens_model_extension = LensModelExtensions(lens_model)

    magnifications = []
    images = []

    grid_x_0, grid_y_0, source_model, kwargs_source, grid_resolution, grid_radius_arcsec = \
        setup_mag_finite(cosmo, lens_model, grid_radius_arcsec, grid_resolution, source_fwhm_parsec,
                         source_light_model, z_source, source_x, source_y, dx, dy, amp_scale, size_scale)
    shape0 = grid_x_0.shape
    grid_x_0, grid_y_0 = grid_x_0.ravel(), grid_y_0.ravel()

    for xi, yi in zip(x_image, y_image):
        flux_array = np.zeros_like(grid_x_0)
        r_min = 0
        r_max = grid_radius_arcsec
        grid_r = np.hypot(grid_x_0, grid_y_0)
        flux_array = lens_model_extension._magnification_adaptive_iteration(
            flux_array, xi, yi, grid_x_0, grid_y_0, grid_r, r_min, r_max,
            lens_model, kwargs_lens, source_model, kwargs_source)
        m = np.sum(flux_array) * grid_resolution**2
        magnifications.append(m)
        images.append(flux_array.reshape(shape0))

    magnifications = np.array(magnifications)
    flux_ratios = magnifications / max(magnifications)
    import matplotlib.pyplot as plt
    fig = plt.figure(1)
    fig.set_size_inches(16, 6)
    N = len(images)
    for i, (image, mag,
            fr) in enumerate(zip(images, magnifications, flux_ratios)):
        ax = plt.subplot(1, N, i + 1)
        ax.imshow(image,
                  origin='lower',
                  extent=[
                      -grid_radius_arcsec, grid_radius_arcsec,
                      -grid_radius_arcsec, grid_radius_arcsec
                  ])
        ax.annotate('magnification: ' + str(np.round(mag, 3)),
                    xy=(0.05, 0.9),
                    xycoords='axes fraction',
                    color='w',
                    fontsize=12)
        ax.annotate('flux ratio: ' + str(np.round(fr, 3)),
                    xy=(0.05, 0.8),
                    xycoords='axes fraction',
                    color='w',
                    fontsize=12)
    plt.show()