def decompose(self,l_edges,keep_fourier=False): """ Decomposes the shear map into its E and B modes components and returns the respective power spectral densities at the specified multipole moments :param l_edges: Multipole bin edges :type l_edges: array :param keep_fourier: If set to True, holds the Fourier transforms of the E and B mode maps into the E and B attributes of the ShearMap instance :type keep_fourier: bool. :returns: :returns: tuple -- (l -- array,P_EE,P_BB,P_EB -- arrays) = (multipole moments, EE,BB power spectra and EB cross power) >>> test_map = ShearMap.load("shear.fit",format=load_fits_default_shear) >>> l_edges = np.arange(300.0,5000.0,200.0) >>> l,EE,BB,EB = test_map.decompose(l_edges) """ #Perform Fourier transforms ft_data1 = rfft2(self.data[0]) ft_data2 = rfft2(self.data[1]) #Compute frequencies lx = rfftfreq(ft_data1.shape[0]) ly = fftfreq(ft_data1.shape[0]) #Safety check assert len(lx)==ft_data1.shape[1] assert len(ly)==ft_data1.shape[0] #Compute sines and cosines of rotation angles l_squared = lx[np.newaxis,:]**2 + ly[:,np.newaxis]**2 l_squared[0,0] = 1.0 sin_2_phi = 2.0 * lx[np.newaxis,:] * ly[:,np.newaxis] / l_squared cos_2_phi = (lx[np.newaxis,:]**2 - ly[:,np.newaxis]**2) / l_squared #Compute E and B components ft_E = cos_2_phi * ft_data1 + sin_2_phi * ft_data2 ft_B = -1.0 * sin_2_phi * ft_data1 + cos_2_phi * ft_data2 ft_E[0,0] = 0.0 ft_B[0,0] = 0.0 assert ft_E.shape == ft_B.shape assert ft_E.shape == ft_data1.shape #Compute and return power spectra l = 0.5*(l_edges[:-1] + l_edges[1:]) P_EE = _topology.rfft2_azimuthal(ft_E,ft_E,self.side_angle.to(deg).value,l_edges) P_BB = _topology.rfft2_azimuthal(ft_B,ft_B,self.side_angle.to(deg).value,l_edges) P_EB = _topology.rfft2_azimuthal(ft_E,ft_B,self.side_angle.to(deg).value,l_edges) if keep_fourier: self.fourier_E = ft_E self.fourier_B = ft_B return l,P_EE,P_BB,P_EB
def powerSpectrum(self, l_edges): """ Measures the power spectrum of the convergence map at the multipole moments specified in the input :param l_edges: Multipole bin edges :type l_edges: array :returns: tuple -- (l -- array,Pl -- array) = (multipole moments, power spectrum at multipole moments) :raises: AssertionError if l_edges are not provided >>> test_map = ConvergenceMap.load("map.fit") >>> l_edges = np.arange(200.0,5000.0,200.0) >>> l,Pl = test_map.powerSpectrum(l_edges) """ assert not self._masked, "Power spectrum calculation for masked maps is not allowed yet!" assert l_edges is not None if self.side_angle.unit.physical_type == "length": raise NotImplementedError( "Power spectrum measurement not implemented yet if side physical unit is length!" ) l = 0.5 * (l_edges[:-1] + l_edges[1:]) #Calculate the Fourier transform of the map with numpy FFT ft_map = rfft2(self.data) #Compute the power spectrum with the C backend implementation power_spectrum = _topology.rfft2_azimuthal( ft_map, ft_map, self.side_angle.to(deg).value, l_edges) #Output the power spectrum return l, power_spectrum
def decompose(self, l_edges, keep_fourier=False): """ Decomposes the shear map into its E and B modes components and returns the respective power spectral densities at the specified multipole moments :param l_edges: Multipole bin edges :type l_edges: array :param keep_fourier: If set to True, holds the Fourier transforms of the E and B mode maps into the E and B attributes of the ShearMap instance :type keep_fourier: bool. :returns: :returns: tuple -- (l -- array,P_EE,P_BB,P_EB -- arrays) = (multipole moments, EE,BB power spectra and EB cross power) >>> test_map = ShearMap.load("shear.fit",format=load_fits_default_shear) >>> l_edges = np.arange(300.0,5000.0,200.0) >>> l,EE,BB,EB = test_map.decompose(l_edges) """ #Perform Fourier transforms ft_data1 = rfft2(self.data[0]) ft_data2 = rfft2(self.data[1]) #Compute frequencies lx = rfftfreq(ft_data1.shape[0]) ly = fftfreq(ft_data1.shape[0]) #Safety check assert len(lx) == ft_data1.shape[1] assert len(ly) == ft_data1.shape[0] #Compute sines and cosines of rotation angles l_squared = lx[np.newaxis, :]**2 + ly[:, np.newaxis]**2 l_squared[0, 0] = 1.0 sin_2_phi = 2.0 * lx[np.newaxis, :] * ly[:, np.newaxis] / l_squared cos_2_phi = (lx[np.newaxis, :]**2 - ly[:, np.newaxis]**2) / l_squared #Compute E and B components ft_E = cos_2_phi * ft_data1 + sin_2_phi * ft_data2 ft_B = -1.0 * sin_2_phi * ft_data1 + cos_2_phi * ft_data2 ft_E[0, 0] = 0.0 ft_B[0, 0] = 0.0 assert ft_E.shape == ft_B.shape assert ft_E.shape == ft_data1.shape #Compute and return power spectra l = 0.5 * (l_edges[:-1] + l_edges[1:]) P_EE = _topology.rfft2_azimuthal(ft_E, ft_E, self.side_angle.to(deg).value, l_edges) P_BB = _topology.rfft2_azimuthal(ft_B, ft_B, self.side_angle.to(deg).value, l_edges) P_EB = _topology.rfft2_azimuthal(ft_E, ft_B, self.side_angle.to(deg).value, l_edges) if keep_fourier: self.fourier_E = ft_E self.fourier_B = ft_B return l, P_EE, P_BB, P_EB
def cross(self, other, statistic="power_spectrum", **kwargs): """ Measures a cross statistic between maps :param other: The other convergence map :type other: ConvergenceMap instance :param statistic: the cross statistic to measure (default is 'power_spectrum') :type statistic: string or callable :param kwargs: the keyword arguments are passed to the statistic (when callable) :type kwargs: dict. :returns: tuple -- (l -- array,Pl -- array) = (multipole moments, cross power spectrum at multipole moments) if the statistic is the power spectrum, otherwise whatever statistic() returns on call :raises: AssertionError if the other map has not the same shape as the input one >>> test_map = ConvergenceMap.load("map.fit",format=load_fits_default_convergence) >>> other_map = ConvergenceMap.load("map2.fit",format=load_fits_default_convergence) >>> l_edges = np.arange(200.0,5000.0,200.0) >>> l,Pl = test_map.cross(other_map,l_edges=l_edges) """ #The other map must be of the same type as this one assert isinstance(other, self.__class__) if statistic == "power_spectrum": assert not ( self._masked or other._masked ), "Power spectrum calculation for masked maps is not allowed yet!" if self.side_angle.unit.physical_type == "length": raise NotImplementedError( "Power spectrum measurement not implemented yet if side physical unit is length!" ) assert "l_edges" in kwargs.keys() l_edges = kwargs["l_edges"] assert l_edges is not None l = 0.5 * (l_edges[:-1] + l_edges[1:]) assert self.side_angle == other.side_angle assert self.data.shape == other.data.shape #Calculate the Fourier transform of the maps with numpy FFTs ft_map1 = rfft2(self.data) ft_map2 = rfft2(other.data) #Compute the cross power spectrum with the C backend implementation cross_power_spectrum = _topology.rfft2_azimuthal( ft_map1, ft_map2, self.side_angle.to(deg).value, l_edges) #Output the cross power spectrum return l, cross_power_spectrum else: return statistic(self, other, **kwargs)