def setup_d_transform(b, J_dense): """ """ # We know how to efficiently compute d functions in the real basis using # Pinchon-Hoggans approach (d_real = J X(beta) J), but we want them in the # basis of complex centered spherical harmonics Y^{-l}, ..., Y^{l}. # These matrices perform that change of basis ##C2R = [cc2rcph(l) for l in range(b)] #C2R = [get_sh_change_of_basis(l, # frm=('complex', 'seismology', 'centered'), # to=('real', 'quantum', 'centered')) # for l in range(b)] C2R = [ change_of_basis_matrix(l, frm=('complex', 'seismology', 'centered', 'cs'), to=('real', 'quantum', 'centered', 'cs')) for l in range(b) ] # Compute array of beta values as described in SOFT 2.0 documentation. beta = np.pi * (2 * np.arange(0, 2 * b) + 1) / (4. * b) # Compute d matrices in real basis (fast, stable), # then change them to complex basis (where the d-funcs are still real): d = [ np.array([rot_mat(0, bt, 0, l, J_dense[l]) for bt in beta]) for l in range(b) ] d = [C2R[l].conj().T.dot(d[l]).dot(C2R[l]).real for l in range(b)] #d = [np.array([wignerd_mat(l, b, approx_lim=100000) # for b in beta]).transpose(1, 0, 2) # for l in range(B)] # We want the L2 normalized functions: d = [d[l] * np.sqrt(l + 0.5) for l in range(len(d))] # Construct quadrature weights w # NO: this should be separate so that we can use the same d for forward and backward transforms """if weight: k = np.arange(0, b) w = np.array([(2. / b) * np.sin(np.pi * (2. * j + 1.) / (4. * b)) * (np.sum((1. / (2 * k + 1)) * np.sin((2 * j + 1) * (2 * k + 1) * np.pi / (4. * b)))) for j in range(2 * b)]) # In the SOFT source, they talk about the following weights being used for # odd-order transforms. Do not understand this, and the weights used above # (defined in the SOFT papers) seems to work. #w = np.array([(2. / B) * # (np.sum((1. / (2 * k + 1)) # * np.sin((2 * j + 1) * (2 * k + 1) # * np.pi / (4. * B)))) # for j in range(2 * B)]) # Apply quadrature weights to the wigner d function samples: d = [d[l] * w[None, :, None] for l in range(b)] """ return d
def setup_d_transform(b, J_dense): """ """ # We know how to efficiently compute d functions in the real basis using # Pinchon-Hoggans approach (d_real = J X(beta) J), but we want them in the # basis of complex centered spherical harmonics Y^{-l}, ..., Y^{l}. # These matrices perform that change of basis ##C2R = [cc2rcph(l) for l in range(b)] #C2R = [get_sh_change_of_basis(l, # frm=('complex', 'seismology', 'centered'), # to=('real', 'quantum', 'centered')) # for l in range(b)] C2R = [change_of_basis_matrix(l, frm=('complex', 'seismology', 'centered', 'cs'), to=('real', 'quantum', 'centered', 'cs')) for l in range(b)] # Compute array of beta values as described in SOFT 2.0 documentation. beta = np.pi * (2 * np.arange(0, 2 * b) + 1) / (4. * b) # Compute d matrices in real basis (fast, stable), # then change them to complex basis (where the d-funcs are still real): d = [np.array([rot_mat(0, bt, 0, l, J_dense[l]) for bt in beta]) for l in range(b)] d = [C2R[l].conj().T.dot(d[l]).dot(C2R[l]).real for l in range(b)] #d = [np.array([wignerd_mat(l, b, approx_lim=100000) # for b in beta]).transpose(1, 0, 2) # for l in range(B)] # We want the L2 normalized functions: d = [d[l] * np.sqrt(l + 0.5) for l in range(len(d))] # Construct quadrature weights w # NO: this should be separate so that we can use the same d for forward and backward transforms """if weight: k = np.arange(0, b) w = np.array([(2. / b) * np.sin(np.pi * (2. * j + 1.) / (4. * b)) * (np.sum((1. / (2 * k + 1)) * np.sin((2 * j + 1) * (2 * k + 1) * np.pi / (4. * b)))) for j in range(2 * b)]) # In the SOFT source, they talk about the following weights being used for # odd-order transforms. Do not understand this, and the weights used above # (defined in the SOFT papers) seems to work. #w = np.array([(2. / B) * # (np.sum((1. / (2 * k + 1)) # * np.sin((2 * j + 1) * (2 * k + 1) # * np.pi / (4. * B)))) # for j in range(2 * B)]) # Apply quadrature weights to the wigner d function samples: d = [d[l] * w[None, :, None] for l in range(b)] """ return d
def __init__(self, L_max, d=None, L2_normalized=True): self.L_max = L_max self.complex_fft = SO3_FFT_NaiveComplex(L_max=L_max, d=d, L2_normalized=L2_normalized) # Compute change of basis function: self.c2b = [change_of_basis_matrix(l, frm=('complex', 'seismology', 'centered', 'cs'), to=('real', 'quantum', 'centered', 'cs')) for l in range(L_max + 1)]
def __init__(self, L_max, d=None, L2_normalized=True): self.L_max = L_max self.complex_fft = SO3_FFT_NaiveComplex(L_max=L_max, d=d, L2_normalized=L2_normalized) # Compute change of basis function: self.c2b = [ change_of_basis_matrix(l, frm=('complex', 'seismology', 'centered', 'cs'), to=('real', 'quantum', 'centered', 'cs')) for l in range(L_max + 1) ]
def setup_d_transform(b, J_dense, L2_normalized): """ """ # We know how to efficiently compute d functions in the real basis using # Pinchon-Hoggans approach (d_real = J X(beta) J), but we want them in the # basis of complex centered spherical harmonics Y^{-l}, ..., Y^{l}. # These matrices perform that change of basis #C2R = [get_sh_change_of_basis(l, # frm=('complex', 'seismology', 'centered'), # to=('real', 'quantum', 'centered')) # for l in range(b)] C2R = [ change_of_basis_matrix(l, frm=('complex', 'seismology', 'centered', 'cs'), to=('real', 'quantum', 'centered', 'cs')) for l in range(b) ] # Compute array of beta values as described in SOFT 2.0 documentation. beta = np.pi * (2 * np.arange(0, 2 * b) + 1) / (4. * b) # Compute d matrices in real basis (fast, stable), # then change them to complex basis (where the d-funcs are still real): d = [ np.array([rot_mat(0, bt, 0, l, J_dense[l]) for bt in beta]) for l in range(b) ] d = [C2R[l].conj().T.dot(d[l]).dot(C2R[l]).real for l in range(b)] if L2_normalized: # The Unitary matrix elements have norm: # | U^\lambda_mn |^2 = 1/(2l+1) # where the 2-norm is defined in terms of normalized Haar measure. # So T = sqrt(2l + 1) U are L2-normalized functions d = [d[l] * np.sqrt(2 * l + 1) for l in range(len(d))] return d
def make_D_sample_grid(Jd, b=4, l=0, m=0, n=0, D='c'): if D == 'c': C2R = change_of_basis_matrix(l, frm=('complex', 'seismology', 'centered', 'cs'), to=('real', 'quantum', 'centered', 'cs')) D = lambda a, b, c: C2R.conj().T.dot(rot_mat(a, b, c, l, Jd[l])).dot( C2R)[m + l, n + l] elif D == 'r': D = lambda a, b, c: rot_mat(a, b, c, l, Jd[l])[m + l, n + l] else: assert False f = np.zeros((2 * b, 2 * b, 2 * b), dtype='complex') # We use the L2-normalized Wigner D functions #Z = (1. / (2 * np.pi)) * np.sqrt(l + 0.5) #Z = 1. / np.pi # Normalized wrt normalized Haar measure, as used by S3.integrate() #Z = np.sqrt(2 * l + 1) Z = 1. for j1 in range(f.shape[0]): alpha = 2 * np.pi * j1 / (2. * b) for k in range(f.shape[1]): beta = np.pi * (2 * k + 1) / (4. * b) for j2 in range(f.shape[2]): gamma = 2 * np.pi * j2 / (2. * b) #f[j1, k, j2] = D(alpha, beta, gamma) * (1. / 2. * np.pi) * np.sqrt(l + 0.5) #f[j1, k, j2] = (C2R.conj().T.dot(D(alpha, beta, gamma)).dot(C2R))[m + l, n + l] #f[j1, k, j2] *= (1. / (2. * np.pi)) * np.sqrt(l + 0.5) f[j1, k, j2] = D(alpha, beta, gamma) * Z return f
def make_D_sample_grid(Jd, b=4, l=0, m=0, n=0, D='c'): if D == 'c': C2R = change_of_basis_matrix(l, frm=('complex', 'seismology', 'centered', 'cs'), to=('real', 'quantum', 'centered', 'cs')) D = lambda a, b, c: C2R.conj().T.dot(rot_mat(a, b, c, l, Jd[l])).dot(C2R)[m + l, n + l] elif D == 'r': D = lambda a, b, c: rot_mat(a, b, c, l, Jd[l])[m + l, n + l] else: assert False f = np.zeros((2 * b, 2 * b, 2 * b), dtype='complex') # We use the L2-normalized Wigner D functions #Z = (1. / (2 * np.pi)) * np.sqrt(l + 0.5) #Z = 1. / np.pi # Normalized wrt normalized Haar measure, as used by S3.integrate() #Z = np.sqrt(2 * l + 1) Z = 1. for j1 in range(f.shape[0]): alpha = 2 * np.pi * j1 / (2. * b) for k in range(f.shape[1]): beta = np.pi * (2 * k + 1) / (4. * b) for j2 in range(f.shape[2]): gamma = 2 * np.pi * j2 / (2. * b) #f[j1, k, j2] = D(alpha, beta, gamma) * (1. / 2. * np.pi) * np.sqrt(l + 0.5) #f[j1, k, j2] = (C2R.conj().T.dot(D(alpha, beta, gamma)).dot(C2R))[m + l, n + l] #f[j1, k, j2] *= (1. / (2. * np.pi)) * np.sqrt(l + 0.5) f[j1, k, j2] = D(alpha, beta, gamma) * Z return f
def setup_d_transform(b, J_dense, L2_normalized): """ """ # We know how to efficiently compute d functions in the real basis using # Pinchon-Hoggans approach (d_real = J X(beta) J), but we want them in the # basis of complex centered spherical harmonics Y^{-l}, ..., Y^{l}. # These matrices perform that change of basis #C2R = [get_sh_change_of_basis(l, # frm=('complex', 'seismology', 'centered'), # to=('real', 'quantum', 'centered')) # for l in range(b)] C2R = [change_of_basis_matrix(l, frm=('complex', 'seismology', 'centered', 'cs'), to=('real', 'quantum', 'centered', 'cs')) for l in range(b)] # Compute array of beta values as described in SOFT 2.0 documentation. beta = np.pi * (2 * np.arange(0, 2 * b) + 1) / (4. * b) # Compute d matrices in real basis (fast, stable), # then change them to complex basis (where the d-funcs are still real): d = [np.array([rot_mat(0, bt, 0, l, J_dense[l]) for bt in beta]) for l in range(b)] d = [C2R[l].conj().T.dot(d[l]).dot(C2R[l]).real for l in range(b)] if L2_normalized: # The Unitary matrix elements have norm: # | U^\lambda_mn |^2 = 1/(2l+1) # where the 2-norm is defined in terms of normalized Haar measure. # So T = sqrt(2l + 1) U are L2-normalized functions d = [d[l] * np.sqrt(2 * l + 1) for l in range(len(d))] return d