lenstronomy.Util.multi_gauss_expansion — lenstronomy 1.9.1 documentation

# Source code for lenstronomy.Util.multi_gauss_expansion

    __author__ = "ajshajib", "sibirrer"
    """
    Multi-Gaussian expansion fitting, based on Capellari 2002, http://adsabs.harvard.edu/abs/2002MNRAS.333..400C
    """

    import numpy as np
    from scipy.optimize import nnls
    import warnings
    from lenstronomy.LightModel.Profiles.gaussian import Gaussian
    gaussian_func = Gaussian()

    from lenstronomy.Util.package_util import exporter
    export, __all__ = exporter()

    @export
    def gaussian(R, sigma, amp):
        """

        :param R: radius
        :param sigma: gaussian sigma
        :param amp: normalization
        :return: Gaussian function
        """
        c = amp / (2 * np.pi * sigma**2)
        return c * np.exp(-(R/float(sigma))**2/2.)

    @export
    def mge_1d(r_array, flux_r, N=20, linspace=False):
        """

        :param r_array: list or radii (numpy array)
        :param flux_r: list of flux values (numpy array)
        :param N: number of Gaussians
        :return: amplitudes and Gaussian sigmas for the best 1d flux profile
        """
        if N == 0:
            warnings.warn('Number of MGE went down to zero! This should not happen!', Warning)
            amplitudes = [0]
            sigmas = [1]
            norm = 0
            return amplitudes, sigmas, norm
        try:
            amplitudes, sigmas, norm = _mge_1d(r_array, flux_r, N, linspace=linspace)
        except:
            N_new = N - 1
            amplitudes, sigmas, norm = mge_1d(r_array, flux_r, N=N_new, linspace=linspace)
        return amplitudes, sigmas, norm

    @export
    def _mge_1d(r_array, flux_r, N=20, linspace=False):
        """

        :param r_array:
        :param flux_r:
        :param N:
        :return:
        """
        if linspace is True:
            sigmas = np.linspace(r_array[0], r_array[-1] / 2, N + 2)[1:-1]
        else:
            sigmas = np.logspace(np.log10(r_array[0]), np.log10((r_array[-1] + 0.0000001) / 2.), N + 2)[1:-1]
        # sigmas = np.linspace(r_array[0], r_array[-1]/2, N + 2)[1:-1]

        A = np.zeros((len(flux_r), N))
        for j in np.arange(A.shape[1]):
            A[:, j] = gaussian(r_array, sigmas[j], 1.)
        amplitudes, norm = nnls(A, flux_r)
        return amplitudes, sigmas, norm

    @export
    def de_projection_3d(amplitudes, sigmas):
        """
        de-projects a gaussian (or list of multiple Gaussians from a 2d projected to a 3d profile)
        :param amplitudes:
        :param sigmas:
        :return:
        """
        amplitudes_3d = amplitudes / sigmas / np.sqrt(2*np.pi)
        return amplitudes_3d, sigmas