def test_reduced_shear_transform_mw(): L = 20 Cl = np.ones(L) * 1E-4 seed = 1 Method = "MW" kappa_lm = mm.generate_kappa_lm_mw(Cl, L, seed=seed) k_mw = ssht.inverse(kappa_lm, L, Reality=True, Method=Method) gamma_lm = mm.kappa_lm_to_gamma_lm_mw(kappa_lm, L) gamma = ssht.inverse(gamma_lm, L, Method=Method, Spin=2) shear = gamma / (1.0 - k_mw) k_rec_mw = mm.reduced_shear_to_kappa_mw(shear, L, Iterate=True, Method=Method, tol_error=1E-10) np.testing.assert_almost_equal( k_rec_mw, k_mw, decimal=7, err_msg="reduced shear and kappa transoforms are not invereses")
def test_real_inverse_ssht_vs_ducc0(real_coeffs, order, method, nthreads=1): ssht_image = ssht.inverse(real_coeffs, order, Reality=True, Method=method, Spin=0) ducc0_image = ssht.inverse( real_coeffs, order, Reality=True, Method=method, Spin=0, backend="ducc", nthreads=nthreads, ) assert ssht_image == approx(ducc0_image)
def sYlm(s, l, m, L, rotation=None): flm = np.zeros(L*L, dtype=complex) ind = ssht.elm2ind(l, m) flm[ind] = 1.0 if rotation: flm = ssht.rotate_flms(flm, rotation[0], rotation[1], rotation[2], L) f = ssht.inverse(flm, L, Spin=s) return f
def test_SHT(L, Method, Reality, Spin, nthreads=1): if Reality: # Generate random flms (of real signal). flm = np.zeros((L * L), dtype=complex) # Impose reality on flms. for el in range(L): m = 0 ind = ssht.elm2ind(el, m) flm[ind] = np.random.randn() for m in range(1, el + 1): ind_pm = ssht.elm2ind(el, m) ind_nm = ssht.elm2ind(el, -m) flm[ind_pm] = np.random.randn() + 1j * np.random.randn() flm[ind_nm] = (-1)**m * np.conj(flm[ind_pm]) else: flm = np.random.randn(L * L) + 1j * np.random.randn(L * L) t0 = time() f = ssht.inverse( flm, L, Reality=Reality, Method=Method, Spin=Spin, backend="ducc", nthreads=nthreads, ) flm_syn = ssht.forward( f, L, Reality=Reality, Method=Method, Spin=Spin, backend="ducc", nthreads=nthreads, ) tducc = time() - t0 t0 = time() f2 = ssht.inverse(flm, L, Reality=Reality, Method=Method, Spin=Spin) flm_syn2 = ssht.forward(f2, L, Reality=Reality, Method=Method, Spin=Spin) tssht = time() - t0 return (_l2error(f, f2) + _l2error(flm_syn, flm_syn2), tssht / tducc)
def test_complex_inverse_ssht_vs_ducc0(complex_coeffs, order, method, spin, nthreads=1): ssht_image = ssht.inverse(complex_coeffs, order, Reality=False, Method=method, Spin=spin) ducc0_image = ssht.inverse( complex_coeffs, order, Reality=False, Method=method, Spin=spin, backend="ducc", nthreads=nthreads, ) assert ssht_image == approx(ducc0_image)
def test_gamma_transform_mw(): L = 20 Cl = np.ones(L) seed = 1 Method = "MW" kappa_lm = mm.generate_kappa_lm_mw(Cl, L, seed=seed) k_mw = ssht.inverse(kappa_lm, L, Reality=True, Method=Method) gamma_lm = mm.kappa_lm_to_gamma_lm_mw(kappa_lm, L) gamma = ssht.inverse(gamma_lm, L, Method=Method, Spin=2) k_rec_mw = mm.gamma_to_kappa_mw(gamma, L, Method=Method) np.testing.assert_almost_equal( k_rec_mw, k_mw, decimal=7, err_msg="gamma and kappa transoforms are not invereses")
def test_real_forward_adjoint(rng: np.random.Generator, method, order): shape = ssht.sample_shape(order, Method=method) f = rng.standard_normal(shape, dtype="float64") flm = ssht.forward(f, order, Reality=True, Method=method) f = ssht.inverse(flm, order, Reality=True, Method=method) f_prime = rng.standard_normal(shape, dtype="float64") flm_prime = ssht.forward(f_prime, order, Reality=True, Method=method) f_prime = ssht.forward_adjoint(flm_prime, order, Reality=True, Method=method, backend="ducc") assert flm_prime.conj() @ flm == approx( f_prime.flatten().conj() @ f.flatten())
def test_forward_adjoint(rng: np.random.Generator, spin, method, order): flm = rng.standard_normal( (order * order, 2), dtype="float64") @ np.array([1, 1j]) flm[0:spin * spin] = 0.0 f = ssht.inverse(flm, order, Spin=spin, Method=method, backend="ducc") flm_prime = rng.standard_normal( (order * order, 2), dtype="float64") @ np.array([1, 1j]) flm_prime[0:spin * spin] = 0.0 f_prime = ssht.forward_adjoint(flm_prime, order, Spin=spin, Method=method, backend="ducc") assert flm_prime.conj() @ flm == approx( f_prime.flatten().conj() @ f.flatten())
error_cylindrical_B = np.zeros((N_angle, N_real)) error_mercator_B = np.zeros((N_angle, N_real)) error_sine_B = np.zeros((N_angle, N_real)) error_orthographic_B = np.zeros((N_angle, N_real)) error_steriographic_B = np.zeros((N_angle, N_real)) error_gnomic_B = np.zeros((N_angle, N_real)) Cls = np.loadtxt("data/cls_ap.txt") for i_real in range(N_real): print i_real k_lm_mw = mm.generate_kappa_lm_mw(np.array(Cls[:, 1]), L) ks_lm_mw = ssht.guassian_smoothing(k_lm_mw, L, sigma_in=np.pi / 256) k_mw = ssht.inverse(ks_lm_mw, L, Reality=True, Method=Method) gamma_lm = mm.kappa_lm_to_gamma_lm_mw(ks_lm_mw, L) gamma = ssht.inverse(gamma_lm, L, Method=Method, Spin=2) if do_cylindrical: print "Doing Projection Cylindrical" gamma_plane = -gamma kappa_orig_plane = k_mw kappa_plane = mm.gamma_to_kappa_plane(gamma_plane, np.pi / L, 2 * np.pi / (2 * L - 1)) for i in range(N_angle): x = np.abs(thetas - np.pi / 2) indexes = np.nonzero((x < angle[i] + angle_step / 2)
# Compute weights as function of theta. wr = (np.fft.fft(np.fft.ifftshift(wr)) * 2 * np.pi / (2 * L - 1)**2).real # Compute symmetrised quadrature weights defined on sphere. q = wr[0:L] for i, j in enumerate(range(2 * L - 2, L - 1, -1)): q[i] = q[i] + wr[j] # Integral of function given by rescaled (el,m)=(0,0) harmonic coefficient. I0 = flm[0] * np.sqrt(4 * np.pi) print("Integration using input flm:", I0) # Integrate function on sphere using all points. f = ssht.inverse(flm, L, Method=method, Reality=reality) Q = np.outer(q, np.ones(2 * L - 1)) I1 = sum(sum(Q[:] * f[:])) print("Integration using all points:", I1) # Integration function on sphere using L points in phi. # (Zero-pad to evalue the band-limited function on the correct L points.) ntheta, nphi = ssht.sample_shape(L, Method=method) f_up = np.zeros((L, 2 * L), dtype=complex) f_down = np.zeros((L, int((2 * L) / 2)), dtype=complex) for r in range(ntheta): dum = np.fft.fftshift(np.fft.fft(f[r, :])) dum = np.insert(dum, 0, 0.0) f_up[r, :] = np.fft.ifft(np.fft.ifftshift(dum)) / (2 * L - 1) * (2 * L)
def test_everything(): # Test indexing functions ind2elm_check = [ pyssht.ind2elm(i) == sshtn.ind2elm(i) for i in range(L * L) ] assert all(ind2elm_check), "ind2elm functions do not match" elm2ind_check = [ pyssht.elm2ind(el, m) == sshtn.elm2ind(el, m) for el in range(L) for m in range(-el, el) ] assert all(elm2ind_check), "elm2ind functions do not match" assert pyssht.sample_shape(L, Method="MW") == sshtn.mw_sample_shape(L) assert pyssht.sample_shape(L, Method="MWSS") == sshtn.mwss_sample_shape(L) py_theta, py_phi = pyssht.sample_positions(L, Method="MW", Grid=False) nb_theta, nb_phi = sshtn.mw_sample_positions(L) assert np.allclose(py_theta, nb_theta) assert np.allclose(py_phi, nb_phi) py_theta, py_phi = pyssht.sample_positions(L, Method="MWSS", Grid=False) nb_theta, nb_phi = sshtn.mwss_sample_positions(L) assert np.allclose(py_theta, nb_theta) assert np.allclose(py_phi, nb_phi) py_ttheta, py_pphi = pyssht.sample_positions(L, Method="MW", Grid=True) nb_ttheta, nb_pphi = sshtn.mw_sample_grid(L) assert np.allclose(py_ttheta, nb_ttheta) assert np.allclose(py_pphi, nb_pphi) py_ttheta, py_pphi = pyssht.sample_positions(L, Method="MWSS", Grid=True) nb_ttheta, nb_pphi = sshtn.mwss_sample_grid(L) assert np.allclose(py_ttheta, nb_ttheta) assert np.allclose(py_pphi, nb_pphi) # Generate random flms (of complex signal). np.random.seed(89834) flm = np.random.randn(L * L) + 1j * np.random.randn(L * L) # Zero harmonic coefficients with el<|spin|. ind_min = np.abs(s)**2 flm[0:ind_min] = 0.0 + 1j * 0.0 # MW inverse complex transform f_py_mw = pyssht.inverse(flm, L, Spin=s, Method="MW") f_nb_mw = np.empty(sshtn.mw_sample_shape(L), dtype=np.complex128) sshtn.mw_inverse_sov_sym(flm, L, s, f_nb_mw) assert np.allclose(f_py_mw, f_nb_mw) # MW forward complex transform, recovering input rec_flm_py_mw = pyssht.forward(f_py_mw, L, Spin=s, Method="MW") rec_flm_nb_mw = np.empty(L * L, dtype=np.complex128) sshtn.mw_forward_sov_conv_sym(f_nb_mw, L, s, rec_flm_nb_mw) assert np.allclose(rec_flm_py_mw, rec_flm_nb_mw) assert np.allclose(rec_flm_nb_mw, flm) # MW forward real transform f_re = np.random.randn(*sshtn.mw_sample_shape(L)) flm_py_re_mw = pyssht.forward(f_re, L, Spin=0, Method="MW", Reality=True) flm_nb_re_mw = np.empty(L * L, dtype=np.complex128) sshtn.mw_forward_sov_conv_sym_real(f_re, L, flm_nb_re_mw) assert np.allclose(flm_py_re_mw, flm_nb_re_mw) # MW inverse real transform rec_f_re_py = pyssht.inverse(flm_py_re_mw, L, Spin=0, Method="MW", Reality=True) rec_f_re_nb = np.empty(sshtn.mw_sample_shape(L), dtype=np.float64) sshtn.mw_inverse_sov_sym_real(flm_nb_re_mw, L, rec_f_re_nb) assert np.allclose(rec_f_re_py, rec_f_re_nb) # Note that rec_f_re_{py,nb} != f_re since f_re is not band-limited at L # MWSS invserse complex transform f_py_mwss = pyssht.inverse(flm, L, Spin=s, Method="MWSS", Reality=False) f_nb_mwss = np.empty(sshtn.mwss_sample_shape(L), dtype=np.complex128) sshtn.mw_inverse_sov_sym_ss(flm, L, s, f_nb_mwss) assert np.allclose(f_py_mwss, f_nb_mwss) # MWSS forward complex transform rec_flm_py_mwss = pyssht.forward(f_py_mwss, L, Spin=s, Method="MWSS", Reality=False) rec_flm_nb_mwss = np.empty(L * L, dtype=np.complex128) sshtn.mw_forward_sov_conv_sym_ss(f_nb_mwss, L, s, rec_flm_nb_mwss) assert np.allclose(rec_flm_py_mwss, rec_flm_nb_mwss) assert np.allclose(rec_flm_nb_mwss, flm) # MWSS forward real transform f_re2 = np.random.randn(*sshtn.mwss_sample_shape(L)) flm_py_re_mwss = pyssht.forward(f_re2, L, Spin=0, Method="MWSS", Reality=True) flm_nb_re_mwss = np.empty(L * L, dtype=np.complex128) sshtn.mw_forward_sov_conv_sym_ss_real(f_re2, L, flm_nb_re_mwss) assert np.allclose(flm_py_re_mwss, flm_nb_re_mwss) # MWSS inverse real transform rec_f_re_py_mwss = pyssht.inverse(flm_py_re_mwss, L, Spin=0, Method="MWSS", Reality=True) rec_f_re_nb_mwss = np.empty(sshtn.mwss_sample_shape(L), dtype=np.float64) sshtn.mw_inverse_sov_sym_ss_real(flm_nb_re_mwss, L, rec_f_re_nb_mwss) assert np.allclose(rec_f_re_py_mwss, rec_f_re_nb_mwss) assert np.allclose(pyssht.generate_dl(np.pi / 2, 10), sshtn.generate_dl(np.pi / 2, 10))
# % Simple demo to compute inverse and forward transform of complex scalar # % function, using simplest interface with default options. # % # % Author: Christopher G R Wallis & Jason McEwen (www.christophergrwallis.org & www.jasonmcewen.org) # % # % pyssht python package to perform spin spherical harmonic transforms # Define parameters. L = 64 # Generate random flms (of complex signal). flm = np.random.randn(L*L) + 1j*np.random.randn(L*L) # Compute inverse then forward transform. f = ssht.inverse(flm, L); flm_syn = ssht.forward(f, L); # Compute max error in harmonic space. maxerr = np.abs(flm_syn - flm).max() print "Max error: ", maxerr # Plot function on sphere using mollweide projection f_plot, mask_array = ssht.mollweide_projection(np.abs(f), L, resolution=200) plt.figure() imgplot = plt.imshow(f_plot,interpolation='nearest') plt.colorbar(imgplot,fraction=0.025, pad=0.04) plt.imshow(mask_array, interpolation='nearest', cmap=cm.gray, vmin=-1., vmax=1.) plt.gca().set_aspect("equal") plt.title("|f|")
# hp.gnomview(kappa_E_map_hp_rec*mask_hp, title="K E map",rot=[70,-53,0.0], reso=6.0, min=-0.015, max=0.015, cmap="cubehelix") # if save_figs: # plt.savefig("fig/DES_hp_E.pdf") # hp.gnomview(kappa_B_map_hp_rec*mask_hp, title="K B map",rot=[70,-53,0.0], reso=6.0, min=-0.015, max=0.015, cmap="cubehelix") # if save_figs: # plt.savefig("fig/DES_hp_B.pdf") alm_mask_hp = hp.map2alm(mask, lmax=L_hp - 1) alm_E_hp = hp.map2alm(kappa_E_map_hp_rec, lmax=L_hp - 1) alm_B_hp = hp.map2alm(kappa_B_map_hp_rec, lmax=L_hp - 1) alm_mask_hp_mw = mm.lm_hp2lm(alm_mask_hp, L_hp) alm_E_hp_mw = mm.lm_hp2lm(alm_E_hp, L_hp) alm_B_hp_mw = mm.lm_hp2lm(alm_B_hp, L_hp) mask_mw = ssht.inverse(alm_mask_hp_mw, L_hp, Reality=True) kappa_E_map_hp_rec_mw = ssht.inverse(alm_E_hp_mw, L_hp, Reality=True) kappa_B_map_hp_rec_mw = ssht.inverse(alm_B_hp_mw, L_hp, Reality=True) mask_mw[mask_mw < 0.5] = np.nan k_hp_mw = kappa_E_map_hp_rec_mw + 1j * kappa_B_map_hp_rec_mw k_mw_north_real, mask_north_real, k_mw_south_real, mask_south_real, \ k_mw_north_imag, mask_north_imag, k_mw_south_imag, mask_south_imag \ = ssht.polar_projection(k_hp_mw*mask_mw, L_hp, resolution=250, Method="MW", zoom_region=zoom_region,\ rot=[np.radians(alpha),np.radians(beta),np.radians(g)], Projection="SP") RA_lines_1, RA_lines_2, dec_lines_1, dec_lines_2 = sterio_grid_lines( resolution=250, zoom_region=zoom_region)
def test_inverse_ndim(self): with self.assertRaises(ssht.ssht_input_error) as context: ssht.inverse(f,L) self.assertTrue('flm must be 1D numpy array' in context.exception)
# % pyssht_demo_4 - Run demo4 # % # % Demo to compute inverse and forward transform of spin function, using # % polar interface. # % # % Author: Christopher G R Wallis & Jason McEwen (www.christophergrwallis.org & www.jasonmcewen.org) # % # % pyssht python package to perform spin spherical harmonic transforms # Define parameters. L = 64 Spin = 0 method = "MW_pole" # Generate random flms (of complex signal). flm = np.random.randn(L * L) + 1j * np.random.randn(L * L) # Zero harmonic coefficients with el<|spin|. ind_min = np.abs(Spin)**2 flm[0:ind_min] = 0.0 + 1j * 0.0 # Compute inverse then forward transform. f, f_sp, phi_sp = ssht.inverse(flm, L, Spin=Spin, Method="MW_pole") flm_syn = ssht.forward((f, f_sp, phi_sp), L, Spin=Spin, Method="MW_pole") # Compute max error in harmonic space. maxerr = np.abs(flm_syn - flm).max() print("Max error:", maxerr)
# Generate random flms (of real signal). flm = np.zeros((L * L), dtype=complex) # Impose reality on flms. for el in range(L): m = 0 ind = ssht.elm2ind(el, m) flm[ind] = np.random.randn() for m in range(1, el + 1): ind_pm = ssht.elm2ind(el, m) ind_nm = ssht.elm2ind(el, -m) flm[ind_pm] = np.random.randn() + 1j * np.random.randn() flm[ind_nm] = (-1)**m * np.conj(flm[ind_pm]) # Compute inverse then forward transform. f = ssht.inverse(flm, L, Reality=True) flm_syn = ssht.forward(f, L, Reality=True) # Compute max error in harmonic space. maxerr = np.abs(flm_syn - flm).max() print "Max error: ", maxerr # Plot function on sphere using mollweide projection f_plot, mask_array = ssht.mollweide_projection(np.abs(f), L, resolution=200) plt.figure() imgplot = plt.imshow(f_plot, interpolation='nearest') plt.colorbar(imgplot, fraction=0.025, pad=0.04) plt.imshow(mask_array, interpolation='nearest', cmap=cm.gray,
# s2c test L=256 thetas, phis = ssht.sample_positions(L, Grid=True) f = np.zeros((L,2*L-1), dtype=np.float_) + np.random.randn(L,2*L-1) #ssht.plot_sphere(phis, L,Parametric=False, Output_File='test.pdf',Show=False, Color_Bar=True, Units='Radians') (x, y, z) = ssht.s2_to_cart(thetas, phis) (x, y, z) = ssht.spherical_to_cart( np.ones(thetas.shape), thetas, phis) #test rotations flm = ssht.forward(phis, L, Reality=True) f = ssht.inverse(flm,L, Reality=True) flm_prime = ssht.rotate_flms(flm, np.pi/4, np.pi/4, np.pi/4, L) f_prime = ssht.inverse(flm_prime, L, Reality=True) #ssht.plot_sphere(f, L,Parametric=False, Output_File='test_phi_sphere.pdf',Show=False, Color_Bar=True, Units='Radians') #ssht.plot_sphere(f_prime, L,Parametric=False, Output_File='test_phi_rot_sphere.pdf',Show=False, Color_Bar=True, Units='Radians') #plot = ssht.plot_mollweide(f, L, Close=True) #plt.show() #plot2 = ssht.plot_mollweide(f_prime, L, Close=True) #plt.show() # transform tests
def real_image(order, method, real_coeffs): return ssht.inverse(real_coeffs, order, Reality=True, Method=method, Spin=0)
def test_inverse_method_type(self): with self.assertRaises(ssht.ssht_input_error) as context: ssht.inverse(flm,L,Method="DJ") self.assertTrue('Method is not recognised, Methods are: MW, MW_pole, MWSS, DH and GL' in context.exception)
def complex_image(complex_coeffs, order, method, spin): return ssht.inverse(complex_coeffs, order, Reality=False, Method=method, Spin=spin)
# % pyssht python package to perform spin spherical harmonic transforms # Define parameters. L = 128 sigma = np.pi / L #% Load harmonic coefficients of Earth. mat_contents = sio.loadmat('src/matlab/data/EGM2008_Topography_flms_L0128') flm = np.ascontiguousarray(mat_contents['flm'][:, 0]) #% Smooth harmonic coefficients. flm_smooth = ssht.guassian_smoothing(flm, L, sigma) # Compute real space version of Earth. f = ssht.inverse(flm, L, Reality=True) f_smooth = ssht.inverse(flm_smooth, L, Reality=True) # Plot f_plot, mask_array = ssht.mollweide_projection(f, L, resolution=200, rot=[0.0, np.pi, np.pi]) plt.figure() plt.subplot(1, 2, 1) imgplot = plt.imshow(f_plot, interpolation='nearest') plt.colorbar(imgplot, fraction=0.025, pad=0.04) plt.imshow(mask_array, interpolation='nearest', cmap=cm.gray, vmin=-1.,
# % pyssht_demo_3 - Run demo3 # % # % Demo to compute inverse and forward transform of spin function, using # % standard interface with various options. # % # % Author: Christopher G R Wallis & Jason McEwen (www.christophergrwallis.org & www.jasonmcewen.org) # % # % pyssht python package to perform spin spherical harmonic transforms # Define parameters. L = 64 spin = 4 methods = ["MW", "MWSS", "GL", "DH"] # Generate random flms (of complex signal). flm = np.random.randn(L * L) + 1j * np.random.randn(L * L) # Zero harmonic coefficients with el<|spin|. ind_min = np.abs(spin)**2 flm[0:ind_min] = 0.0 + 1j * 0.0 # Compute inverse then forward transform. for method in methods: f = ssht.inverse(flm, L, Method=method, Spin=spin, Reality=False) flm_syn = ssht.forward(f, L, Method=method, Spin=spin, Reality=False) # Compute max error in harmonic space. maxerr = np.abs(flm_syn - flm).max() print("Method:", method, "\nMax error:", maxerr)
# Define parameters. L = 64; el = 4 m = 2 gamma = np.pi/2 beta = np.pi/4 alpha = -np.pi/2 # Generate spherical harmonics. flm = np.zeros((L*L),dtype=complex); ind = ssht.elm2ind(el, m); flm[ind] = 1.0 + 1j*0.0; # Compute function on the sphere. f = ssht.inverse(flm, L) # Rotate spherical harmonic flm_rot = ssht.rotate_flms(flm, alpha, beta, gamma, L) # Compute rotated function on the sphere. f_rot = ssht.inverse(flm_rot, L) # Plot f_plot, mask_array, f_plot_imag, mask_array_imag = ssht.mollweide_projection(f, L, resolution=200, rot=[0.0,np.pi,np.pi]) plt.figure() plt.subplot(1,2,1) imgplot = plt.imshow(f_plot,interpolation='nearest')
def ReadFingerprint(fname): # Calculates the number of real spherical harmonic orders that belong to an # expansion from degree l=0 to L. def addmup(x): x = np.array(x) res = 0.5 * (x + 1)**2 + 0.5 * x + 0.5 return (res.astype(int)) # Read in the file header with open(fname) as f: header = f.readline() (L, age) = header.split() L = int(L) # Read in the rest of the file test = np.loadtxt(fname, skiprows=1) my_C = test[:, [0, 2]].flatten() my_S = test[:, [1, 3]].flatten() # Calculate the indices that are expected to have '0' as coefficients mods = L - np.arange(0, L + 1) + 1 modu = np.cumsum(mods + np.mod(mods, 2)) zero_inds = modu[np.mod(mods, 2) == 1] - 1 # Remove the zero coefficients my_C = np.delete(my_C, zero_inds) my_S = np.delete(my_S, zero_inds) # Indices to line up coefficients in hlm modm = np.append( np.cumsum(np.append(0, mods[np.arange(0, mods.size - 1)])), int(addmup(L))) #### Produces "dems' and 'dels' from addmon dems = np.empty(0, np.int8) dels = np.empty(0, np.int8) for i in np.arange(0, L + 1): dems = np.append(dems, np.arange(0, i + 1)) dels = np.append(dels, np.repeat(i, i + 1)) # Initialize variable to hold coefficients hlm = np.zeros((dels.size, 2)) # Populate hlm with the coefficients for m in np.arange(0, L + 1): hlm[addmup(np.arange(m - 1, L)) + m, 0] = my_C[modm[m]:modm[m + 1]] hlm[addmup(np.arange(m - 1, L)) + m, 1] = my_S[modm[m]:modm[m + 1]] # Realign conventions CSC = (-1)**dems hlm[:, 0] = hlm[:, 0] * CSC hlm[:, 1] = hlm[:, 1] * CSC # Convert hlm into a form that can be used by the ssht library counter = 0 flm = np.zeros((L + 1)**2, dtype=np.complex_) for ii in np.arange(0, L + 1): sub = np.where(dels == ii)[0] if sub.size > 1: sub2 = np.append(sub[-1:0:-1], sub) else: sub2 = sub flm[counter:(counter + sub2.size)] = hlm[sub2, 0] + 1j * hlm[sub2, 1] counter = counter + sub2.size fels = np.floor(np.sqrt(np.arange(0, flm.size))) fems = np.arange(0, flm.size) - fels * fels - fels sub = np.where(fems < 0)[0] flm[sub] = (-1)**fems[sub] * np.conj(flm[sub]) # Invert the harmonics f = ssht.inverse(flm, L + 1, Method="MWSS", Reality=True) f = f * np.sqrt(4 * np.pi) (thetas, phis) = ssht.sample_positions(L + 1, "MWSS") lat = 90 - np.rad2deg(thetas) lon = np.mod(np.rad2deg(phis) + 180, 360) sort_inds = np.argsort(lon) lon = lon[sort_inds] f = f[:, sort_inds] return (f, lat, lon)