<commit_before># Licensed under an MIT open source license - see LICENSE


import numpy as np
from numpy.fft import fft2, fftshift
import astropy.units as u
from warnings import warn

from ..base_pspec2 import StatisticBase_PSpec2D
from ..base_statistic import BaseStatisticMixIn
from ...io import input_data, common_types, twod_types
from ..fitting_utils import check_fit_limits


class MVC(BaseStatisticMixIn, StatisticBase_PSpec2D):

    """
    Implementation of Modified Velocity Centroids (Lazarian & Esquivel, 03)

    Parameters
    ----------
    centroid : %(dtypes)s
        Normalized first moment array.
    moment0 : %(dtypes)s
        Moment 0 array.
    linewidth : %(dtypes)s
        Normalized second moment array
    header : FITS header
        Header of any of the arrays. Used only to get the
        spatial scale.
    """

    __doc__ %= {"dtypes": " or ".join(common_types + twod_types)}

    def __init__(self, centroid, moment0, linewidth, header=None):

        # data property not used here
        self.no_data_flag = True
        self.data = None

        if header is None:
            try:
                self._centroid, self.header = input_data(centroid,
                                                         no_header=False)
            except TypeError:
                warn("Could not load header from centroid. No header has been"
                     " specified.")
                self._centroid = input_data(centroid, no_header=True)

        else:
            self._centroid = input_data(centroid, no_header=True)
            self.header = header

        self._moment0 = input_data(moment0, no_header=True)
        self._linewidth = input_data(linewidth, no_header=True)

        # Get rid of nans.
        self._centroid[np.isnan(self.centroid)] = np.nanmin(self.centroid)
        self._moment0[np.isnan(self.moment0)] = np.nanmin(self.moment0)
        self._linewidth[np.isnan(self.linewidth)] = np.nanmin(self.linewidth)

        shape_check1 = self.centroid.shape == self.moment0.shape
        shape_check2 = self.centroid.shape == self.linewidth.shape
        if not shape_check1 or not shape_check2:
            raise IndexError("The centroid, moment0, and linewidth arrays must"
                             "have the same shape.")

        self.shape = self.centroid.shape

        self._ps1D_stddev = None

    @property
    def centroid(self):
        '''
        Normalized centroid array.
        '''
        return self._centroid

    @property
    def moment0(self):
        '''
        Zeroth moment (integrated intensity) array.
        '''
        return self._moment0

    @property
    def linewidth(self):
        '''
        Linewidth array. Square root of the velocity dispersion.
        '''
        return self._linewidth

    def compute_pspec(self):
        '''
        Compute the 2D power spectrum.

        The quantity calculated here is the same as Equation 3 in Lazarian &
        Esquivel (2003), but the inputted arrays are not in the same form as
        described. We can, however, adjust for the use of normalized Centroids
        and the linewidth.

        An unnormalized centroid can be constructed by multiplying the centroid
        array by the moment0. Velocity dispersion is the square of the
        linewidth subtracted by the square of the normalized centroid.
        '''

        term1 = fft2(self.centroid * self.moment0)

        # Account for normalization in the line width.
        term2 = np.nanmean(self.linewidth**2 + self.centroid**2)

        mvc_fft = term1 - term2 * fft2(self.moment0)

        # Shift to the center
        mvc_fft = fftshift(mvc_fft)

        self._ps2D = np.abs(mvc_fft) ** 2.

    def run(self, verbose=False, save_name=None, logspacing=True,
            return_stddev=True, low_cut=None, high_cut=0.5,
            ang_units=False, unit=u.deg, use_wavenumber=False, **kwargs):
        '''
        Full computation of MVC. For fitting parameters and radial binning
        options, see `~turbustat.statistics.base_pspec2.StatisticBase_PSpec2D`.

        Parameters
        ----------
        verbose: bool, optional
            Enables plotting.
        save_name : str,optional
            Save the figure when a file name is given.
        logspacing : bool, optional
            Return logarithmically spaced bins for the lags.
        return_stddev : bool, optional
            Return the standard deviation in the 1D bins.
        low_cut : float, optional
            Low frequency cut off in frequencies used in the fitting.
        high_cut : float, optional
            High frequency cut off in frequencies used in the fitting.
        ang_units : bool, optional
            Convert frequencies to angular units using the given header.
        unit : u.Unit, optional
            Choose the angular unit to convert to when ang_units is enabled.<commit_msg>Disable logspacing by default in MVC to match all others<commit_after># Licensed under an MIT open source license - see LICENSE


import numpy as np
from numpy.fft import fft2, fftshift
import astropy.units as u
from warnings import warn

from ..base_pspec2 import StatisticBase_PSpec2D
from ..base_statistic import BaseStatisticMixIn
from ...io import input_data, common_types, twod_types
from ..fitting_utils import check_fit_limits


class MVC(BaseStatisticMixIn, StatisticBase_PSpec2D):

    """
    Implementation of Modified Velocity Centroids (Lazarian & Esquivel, 03)

    Parameters
    ----------
    centroid : %(dtypes)s
        Normalized first moment array.
    moment0 : %(dtypes)s
        Moment 0 array.
    linewidth : %(dtypes)s
        Normalized second moment array
    header : FITS header
        Header of any of the arrays. Used only to get the
        spatial scale.
    """

    __doc__ %= {"dtypes": " or ".join(common_types + twod_types)}

    def __init__(self, centroid, moment0, linewidth, header=None):

        # data property not used here
        self.no_data_flag = True
        self.data = None

        if header is None:
            try:
                self._centroid, self.header = input_data(centroid,
                                                         no_header=False)
            except TypeError:
                warn("Could not load header from centroid. No header has been"
                     " specified.")
                self._centroid = input_data(centroid, no_header=True)

        else:
            self._centroid = input_data(centroid, no_header=True)
            self.header = header

        self._moment0 = input_data(moment0, no_header=True)
        self._linewidth = input_data(linewidth, no_header=True)

        # Get rid of nans.
        self._centroid[np.isnan(self.centroid)] = np.nanmin(self.centroid)
        self._moment0[np.isnan(self.moment0)] = np.nanmin(self.moment0)
        self._linewidth[np.isnan(self.linewidth)] = np.nanmin(self.linewidth)

        shape_check1 = self.centroid.shape == self.moment0.shape
        shape_check2 = self.centroid.shape == self.linewidth.shape
        if not shape_check1 or not shape_check2:
            raise IndexError("The centroid, moment0, and linewidth arrays must"
                             "have the same shape.")

        self.shape = self.centroid.shape

        self._ps1D_stddev = None

    @property
    def centroid(self):
        '''
        Normalized centroid array.
        '''
        return self._centroid

    @property
    def moment0(self):
        '''
        Zeroth moment (integrated intensity) array.
        '''
        return self._moment0

    @property
    def linewidth(self):
        '''
        Linewidth array. Square root of the velocity dispersion.
        '''
        return self._linewidth

    def compute_pspec(self):
        '''
        Compute the 2D power spectrum.

        The quantity calculated here is the same as Equation 3 in Lazarian &
        Esquivel (2003), but the inputted arrays are not in the same form as
        described. We can, however, adjust for the use of normalized Centroids
        and the linewidth.

        An unnormalized centroid can be constructed by multiplying the centroid
        array by the moment0. Velocity dispersion is the square of the
        linewidth subtracted by the square of the normalized centroid.
        '''

        term1 = fft2(self.centroid * self.moment0)

        # Account for normalization in the line width.
        term2 = np.nanmean(self.linewidth**2 + self.centroid**2)

        mvc_fft = term1 - term2 * fft2(self.moment0)

        # Shift to the center
        mvc_fft = fftshift(mvc_fft)

        self._ps2D = np.abs(mvc_fft) ** 2.

    def run(self, verbose=False, save_name=None, logspacing=False,
            return_stddev=True, low_cut=None, high_cut=0.5,
            ang_units=False, unit=u.deg, use_wavenumber=False, **kwargs):
        '''
        Full computation of MVC. For fitting parameters and radial binning
        options, see `~turbustat.statistics.base_pspec2.StatisticBase_PSpec2D`.

        Parameters
        ----------
        verbose: bool, optional
            Enables plotting.
        save_name : str,optional
            Save the figure when a file name is given.
        logspacing : bool, optional
            Return logarithmically spaced bins for the lags.
        return_stddev : bool, optional
            Return the standard deviation in the 1D bins.
        low_cut : float, optional
            Low frequency cut off in frequencies used in the fitting.
        high_cut : float, optional
            High frequency cut off in frequencies used in the fitting.
        ang_units : bool, optional
            Convert frequencies to angular units using the given header.
        unit : u.Unit, optional
            Choose the angular unit to convert to when ang_units is enabled.
{'fraction_non_alphanumeric': 0.07501524700142305, 'fraction_numerical': 0.00955478755844684, 'mean_word_length': 2.153525641025641, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7464163', 'n_tokens_mistral': 2782, 'n_tokens_neox': 2647, 'n_words': 874}