Example #1
0
def healpix_interp_along_axis(indata, theta_phi=None, inloc_axis=None,
                              outloc_axis=None, axis=-1, kind='linear',
                              bounds_error=True, fill_value=NP.nan,
                              assume_sorted=False, nest=False):

    """
    -----------------------------------------------------------------------------
    Interpolate healpix data to specified angular locations (HEALPIX 
    interpolation) and along one other specified axis (usually frequency axis, 
    for instance) via SciPy interpolation. Wraps HEALPIX and SciPy interpolations
    into one routine.

    Inputs:

    indata      [numpy array] input data to be interpolated. Must be of shape 
                (nhpy x nax1 x nax2 x ...). Currently works only for 
                (nhpy x nax1). nhpy is a HEALPIX compatible npix

    theta_phi   [numpy array] spherical angle locations (in radians) at which
                the healpix data is to be interpolated to at each of the other 
                given axes. It must be of size nang x 2 where nang is the number 
                of spherical angle locations, 2 denotes theta and phi. If set to
                None (default), no healpix interpolation is performed

    inloc_axis  [numpy array] locations along the axis specified in axis (to be 
                interpolated with SciPy) in which indata is specified. It 
                should be of size nax1, nax2, ... or naxm. Currently it works 
                only if set to nax1

    outloc_axis [numpy array] locations along the axis specified in axis to be 
                interpolated to with SciPy. The axis over which this 
                interpolation is to be done is specified in axis. It must be of
                size nout. If this is set exactly equal to inloc_axis, no 
                interpolation along this axis is performed

    axis        [integer] axis along which SciPy interpolation is to be done. 
                If set to -1 (default), the interpolation happens over the last
                axis. Since the first axis of indata is reserved for the healpix
                pixels, axis must be set to 1 or above (upto indata.ndim-1).

    kind        [str or int] Specifies the kind of interpolation as a 
                string ('linear', 'nearest', 'zero', 'slinear', 'quadratic', 
                'cubic' where 'slinear', 'quadratic' and 'cubic' refer to a 
                spline interpolation of first, second or third order) or as an 
                integer specifying the order of the spline interpolator to use. 
                Default is 'linear'.

    bounds_error 
                [bool, optional] If True, a ValueError is raised any time 
                interpolation is attempted on a value outside of the range of x 
                (where extrapolation is necessary). If False, out of bounds 
                values are assigned fill_value. By default, an error is raised.

    fill_value  [float] If provided, then this value will be used to fill in 
                for requested points outside of the data range. If not provided, 
                then the default is NaN.

    assume_sorted 
                [bool] If False, values of inloc_axis can be in any order and 
                they are sorted first. If True, inloc_axis has to be an array 
                of monotonically increasing values.
    
    nest        [bool] if True, the is assumed to be in NESTED ordering.

    Outputs:

    HEALPIX interpolated and SciPy interpolated output. Will be of size
    nang x ... x nout x ... x naxm. Currently returns an array of shape 
    nang x nout
    -----------------------------------------------------------------------------
    """

    try:
        indata
    except NameError:
        raise NameError('input data not specified')

    if not isinstance(indata, NP.ndarray):
        raise TypeError('input data must be a numpy array')

    if theta_phi is not None:
        if not isinstance(theta_phi, NP.ndarray):
            raise TypeError('output locations must be a numpy array')

        if theta_phi.ndim != 2:
            raise ValueError('Output locations must be a 2D array')

    if axis == -1:
        axis = indata.ndim - 1

    if (axis < 1) or (axis >= indata.ndim):
        raise ValueError('input axis out of range')

    if theta_phi is not None:
        intermediate_data_shape = list(indata.shape)
        intermediate_data_shape[0] = theta_phi.shape[0]
        intermediate_data_shape = tuple(intermediate_data_shape)
        
        intermediate_data = NP.zeros(intermediate_data_shape, dtype=NP.float64)
        for ax in range(1,indata.ndim):
            for i in xrange(indata.shape[ax]):
                intermediate_data[:,i] = HP.get_interp_val(indata[:,i], theta_phi[:,0], theta_phi[:,1], nest=nest)
    else:
        intermediate_data = NP.copy(indata)

    if outloc_axis is not None:
        if inloc_axis is not None:
            outloc_axis = outloc_axis.flatten()
            inloc_axis = inloc_axis.flatten()
            eps = 1e-8
            if (outloc_axis.size == inloc_axis.size) and (NP.abs(inloc_axis-outloc_axis).max() <= eps):
                outdata = intermediate_data
            else:
                if kind == 'fft':
                    df_inp = NP.mean(NP.diff(inloc_axis))
                    df_out = NP.mean(NP.diff(outloc_axis))
                    ntau = df_inp / df_out * inloc_axis.size
                    ntau = NP.round(ntau).astype(int)
                    tau_inp = DSP.spectral_axis(inloc_axis.size, delx=df_inp, shift=True)
                    fftinp = NP.fft.fft(intermediate_data, axis=axis)
                    fftinp_shifted = NP.fft.fftshift(fftinp, axes=axis)
                    if fftinp.size % 2 == 0:
                        fftinp_shifted[:,0] = 0.0 # Blank out the N/2 element (0 element when FFT-shifted) for conjugate symmetry
                    npad = ntau - inloc_axis.size
                    if npad % 2 == 0:
                        npad_before = npad/2
                        npad_after = npad/2
                    else:
                        npad_before = npad/2 + 1
                        npad_after = npad/2

                    fftinp_shifted_padded = NP.pad(fftinp_shifted, [(0,0), (npad_before, npad_after)], mode='constant')
                    fftinp_padded = NP.fft.ifftshift(fftinp_shifted_padded, axes=axis)
                    ifftout = NP.fft.ifft(fftinp_padded, axis=axis) * (1.0 * ntau / inloc_axis.size)
                    eps_imag = 1e-10
                    if NP.any(NP.abs(ifftout.imag) > eps_imag):
                        raise ValueError('Significant imaginary component has been introduced unintentionally during the FFT based interpolation. Debug the code.')
                    else:
                        ifftout = ifftout.real
                    fout = DSP.spectral_axis(ntau, delx=tau_inp[1]-tau_inp[0], shift=True)
                    fout -= fout.min()
                    fout += inloc_axis.min() 
                    ind_outloc, ind_fout, dfreq = LKP.find_1NN(fout.reshape(-1,1), outloc_axis.reshape(-1,1), distance_ULIM=0.5*(fout[1]-fout[0]), remove_oob=True)
                    outdata = ifftout[:,ind_fout]
                    
                    # npad = 2 * (outloc_axis.size - inloc_axis.size)
                    # dt_inp = DSP.spectral_axis(2*inloc_axis.size, delx=inloc_axis[1]-inloc_axis[0], shift=True)
                    # dt_out = DSP.spectral_axis(2*outloc_axis.size, delx=outloc_axis[1]-outloc_axis[0], shift=True)
                    # fftinp = NP.fft.fft(NP.pad(intermediate_data, [(0,0), (0,inloc_axis.size)], mode='constant'), axis=axis) * (1.0 * outloc_axis.size / inloc_axis.size)
                    # fftinp = NP.fft.fftshift(fftinp, axes=axis)
                    # fftinp[0,0] = 0.0  # Blank out the N/2 element for conjugate symmetry
                    # fftout = NP.pad(fftinp, [(0,0), (npad/2, npad/2)], mode='constant')
                    # fftout = NP.fft.ifftshift(fftout, axes=axis)
                    # outdata = NP.fft.ifft(fftout, axis=axis)
                    # outdata = outdata[0,:outloc_axis.size]
                else:
                    interp_func = interpolate.interp1d(inloc_axis, intermediate_data, axis=axis, kind=kind, bounds_error=bounds_error, fill_value=fill_value, assume_sorted=assume_sorted)
                    outdata = interp_func(outloc_axis)
        else:
            raise ValueError('input inloc_axis not specified')
    else:
        outdata = intermediate_data

    return outdata
Example #2
0
def healpix_interp_along_axis(indata, theta_phi=None, inloc_axis=None,
                              outloc_axis=None, axis=-1, kind='linear',
                              bounds_error=True, fill_value=NP.nan,
                              assume_sorted=False, nest=False):

    """
    -----------------------------------------------------------------------------
    Interpolate healpix data to specified angular locations (HEALPIX 
    interpolation) and along one other specified axis (usually frequency axis, 
    for instance) via SciPy interpolation. Wraps HEALPIX and SciPy interpolations
    into one routine.

    Inputs:

    indata      [numpy array] input data to be interpolated. Must be of shape 
                (nhpy x nax1 x nax2 x ...). Currently works only for 
                (nhpy x nax1). nhpy is a HEALPIX compatible npix

    theta_phi   [numpy array] spherical angle locations (in radians) at which
                the healpix data is to be interpolated to at each of the other 
                given axes. It must be of size nang x 2 where nang is the number 
                of spherical angle locations, 2 denotes theta and phi. If set to
                None (default), no healpix interpolation is performed

    inloc_axis  [numpy array] locations along the axis specified in axis (to be 
                interpolated with SciPy) in which indata is specified. It 
                should be of size nax1, nax2, ... or naxm. Currently it works 
                only if set to nax1

    outloc_axis [numpy array] locations along the axis specified in axis to be 
                interpolated to with SciPy. The axis over which this 
                interpolation is to be done is specified in axis. It must be of
                size nout. If this is set exactly equal to inloc_axis, no 
                interpolation along this axis is performed

    axis        [integer] axis along which SciPy interpolation is to be done. 
                If set to -1 (default), the interpolation happens over the last
                axis. Since the first axis of indata is reserved for the healpix
                pixels, axis must be set to 1 or above (upto indata.ndim-1).

    kind        [str or int] Specifies the kind of interpolation as a 
                string ('linear', 'nearest', 'zero', 'slinear', 'quadratic', 
                'cubic' where 'slinear', 'quadratic' and 'cubic' refer to a 
                spline interpolation of first, second or third order) or as an 
                integer specifying the order of the spline interpolator to use. 
                Default is 'linear'.

    bounds_error 
                [bool, optional] If True, a ValueError is raised any time 
                interpolation is attempted on a value outside of the range of x 
                (where extrapolation is necessary). If False, out of bounds 
                values are assigned fill_value. By default, an error is raised.

    fill_value  [float] If provided, then this value will be used to fill in 
                for requested points outside of the data range. If not provided, 
                then the default is NaN.

    assume_sorted 
                [bool] If False, values of x can be in any order and they are 
                sorted first. If True, x has to be an array of monotonically 
                increasing values.
    
    nest        [bool] if True, the is assumed to be in NESTED ordering.

    Outputs:

    HEALPIX interpolated and SciPy interpolated output. Will be of size
    nang x ... x nout x ... x naxm. Currently returns an array of shape 
    nang x nout
    
    -----------------------------------------------------------------------------
    """

    try:
        indata
    except NameError:
        raise NameError('input data not specified')

    if not isinstance(indata, NP.ndarray):
        raise TypeError('input data must be a numpy array')

    if theta_phi is not None:
        if not isinstance(theta_phi, NP.ndarray):
            raise TypeError('output locations must be a numpy array')

        if theta_phi.ndim != 2:
            raise ValueError('Output locations must be a 2D array')

    if axis == -1:
        axis = indata.ndim - 1

    if (axis < 1) or (axis >= indata.ndim):
        raise ValueError('input axis out of range')

    if theta_phi is not None:
        intermediate_data_shape = list(indata.shape)
        intermediate_data_shape[0] = theta_phi.shape[0]
        intermediate_data_shape = tuple(intermediate_data_shape)
        
        intermediate_data = NP.zeros(intermediate_data_shape, dtype=NP.float32)
        for ax in range(1,indata.ndim):
            for i in xrange(indata.shape[ax]):
                intermediate_data[:,i] = HP.get_interp_val(indata[:,i], theta_phi[:,0], theta_phi[:,1], nest=nest)
    else:
        intermediate_data = NP.copy(indata)

    if outloc_axis is not None:
        if inloc_axis is not None:
            outloc_axis = outloc_axis.flatten()
            inloc_axis = inloc_axis.flatten()
            eps = 1e-8
            if (outloc_axis.size == inloc_axis.size) and (NP.abs(inloc_axis-outloc_axis).max() <= eps):
                outdata = intermediate_data
            else:
                if kind == 'fft':
                    df_inp = NP.mean(NP.diff(inloc_axis))
                    df_out = NP.mean(NP.diff(outloc_axis))
                    ntau = df_inp / df_out * inloc_axis.size
                    ntau = NP.round(ntau).astype(int)
                    tau_inp = DSP.spectral_axis(inloc_axis.size, delx=df_inp, shift=True)
                    fftinp = NP.fft.fft(intermediate_data, axis=axis)
                    fftinp_shifted = NP.fft.fftshift(fftinp, axes=axis)
                    if fftinp.size % 2 == 0:
                        fftinp_shifted[:,0] = 0.0 # Blank out the N/2 element (0 element when FFT-shifted) for conjugate symmetry
                    npad = ntau - inloc_axis.size
                    if npad % 2 == 0:
                        npad_before = npad/2
                        npad_after = npad/2
                    else:
                        npad_before = npad/2 + 1
                        npad_after = npad/2

                    fftinp_shifted_padded = NP.pad(fftinp_shifted, [(0,0), (npad_before, npad_after)], mode='constant')
                    fftinp_padded = NP.fft.ifftshift(fftinp_shifted_padded, axes=axis)
                    ifftout = NP.fft.ifft(fftinp_padded, axis=axis) * (1.0 * ntau / inloc_axis.size)
                    eps_imag = 1e-10
                    if NP.any(NP.abs(ifftout.imag) > eps_imag):
                        raise ValueError('Significant imaginary component has been introduced unintentionally during the FFT based interpolation. Debug the code.')
                    else:
                        ifftout = ifftout.real
                    fout = DSP.spectral_axis(ntau, delx=tau_inp[1]-tau_inp[0], shift=True)
                    fout -= fout.min()
                    fout += inloc_axis.min() 
                    ind_outloc, ind_fout, dfreq = LKP.find_1NN(fout.reshape(-1,1), outloc_axis.reshape(-1,1), distance_ULIM=0.5*(fout[1]-fout[0]), remove_oob=True)
                    outdata = ifftout[:,ind_fout]
                    
                    # npad = 2 * (outloc_axis.size - inloc_axis.size)
                    # dt_inp = DSP.spectral_axis(2*inloc_axis.size, delx=inloc_axis[1]-inloc_axis[0], shift=True)
                    # dt_out = DSP.spectral_axis(2*outloc_axis.size, delx=outloc_axis[1]-outloc_axis[0], shift=True)
                    # fftinp = NP.fft.fft(NP.pad(intermediate_data, [(0,0), (0,inloc_axis.size)], mode='constant'), axis=axis) * (1.0 * outloc_axis.size / inloc_axis.size)
                    # fftinp = NP.fft.fftshift(fftinp, axes=axis)
                    # fftinp[0,0] = 0.0  # Blank out the N/2 element for conjugate symmetry
                    # fftout = NP.pad(fftinp, [(0,0), (npad/2, npad/2)], mode='constant')
                    # fftout = NP.fft.ifftshift(fftout, axes=axis)
                    # outdata = NP.fft.ifft(fftout, axis=axis)
                    # outdata = outdata[0,:outloc_axis.size]
                else:
                    interp_func = interpolate.interp1d(inloc_axis, intermediate_data, axis=axis, kind=kind, bounds_error=bounds_error, fill_value=fill_value, assume_sorted=assume_sorted)
                    outdata = interp_func(outloc_axis)
        else:
            raise ValueError('input inloc_axis not specified')
    else:
        outdata = intermediate_data

    return outdata
Example #3
0
    def generate_spectrum(self, frequency=None):

        """
        -------------------------------------------------------------------------
        Generate and return a spectrum from functional spectral parameters

        Inputs:

        frequency  [scalar or numpy array] Frequencies at which the spectrum at
                   all object locations is to be created. Must be in same units
                   as the attribute frequency and values under key 'freq-ref' 
                   of attribute spec_parms. If not provided (default=None), a 
                   spectrum is generated for all the frequencies specified in 
                   the attribute frequency and values under keys 'freq-ref' and
                   'z-width' of attribute spec_parms. 

        Outputs:

        spectrum   [numpy array] Spectrum of the sky model at the respective
                   sky locations. Has shape nobj x nfreq.

        Power law calculation uses the convention, 
        spectrum = flux_offset + flux_scale * (freq/freq0)**spindex

        Monotone places a delta function at the frequency channel closest to the
        reference frequency if it lies inside the frequency range, otherwise
        a zero spectrum is assigned. 
        Thus spectrum = flux_scale * delta(freq-freq0)

        Random (currently only gaussian) places random fluxes in the spectrum
        spectrum = flux_offset + flux_scale * random_normal(freq.size)

        tanh spectrum is defined as (Bowman & Rogers 2010):
        spectrum = flux_scale * sqrt((1+z)/10) * 0.5 * [tanh((z-zr)/dz) + 1]
        where, flux_scale is typically 0.027 K, zr = reionization redshift 
        when x_i = 0.5, and dz = redshift width (dz ~ 1)

        If the attribute spec_type is 'spectrum' the attribute spectrum is 
        returned without any modifications.
        -------------------------------------------------------------------------
        """

        if self.spec_type == 'func':
            if frequency is not None:
                if isinstance(frequency, (int,float,NP.ndarray)):
                    frequency = NP.asarray(frequency)
                else:
                    raise ValueError('Input parameter frequency must be a scalar or a numpy array')

                if NP.any(frequency <= 0.0):
                    raise ValueError('Input parameter frequency must contain positive values')
            else:
                frequency = NP.copy(self.frequency)

            spectrum = NP.empty((self.location.shape[0], frequency.size))
            spectrum.fill(NP.nan)

            uniq_names, invind = NP.unique(self.spec_parms['name'], return_inverse=True)
            if len(uniq_names) > 1:
                counts, edges, bnum, ri = OPS.binned_statistic(invind, statistic='count', bins=range(len(uniq_names)))
            else:
                counts = len(invind)
                ri = range(counts)

            for i, name in enumerate(uniq_names):
                if len(uniq_names) > 1:
                    indices = ri[ri[i]:ri[i+1]]
                else:
                    indices = ri

                if name == 'random':
                    spectrum[indices,:] = self.spec_parms['flux-offset'][indices].reshape(-1,1) + self.spec_parms['flux-scale'][indices].reshape(-1,1) * NP.random.randn(counts[i], frequency.size)
                if name == 'monotone':  # Needs serious testing
                    spectrum[indices,:] = 0.0
                    inpind, refind, dNN = LKP.find_1NN(frequency, self.spec_parms['freq-ref'][indices], distance=frequency[1]-frequency[0], remove_oob=True) 
                    ind = indices[inpind]
                    ind2d = zip(ind, refind)
                    spectrum[zip(*ind2d)] = self.spec_parms['flux-scale'][ind]
                if name == 'power-law':
                    spectrum[indices,:] = self.spec_parms['flux-offset'][indices].reshape(-1,1) + self.spec_parms['flux-scale'][indices].reshape(-1,1) * (frequency.reshape(1,-1)/self.spec_parms['freq-ref'][indices].reshape(-1,1))**self.spec_parms['power-law-index'][indices].reshape(-1,1)
                if name == 'tanh':
                    z = CNST.rest_freq_HI/frequency.reshape(1,-1) - 1
                    zr = CNST.rest_freq_HI/self.spec_parms['freq-ref'][indices].reshape(-1,1) - 1
                    dz = self.spec_parms['z-width'][indices].reshape(-1,1)

                    amp = self.spec_parms['flux-scale'][indices].reshape(-1,1) * NP.sqrt((1+z)/10)
                    xh = 0.5 * (NP.tanh((z-zr)/dz) + 1)
                    spectrum[indices,:] = amp * xh
                    
            return spectrum
        else:
            return self.spectrum