def test_wigner3j_ignore_invalid(): N = np.arange(1, 2) K = np.arange(-2, 3)[:, np.newaxis] with pytest.raises(ValueError): # should raise an error wigner3j(N * 2, K * 2, 0, 0, 0, 0, ignore_invalid=False) # should compute wigner3j(N * 2, K * 2, 0, 0, 0, 0, ignore_invalid=True)
def test_wigner3j_value(): # scalar test for three_j, expected in THREE_J: three_j = (np.array(three_j) * 2).astype(int) actual = wigner3j(*three_j) assert np.allclose(actual, expected) # test vector three_j = (np.array([thr for thr, _ in THREE_J]).T * 2).astype(int) expected = np.array([value for _, value in THREE_J]).T actual = wigner3j(*three_j) assert np.allclose(actual, expected)
def w3j_vecm(l1, l2, l3, m1, m2, m3): l1 = int(2*l1) l2 = int(2*l2) l3 = int(2*l3) m1 = 2*m1 m2 = 2*m2 m3 = 2*m3 wigvals = py3nj.wigner3j(l1, l2, l3, m1, m2, m3) return wigvals
def compute_Honl_London_factors(self, freqc): ueps = self.map_parity_to_epsilon(freqc[:, 10]) leps = self.map_parity_to_epsilon(freqc[:, 11]) uj, lj = freqc[:, 2], freqc[:, 3] uomega, lomega = freqc[:, 6], freqc[:, 7] ulambda, llambda = freqc[:, 4], freqc[:, 5] eps_expr = 1.0 + (ueps * leps * np.power(-1, 1.0 + uj - lj)) udelta = self.map_quantum_number_to_delta(ulambda) udelta *= self.map_quantum_number_to_delta(uomega) ldelta = self.map_quantum_number_to_delta(llambda) ldelta *= self.map_quantum_number_to_delta(lomega) delta_expr = 1.0 + udelta + ldelta - 2.0 * udelta * ldelta j_expr = ((2.0 * uj) + 1.0) * ((2.0 * lj + 1.0)) two_l1 = np.int64(2 * uj) two_l2 = 2 * np.ones(freqc.shape[0], dtype=np.int64) two_l3 = np.int64(2 * lj) two_m1 = np.int64(-2 * uomega) two_m2 = np.int64(2 * (ulambda - llambda)) two_m3 = np.int64(2 * lomega) # allows for the ambiguous sign in the 3j symbol when one of the Lambda # quantum numbers is zero (Ref: J.K.G. Watson, JMS 252 (2008)) if (ulambda.any() == 0 and llambda.any() != 0) or \ (ulambda.any() != 0 and llambda.any() == 0): two_m2 = np.int64(2 * (ulambda + llambda)) two_m3 = np.int64(-2 * lomega) # set to zero the qunatum numbers that # do not satisfy the following conditions if (two_l1 < np.abs(two_m1)).any(): valid = 1 * ~(two_l1 < np.abs(two_m1)) two_m1 *= valid if (two_l2 < np.abs(two_m2)).any(): valid = 1 * ~(two_l2 < np.abs(two_m2)) two_m2 *= valid if (two_l3 < np.abs(two_m3)).any(): valid = 1 * ~(two_l3 < np.abs(two_m3)) two_m3 *= valid wigner_3j = py3nj.wigner3j(two_l1, two_l2, two_l3, two_m1, two_m2, two_m3) wigner_3j_square = wigner_3j**2 hlf = 0.5 * eps_expr * delta_expr * j_expr * wigner_3j_square return hlf
def thj(j1, j2, j3, m1, m2, m3): """ 3-j symbol ( j1 j2 j3 ) ( m1 m2 m3 ) """ #return wigner3j(j1,j2,j3,m1,m2,m3) return py3nj.wigner3j(int(2 * j1), int(2 * j2), int(2 * j3), int(2 * m1), int(2 * m2), int(2 * m3))
def w3j(l1, l2, l3, m1, m2, m3): l1 = int(2*l1) l2 = int(2*l2) l3 = int(2*l3) m1 = int(2*m1) m2 = int(2*m2) m3 = int(2*m3) try: wigval = py3nj.wigner3j(l1, l2, l3, m1, m2, m3) except ValueError: return 0.0 return wigval
def test_wigner3j_value(ignore_invalid): # scalar test for three_j, expected in THREE_J: three_j = (np.array(three_j) * 2).astype(int) actual = wigner3j(*three_j, ignore_invalid=ignore_invalid) assert np.allclose(actual, expected) # broadcast the first argument actual = wigner3j(np.array([three_j[0]])[:, np.newaxis], *three_j[1:], ignore_invalid=ignore_invalid) assert np.allclose(actual, expected) # further broadcasting actual = wigner3j( np.array([three_j[0]])[:, np.newaxis, np.newaxis], *three_j[1:]) assert np.allclose(actual, expected) # test vector three_j = (np.array([thr for thr, _ in THREE_J]).T * 2).astype(int) expected = np.array([value for _, value in THREE_J]).T actual = wigner3j(*three_j) assert np.allclose(actual, expected)
def get_RgNl0_coeff_for_zdipole_field(k, R, dist, l): ans = 0.0j kd = k * ( R + dist ) #dist is distance between dipole and sphere surface, the translation distance d is between the two origins so dipole and sphere center # norm = np.sqrt(rho_N(l,k*R)/k**3) #normalization for nu in range(l - 1, l + 2): tmp = (1j)**(1 - nu - l) * 0.5 * (2 + l * (l + 1) - nu * (nu + 1)) * (2 * nu + 1) * np.sqrt( 3 * (2 * l + 1) / 2 / l / (l + 1)) tmp *= py3nj.wigner3j(2 * 1, 2 * l, 2 * nu, 0, 0, 0)**2 * ( sp.spherical_jn(nu, kd) + 1j * sp.spherical_yn(nu, kd)) ans += tmp # print(ans) ans *= 1j * k * np.sqrt((1.0 / 6 / np.pi)) #normalization NOT included return ans
def mp_get_normalized_RgNl0_coeff_for_zdipole_field(k, R, dist, l): ans = mpmath.mpc(0.0j) kd = k * ( R + dist ) #dist is distance between dipole and sphere surface, the translation distance d is between the two origins so dipole and sphere center # norm = np.sqrt(rho_N(l,k*R)/k**3) #normalization for nu in range(l - 1, l + 2): tmp = (1j)**(1 - nu - l) * 0.5 * (2 + l * (l + 1) - nu * (nu + 1)) * ( 2 * nu + 1) * mpmath.sqrt(3 * (2 * l + 1) / 2 / l / (l + 1)) tmp *= py3nj.wigner3j(2 * 1, 2 * l, 2 * nu, 0, 0, 0)**2 * mp_spherical_hn(nu, kd) ans += tmp # print(ans) ans *= 1j * k * mpmath.sqrt((1.0 / 6 / mpmath.pi) * mp_rho_N(l, k * R) / k**3) #normalization included in sqrt return ans
def wigner3j(jj1, jj2, jj3, mm1, mm2, mm3): """ Calculate the Wigner 3-j symbol, .. math:: \\left(\\begin{array}{ccc} j_1 & j_2 & j_3 \\\\ m_1 & m_2 & m_3 \\end{array} \\right) Parameters ---------- jj1 : integer Twice the value of :math:`j_1`. jj2 : integer Twice the value of :math:`j_2`. jj3 : integer Twice the value of :math:`j_3`. mm1 : integer Twice the value of :math:`m_1`. mm2 : integer Twice the value of :math:`m_2`. mm3 : integer Twice the value of :math:`m_3`. Returns ------- float The result. Notes ----- This currently wraps the `py3nj <https://github.com/fujiisoup/py3nj>`_ implementation. The back-end may change in the future. Examples -------- >>> n2.angmom.wigner3j(2 * 20, 2 * 21, 2 * 22, 2 * 5, 2 * -15, 2 * 10) 0.032597617477982975 """ result = py3nj.wigner3j(jj1, jj2, jj3, mm1, mm2, mm3) return result
def test_wigner3j(half_integer): n = 10000 n2 = 10 l2 = rng.randint(0, 40, size=n) * 2 + half_integer l3 = rng.randint(0, 40, size=n) * 2 + half_integer m2 = np.zeros(n, dtype=int) m3 = np.zeros(n, dtype=int) for i in range(n): if l2[i] > 0: m2[i] = rng.randint(-l2[i], l2[i]+1) if l3[i] > 0: m3[i] = rng.randint(-l3[i], l3[i]+1) l, expected_all = wigner.drc3jj(l2, l3, m2, m3) for _ in range(n2): lindex = rng.randint(0, 40, n) * 2 - 1 + half_integer two_l1 = l[lindex] two_m1 = -(m2 + m3) actual = wigner3j(two_l1, l2, l3, two_m1, m2, m3) expected = expected_all[np.arange(len(lindex)), lindex] assert np.allclose(actual, expected)
def find_param(coords, l, l2, L, d): myrange = range(-l, l + 1) myrange2 = range(-l2, l2 + 1) param = [] neighbours = [] #find parameter for each particle a for i, a in enumerate(coords): sph_harm = [] sph_harm2 = [] n = [] #loop over all particles b for each particle a for j, b in enumerate(coords): #if a==b, don't use particle b if i != j: r = find_vector(a, b, L) #check if particle b is nearest neighbour to a if np.dot(r, r) <= d**2: #append nearest neighbours to new list n.append(j) #construct spherical harmonics theta = np.arctan2(r[1], r[0]) phi = np.arccos(r[2] / np.linalg.norm(r)) new_vec = np.array( [special.sph_harm(m, l, theta, phi) for m in myrange]) new_vec2 = np.array([ special.sph_harm(m, l2, theta, phi) for m in myrange2 ]) #append spherical harmonics to new list and carry on loop sph_harm.append(new_vec) sph_harm2.append(new_vec2) #find parameter for particle a and append to parameters list #append all neighbours to new list neighbours.append(n) total = sum(sph_harm) N = len(sph_harm) p1 = total / N #make local invariants for l=6 q6 = A1 * np.linalg.norm(p1) combo6 = [seq for seq in combinations(myrange, 3) if sum(seq) == 0] combo6_list = [list(elem) for elem in combo6] W6 = [] for u in combo6_list: wig = py3nj.wigner3j(2 * l, 2 * l, 2 * l, 2 * u[0], 2 * u[1], 2 * u[2]) w_l = np.real(wig * p1[u[0] + 6] * p1[u[1] + 6] * p1[u[2] + 6]) W6.append(w_l) w6 = sum(W6) / (np.linalg.norm(p1)**3) #make local invariants for l=4 total2 = sum(sph_harm2) N2 = len(sph_harm2) p2 = total2 / N2 q4 = A2 * np.linalg.norm(p2) combo4 = [seq for seq in combinations(myrange2, 3) if sum(seq) == 0] combo4_list = [list(elem) for elem in combo4] W4 = [] for v in combo4_list: wig2 = py3nj.wigner3j(2 * l2, 2 * l2, 2 * l2, 2 * v[0], 2 * v[1], 2 * v[2]) w_l2 = np.real(wig2 * p2[v[0] + 4] * p2[v[1] + 4] * p2[v[2] + 4]) W4.append(w_l2) w4 = sum(W4) / (np.linalg.norm(p2)**3) P = [q6, q4, w6, w4] param.append(P) #write parameters to seperate file to be used for machine learning with open('liquid1.8_q6q4w6w4.txt', 'ab') as file: pickle.dump(param, file) return param, neighbours
def obtain_parameters(coordinates): mrange = range(-l,l+1) nrange = range(-l2,l2+1) parameters = [] # gives list of all spherical harmonics for each particle # DQ using enumerate is more "pythonic" than that you were doing.... for a, i in enumerate(coordinates): s_harm1 = [] s_harm2 = [] conc = [] # moved b = 0 outside bracket,put back if it messes things for b, j in enumerate(coordinates): if a != b: r = reduce_vector(i,j,L) if np.dot(r,r) <= neighbour_dist_sqrd: the = np.arctan2(r[1],r[0]) phi = np.arccos(r[2]/np.linalg.norm(r)) m_vec = np.array([sc.special.sph_harm(m,l,the,phi) for m in mrange ]) n_vec = np.array([sc.special.sph_harm(m,l2,the,phi) for m in nrange ]) # gives q4 spherical harmonic aswell s_harm1.append(m_vec) s_harm2.append(n_vec) #returns the spherical harmonics particle which are neighbours to the particle the spherical harmonics particle which are neighbours to the particle param1 = (sum(s_harm1))/ (len(s_harm1)) param2 = (sum(s_harm2))/ (len(s_harm2)) #param1 and param2 are both 1d arrays (lengths 13 and 9), which contain the q6 and q4 set of vectors respectively, for one particle #there are 500 q6m values in param1 and param2 local_inv_q6 = A1sqrt*np.linalg.norm(param1) local_inv_q4 = A2sqrt*np.linalg.norm(param2) #calculate w_descriptor result1 = [seq for i in range(len(mrange), 0, -1) for seq in itertools.combinations(range(-l,l+1), 3) if sum(seq) == 0] result2 = [seq for i in range(len(nrange), 0, -1) for seq in itertools.combinations(range(-l2,l2+1), 3) if sum(seq) == 0] #produces w(i) matrix as list of tuples, however there are repeating tuples in the list. out1 = set([i for i in result1]) out2 = set([i for i in result2]) #remove duplicates from list of tuples w_l = list(out1) w_l2 = list(out2) #coverts set into list of unique tuples list_of_w_l = [] list_of_w_l2 = [] for i, j in enumerate(w_l): m1 = j[0] m2 = j[1] m3 = j[2] qlm1 = param1[m1+6] qlm2 = param1[m2+6] qlm3 = param1[m3+6] #corrects for index position with m values as it starts from m=-l x = py.wigner3j(l*2, l*2, l*2, j[0]*2, j[1]*2, j[2]*2) x1 = x*qlm1*qlm2*qlm3 list_of_w_l.append(x1) # appends each combination of each wl(i)*qlm1*qlm2*qlm3 matrix to a list for i, j in enumerate(w_l2): m1 = j[0] m2 = j[1] m3 = j[2] ql2m1 = param2[m1+4] ql2m2 = param2[m2+4] ql2m3 = param2[m3+4] #corrects for index position with m values as it starts from m=-l y = py.wigner3j(l2*2, l2*2, l2*2, j[0]*2, j[1]*2, j[2]*2) y1 = y*ql2m1*ql2m2*ql2m3 list_of_w_l2.append(y1) # appends each combination of each wl2(i)*qlm1*qlm2*qlm3 matrix to a list w_l_loc = sum(list_of_w_l) w_l2_loc = sum(list_of_w_l2) # w_l(i) parameter w_l_hat_re_im = (w_l_loc)/(np.linalg.norm(param1))**3 w_l2_hat_re_im = (w_l2_loc)/(np.linalg.norm(param2))**3 # get both real and imaginary parts of the w hat loc invaraint descriptor. w_l_hat = np.real(w_l_hat_re_im) w_l2_hat = np.real(w_l2_hat_re_im) li = np.append(local_inv_q6,local_inv_q4) li_list = li.tolist() q6q4w6w4 = li_list + [w_l_hat, w_l2_hat] #appends all 4 descriptors to 1 list for each particle parameters.append(q6q4w6w4) #appends all descriptors to 1 list with 4 descriptors for each of the 500 particles with open('q6q4w6w4_loc_inv_misaligned_quench.txt', 'ab') as filehandle: # store the data as binary data stream #ab instead of wb, so it doesnt overwrite parameters pickle.dump(parameters, filehandle) return parameters
#if os.path.exists(ovr_fileName): # sys.exit(0) for l1 in np.arange(maxJ + 1): for m1_ in np.arange(-1 * l1, l1 + 1): m1 = -1 * m1_ m2 = -1 * (m1 + M) if np.amax(np.abs(np.array([m2, l1 - L]))) > np.amin([maxJ, l1 + L]): continue for l2 in np.arange(np.amax(np.abs(np.array([m2, l1 - L]))), np.amin([maxJ, l1 + L]) + 1): if np.abs(m2) > l2: continue integral = ((-1)**m1)*np.sqrt((2*l1+1)*(2*L+1)*(2*l2+1)/(4*np.pi))\ *py3nj.wigner3j(2*l1,2*L,2*l2,0,0,0)\ *py3nj.wigner3j(2*l1,2*L,2*l2,2*m1,2*M,2*m2) if integral: overlap.append(integral) indices.append(np.array([[l1, m1, l2, m2]])) ovr = np.real(np.array(overlap)).astype(np.double) ind = np.concatenate(indices, axis=0).astype(np.int32) #for o,i in zip(ovr,ind): # print(o,i) ovr.tofile(ovr_fileName) ind_fileName += "_bins[" + str(ind.shape[0]) + "," + str( ind.shape[1]) + "].dat"
def gaunt_for(two_l1, two_l2, two_l3, two_m1, two_m2, two_m3): return ((two_l1+1)*(two_l2+1)*(two_l3+1)/(4*np.pi))**0.5*wigner3j(two_l1,two_l2,two_l3,two_m1,two_m2,two_m3)*wigner3j(two_l1,two_l2,two_l3,0,0,0)