def test_spherical_quadrature(): """ Testing spherical quadrature rule versus numerical integration. """ b = 8 # 10 # Create grids on the sphere x_gl = S2.meshgrid(b=b, grid_type='Gauss-Legendre') x_cc = S2.meshgrid(b=b, grid_type='Clenshaw-Curtis') x_soft = S2.meshgrid(b=b, grid_type='SOFT') x_gl = np.c_[x_gl[0][..., None], x_gl[1][..., None]] x_cc = np.c_[x_cc[0][..., None], x_cc[1][..., None]] x_soft = np.c_[x_soft[0][..., None], x_soft[1][..., None]] # Compute quadrature weights w_gl = S2.quadrature_weights(b=b, grid_type='Gauss-Legendre') w_cc = S2.quadrature_weights(b=b, grid_type='Clenshaw-Curtis') w_soft = S2.quadrature_weights(b=b, grid_type='SOFT') # Define a polynomial function, to be evaluated at one point or at an array of points def f1a(xs): xc = S2.change_coordinates(coords=xs, p_from='S', p_to='C') return xc[..., 0]**2 * xc[..., 1] - 1.4 * xc[..., 2] * xc[ ..., 1]**3 + xc[..., 1] - xc[..., 2]**2 + 2. def f1(theta, phi): xs = np.array([theta, phi]) return f1a(xs) # Obtain the "true" value of the integral of the function over the sphere, using scipy's numerical integration # routines i1 = S2.integrate(f1, normalize=False) # Compute the integral using the quadrature formulae # i1_gl_w = (w_gl * f1a(x_gl)).sum() i1_gl_w = S2.integrate_quad(f1a(x_gl), grid_type='Gauss-Legendre', normalize=False, w=w_gl) print(i1_gl_w, i1, 'diff:', np.abs(i1_gl_w - i1)) assert np.isclose(np.abs(i1_gl_w - i1), 0.0) # i1_cc_w = (w_cc * f1a(x_cc)).sum() i1_cc_w = S2.integrate_quad(f1a(x_cc), grid_type='Clenshaw-Curtis', normalize=False, w=w_cc) print(i1_cc_w, i1, 'diff:', np.abs(i1_cc_w - i1)) assert np.isclose(np.abs(i1_cc_w - i1), 0.0) i1_soft_w = (w_soft * f1a(x_soft)).sum() print(i1_soft_w, i1, 'diff:', np.abs(i1_soft_w - i1)) print(i1_soft_w) print(i1)
def test_S2FFT_NFFT(): """ Testing S2FFT NFFT """ b = 8 convention = 'Gauss-Legendre' #convention = 'Clenshaw-Curtis' x = S2.meshgrid(b=b, grid_type=convention) print(x[0].shape, x[1].shape) x = np.c_[x[0][..., None], x[1][..., None]]#.reshape(-1, 2) print(x.shape) x = x.reshape(-1, 2) w = S2.quadrature_weights(b=b, grid_type=convention).flatten() F = S2FFT_NFFT(L_max=b, x=x, w=w) for l in range(0, b): for m in range(-l, l + 1): #l = b; m = b f = sh(l, m, x[..., 0], x[..., 1], field='real', normalization='quantum', condon_shortley=True) #f2 = np.random.randn(*f.shape) print(f) f_hat = F.analyze(f) print(np.round(f_hat, 3)) f_reconst = F.synthesize(f_hat) #print np.round(f, 3) print(np.round(f_reconst, 3)) #print np.round(f/f_reconst, 3) print(np.abs(f-f_reconst).sum()) assert np.isclose(np.abs(f-f_reconst).sum(), 0.) print(np.round(f_hat, 3)) assert np.isclose(f_hat[l ** 2 + l + m], 1.) #assert False
def __init__(self, L_max, grid_type='Gauss-Legendre', field='real', normalization='quantum', condon_shortley='cs'): super().__init__() self.b = L_max + 1 # Compute a grid of spatial sampling points and associated quadrature weights beta, alpha = S2.meshgrid(b=self.b, grid_type=grid_type) self.w = S2.quadrature_weights(b=self.b, grid_type=grid_type) self.spatial_grid_shape = beta.shape self.num_spatial_points = beta.size # Determine for which degree and order we want the spherical harmonics irreps = np.arange( self.b ) # TODO find out upper limit for exact integration for each grid type ls = [[ls] * (2 * ls + 1) for ls in irreps] ls = np.array([ll for sublist in ls for ll in sublist]) # 0, 1, 1, 1, 2, 2, 2, 2, 2, ... ms = [list(range(-ls, ls + 1)) for ls in irreps] ms = np.array([mm for sublist in ms for mm in sublist]) # 0, -1, 0, 1, -2, -1, 0, 1, 2, ... self.num_spectral_points = ms.size # This equals sum_{l=0}^{b-1} 2l+1 = b^2 # In one shot, sample the spherical harmonics at all spectral (l, m) and spatial (beta, alpha) coordinates self.Y = sh(ls[None, None, :], ms[None, None, :], beta[:, :, None], alpha[:, :, None], field=field, normalization=normalization, condon_shortley=condon_shortley == 'cs') # Convert to a matrix self.Ymat = self.Y.reshape(self.num_spatial_points, self.num_spectral_points)
def naive_S2_conv_v2(f1, f2, alpha, beta, gamma, g_parameterization='EA323'): """ Compute int_S^2 f1(x) f2(g^{-1} x)* dx, where x = (theta, phi) is a point on the sphere S^2, and g = (alpha, beta, gamma) is a point in SO(3) in Euler angle parameterization :param f1, f2: functions to be convolved :param alpha, beta, gamma: the rotation at which to evaluate the result of convolution :return: """ theta, phi = S2.meshgrid(b=3, grid_type='Gauss-Legendre') w = S2.quadrature_weights(b=3, grid_type='Gauss-Legendre') print(theta.shape, phi.shape) s2_coords = np.c_[theta[..., None], phi[..., None]] print(s2_coords.shape) r3_coords = np.c_[theta[..., None], phi[..., None], np.ones_like(theta)[..., None]] # g_inv = SO3.invert((alpha, beta, gamma), parameterization=g_parameterization) # g_inv = (-gamma, -beta, -alpha) g_inv = (alpha, beta, gamma) # wrong ginvx = SO3.transform_r3(g=g_inv, x=r3_coords, g_parameterization=g_parameterization, x_parameterization='S') print(ginvx.shape) g_inv_theta = ginvx[..., 0] g_inv_phi = ginvx[..., 1] g_inv_r = ginvx[..., 2] print(g_inv_theta, g_inv_phi, g_inv_r) f1_grid = f1(theta, phi) f2_grid = f2(g_inv_theta, g_inv_phi) print(f1_grid.shape, f2_grid.shape, w.shape) return np.sum(f1_grid * f2_grid * w)
def check_orthogonality(L_max=3, grid_type='Gauss-Legendre', field='real', normalization='quantum', condon_shortley=True): theta, phi = S2.meshgrid(b=L_max + 1, grid_type=grid_type) w = S2.quadrature_weights(b=L_max + 1, grid_type=grid_type) for l in range(L_max): for m in range(-l, l + 1): for l2 in range(L_max): for m2 in range(-l2, l2 + 1): Ylm = sh(l, m, theta, phi, field, normalization, condon_shortley) Ylm2 = sh(l2, m2, theta, phi, field, normalization, condon_shortley) dot_numerical = S2.integrate_quad(Ylm * Ylm2.conj(), grid_type=grid_type, normalize=False, w=w) dot_numerical2 = S2.integrate( lambda t, p: sh(l, m, t, p, field, normalization, condon_shortley) * \ sh(l2, m2, t, p, field, normalization, condon_shortley).conj(), normalize=False) sqnorm_analytical = sh_squared_norm(l, normalization, normalized_haar=False) dot_analytical = sqnorm_analytical * (l == l2 and m == m2) print(l, m, l2, m2, field, normalization, condon_shortley, dot_analytical, dot_numerical, dot_numerical2) assert np.isclose(dot_numerical, dot_analytical) assert np.isclose(dot_numerical2, dot_analytical)