def stark_interaction_Wigner_6j(state_1, state_2, **kwargs): """ Stark interaction between two states. <n' l' S' J' MJ'| H_S |n l S J MJ>. """ field_angle = kwargs.get('field angle', 0.0) if not np.mod(field_angle, 180.0) == 90.0: # parallel fields q_arr = [0] tau_arr = [1.] elif not np.mod(field_angle, 180.0) == 0.0: # perpendicular fields q_arr = [1, -1] tau_arr = [(1. / 2)**0.5, -(1. / 2)**0.5] else: raise Exception('Arbitrary angles not yet supported!') delta_L = state_1.L - state_2.L delta_S = state_1.S - state_2.S delta_MJ = state_1.M - state_2.M if abs(delta_L) == 1 and delta_S == 0: S = state_1.S sum_q = [] for q, tau in zip(q_arr, tau_arr): sum_q.append( (-1.)**(int(state_1.J - state_1.M)) * \ wigner_3j(state_1.J, 1, state_2.J, -state_1.M, -q, state_2.M) * \ (-1.)**(int(state_1.L + S + state_2.J + 1.)) * \ np.sqrt((2.*state_1.J+1.) * (2.*state_2.J+1.)) * \ wigner_6j(state_1.J, 1., state_2.J, state_2.L, S, state_1.L) * \ (-1.)**state_1.L * np.sqrt((2.*state_1.L+1.) * (2.*state_2.L+1.)) * \ wigner_3j(state_1.L, 1, state_2.L, 0, 0, 0) * tau) return np.sum(sum_q) * radial_overlap(state_1.n_eff, state_1.L, state_2.n_eff, state_2.L) return 0.0
def SetMatrix(I,J,AF,BF,B,gj): #Set values of interaction Hamiltonian matrix NMAX = int((2*J+1)*(2*I+1)) #size of matrix h_bar = scc.hbar #Plank constant/2pi mb = scc.physical_constants['Bohr magneton'][0] #Bohr magneton Hint=np.empty([NMAX,NMAX]) AF = AF * h_bar * 2 * np.pi # magnetic dipole constant BF = BF * h_bar * 2 * np.pi # electric quadrupole constant sj = wigner_6j(1, J, J, J, 1, 2) * wigner_6j(1, I, I, I, 1, 2) m = 0 n = 0 for mj1 in np.arange(-J,J+1): if n > NMAX or m > NMAX: break #stop if n or m exceed NMAX for mi1 in np.arange(-I,I+1): if n > NMAX or m > NMAX: break n = 0 for mj2 in np.arange(-J,J+1): if n > NMAX or m > NMAX: break for mi2 in np.arange(-I,I+1): if n > NMAX or m > NMAX: break Hint[m][n] = Delta(mi1, mi2) * Delta(mj1, mj2) * B * mb * gj * mj1 # first term of Hint if I>0 and J>0 : #contribution if there is a magnetic dipole moment Hint[m][n] = Hint[m][n] + AF * Minus(mj2 + mi1 + J + I)\ *np.sqrt(J*(J+1)*(2*J+1)*I*(I+1)*(2*I+1))\ *wigner_3j(J, 1, J, mj2, mj1 - mj2, -mj1)\ *wigner_3j(I, 1, I, mi2, mj2 - mj1, -mi1) if I>0.5 and J>0.5: #contribution if there is a electric quadrupole moment Hint[m][n] = Hint[m][n] + BF * Minus(mj2 + mi1 - J - I) * 15 / 2\ *((2 * J + 1) * (J + 1) * (2 * I + 1) * (I + 1)) / ((2 * J - 1) * (2 * I - 1))\ *wigner_3j(J, 2, J, mj2, mj1 - mj2, -mj1)\ *wigner_3j(I, 2, I, mi2, mj2 - mj1, -mi1) * sj n += 1 m += 1 return(Hint)
def calculate_microwave_ED_matrix_element(ground_state, excited_state,reduced = True, pol_vec = np.array((0,0,1))): #Find quantum numbers for ground state J = float(ground_state.J) F1 = float(ground_state.F1) F = float(ground_state.F) mF = float(ground_state.mF) I1 = float(ground_state.I1) I2 = float(ground_state.I2) #Find quantum numbers of excited state Jprime = float(excited_state.J) F1prime = float(excited_state.F1) Fprime = float(excited_state.F) mFprime = float(excited_state.mF) #Calculate reduced matrix element M_r = (np.sqrt(float((2*F1+1) * (2*F1prime+1) * (2*F+1)* (2*Fprime+1))) * float(wigner_6j(Jprime, F1prime,1/2,F1,J,1)) * float(wigner_6j(F1prime, Fprime,1/2,F,F1,1)) * np.sqrt(float((2*J+1) * (2*Jprime+1))) *(-1)**(F1prime+J+Fprime+F1+1) * float(wigner_3j(J,1,Jprime,0,0,0) * (-1)**J)) if reduced: return float(M_r) else: p_vec = {} p_vec[-1] = -1/np.sqrt(2) * (pol_vec[0] + 1j *pol_vec[1]) p_vec[0] = pol_vec[2] p_vec[1] = +1/np.sqrt(2) * (pol_vec[0] - 1j *pol_vec[1]) prefactor = 0 for p in range(-1,2): prefactor += (-1)**(p+F-mF) * p_vec[p] * float(wigner_3j(F,1,Fprime,-mF,-p,mFprime)) return prefactor*float(M_r)
def H_hfs(A, B): """ Hamiltonian hyperfine structure for the ground state. Through the wigner 3-J calculations. The two c_hfs terms come about due to the non-spherical, but present cylindrical symmetry of the diatomic representation of YbOh. If we choose to ignore them, then the energy levels will behave well as if it were atomic energy levels. Note, objects A != B. @type A: MolecularState Object @type B: MolecularState Object @rtype: float (Energy Value) """ # hfs J.I H_hfs = 0 for q in (-1, 0, 1): H_hfs += b_hfs * delta(A.N, B.N) * delta(A.mN, B.mN) * delta(A.mF(), B.mF()) \ * (-1)**q * (-1)**(A.S - A.mS) * wigner_3j(A.S, 1, B.S, -A.mS, q, B.mS) \ * (-1)**(A.I - A.mI) * wigner_3j(A.I, 1, B.I, -A.mI, -q,B.mI) \ * np.sqrt(A.S*(A.S+1)*(2*A.S+1)) * np.sqrt(A.I * (A.I+1) * (2 * A.I + 1)) \ H_hfs += c_hfs * ((delta(A.N,B.N) * delta(A.mN,B.mN) * delta(A.mS,B.mS) \ * delta(A.mI,B.mI) * (A.mS*A.mI))) H_hfs += -c_hfs * ((1/3) * delta(A.N,B.N) * delta(A.mN,B.mN) \ * delta(A.mF(),B.mF()) * (-1)**q * (-1)**(A.S-A.mS) \ * wigner_3j(A.S,1,B.S,-A.mS,q,B.mS) * (-1)**(A.I-A.mI) \ * wigner_3j(A.I,1,B.I,-A.mI,-q,B.mI) * np.sqrt(A.S*(A.S+1) * (2*A.S+1)) \ * np.sqrt(A.I * (A.I+1) * (2*A.I+1))) return H_hfs
def hunds_case_b_to_hunds_case_a(k, Q, J1, S1, N1, lam1, sig1, J, S, N, lam, sig, n=True): """ describes the transformation between the Hunds case (a) basis set and the Hunds case (b) basis set. Here, we must implicitly sum over all allowed values of sig and sig1 see Brown and Carrington 6.149 """ output = ((-1)**(J + J1 - S - S1 + lam + lam1) * sqrt( (2 * N + 1) * (2 * N1 + 1)) * wigner_3j(J1, S1, N1, lam1 + sig1, -sig1, -lam1) * wigner_3j(J, S, N, lam + sig, -sig, -lam) * reduced_lab_to_mol(J, lam + sig, k, Q, J1, lam1 + sig1)) return formated_output(output, n=n)
def WeightFunction(l1, l2, l12, l3, l4, m1, m2, m3, m4): """C_m^Lambda for 4th order isotropic basis function""" pref = pow(-1., l1 + l2 + l3 + l4) * np.sqrt(2. * l12 + 1.) wig1 = np.float64(wigner_3j(l1, l2, l12, m1, m2, -m1 - m2)) if wig1 == 0: return 0. wig2 = np.float64(wigner_3j(l12, l3, l4, m1 + m2, m3, m4)) if wig2 == 0: return 0. summ = wig1 * wig2 * pow(-1., l12 - m1 - m2) return summ * pref
def QuadMoment(Nmax,I1,I2): ''' Calculate the nuclear electric quadrupole moments of nuclei 1 and 2. spherical tensor for the nuclear quadrupole moment of both nuclei. Depends on the nuclear spin states not the rotational states. Args: Nmax (int) - Maximum rotational state to include I1,I2 (float) - The nuclear spins of nucleus 1 and 2 Returns: T (list of numpy.ndarray) - length-5 list of numpy.ndarrays ''' shape1 = int(2*I1+1) shape1 = (shape1,shape1) T1 = [numpy.zeros(shape1),numpy.zeros(shape1), numpy.zeros(shape1), numpy.zeros(shape1),numpy.zeros(shape1)] shape2 = int(2*I2+1) shape2 = (shape2,shape2) T2 = [numpy.zeros(shape2),numpy.zeros(shape2), numpy.zeros(shape2), numpy.zeros(shape2),numpy.zeros(shape2)] ShapeN = int(sum([2*x+1 for x in range(0,Nmax+1)])) IdentityN = numpy.identity(ShapeN) Identity1 = numpy.identity(int(2*I1+1)) Identity2 = numpy.identity(int(2*I2+1)) x=-1 for M1 in numpy.arange(I1,-(I1+1),-1): x+=1 y=-1 for M1p in numpy.arange(I1,-(I1+1),-1): y+=1 for i,q in enumerate(range(-2,2+1)): T1[i][x,y]=(-1)**(I1-M1)*wigner_3j(I1,2,I1,-M1,q,M1p)/\ wigner_3j(I1,2,I1,-I1,0,I1) x=-1 for M2 in numpy.arange(I2,-(I2+1),-1): x+=1 y=-1 for M2p in numpy.arange(I2,-(I2+1),-1): y+=1 for i,q in enumerate(range(-2,2+1)): T2[i][x,y]=(-1)**(I2-M2)*wigner_3j(I2,2,I2,-M2,q,M2p)/\ wigner_3j(I2,2,I2,-I2,0,I2) for i,q in enumerate(range(-2,2+1)): T1[i] = numpy.kron(IdentityN,numpy.kron(T1[i],Identity2)) T2[i] = numpy.kron(IdentityN,numpy.kron(Identity1,T2[i])) return T1,T2
def calculate_microwave_ME(state1, state2, reduced=False, pol_vec=np.array((0, 0, 1))): """ Function that evaluates the microwave matrix element between two states, state1 and state2, for a given polarization of the microwaves inputs: state1 = an UncoupledBasisState object state2 = an UncoupledBasisState object reduced = boolean that determines if the function returns reduced or full matrix element pol_vec = np.array describing the orientation of the microwave polarization in cartesian coordinates returns: Microwave matrix element between state 1 and state2 """ #Find quantum numbers for ground state J = float(state1.J) mJ = float(state1.mJ) I1 = float(state1.I1) m1 = float(state1.m1) I2 = float(state1.I2) m2 = float(state1.m2) #Find quantum numbers of excited state Jprime = float(state2.J) mJprime = float(state2.mJ) I1prime = float(state2.I1) m1prime = float(state2.m1) I2prime = float(state2.I2) m2prime = float(state2.m2) #Calculate reduced matrix element M_r = (N(wigner_3j(J, 1, Jprime, 0, 0, 0)) * np.sqrt( (2 * J + 1) * (2 * Jprime + 1)) * float(I1 == I1prime and m1 == m1prime and I2 == I2prime and m2 == m2prime)) #If desired, return just the reduced matrix element if reduced: return float(M_r) else: p_vec = {} p_vec[-1] = -1 / np.sqrt(2) * (pol_vec[0] + 1j * pol_vec[1]) p_vec[0] = pol_vec[2] p_vec[1] = +1 / np.sqrt(2) * (pol_vec[0] - 1j * pol_vec[1]) prefactor = 0 for p in range(-1, 2): prefactor += (-1)**(p - mJ) * p_vec[p] * float( wigner_3j(J, 1, Jprime, -mJ, -p, mJprime)) return prefactor * float(M_r)
def TwoBodyElement(Q1,Q2,m1p,m2p,m1,m2,l): result = 0.0 for lp in range(0,int(2*l+1)): for mp in range(-lp,lp+1): tmp = (-1)**(-m2p-m1p-mp) try: tmp *= wigner_3j(l,lp,l,-Q1,0,Q1)*wigner_3j(l,lp,l,m2p,-mp,-m2)*wigner_3j(l,lp,l,m1p,mp,-m1)*wigner_3j(l,lp,l,-Q2,0,Q2) except: tmp *= 0.0 result += tmp return ((2*l+1)**2)*((-1)**(Q1+Q2))*result
def w1_coeffs(l, p, n, m, q, s): w1 = 0.0 if (l >= abs(m)) and (p >= abs(q)) and (n >= abs(s)): if (l + p + n) % 2 == 0: fac = np.sqrt((sp.factorial(l + m) / sp.factorial(l - m)) * (sp.factorial(p + q) / sp.factorial(p - q)) * (sp.factorial(n - s) / sp.factorial(n + s))) w1 = ((-1)**s) * float( wigner_3j(l, p, n, 0, 0, 0) * wigner_3j(l, p, n, m, q, -s)) * fac return (2 * n + 1) * w1.real
def WeightFunction(l1, l2, l12, l3, l123, l4, l5, m1, m2, m3, m4, m5): """calE(Lambda)*C_M^Lambda for 5th order isotropic basis function""" pref = np.sqrt(2. * l12 + 1.) * np.sqrt(2. * l123 + 1.) # noting m12 = m1+m2, m123 = m1+m2+m3 wig1 = wigner_3j(l1, l2, l12, m1, m2, -m1 - m2) if wig1 == 0: return 0. wig2 = wigner_3j(l12, l3, l123, m1 + m2, m3, -m1 - m2 - m3) if wig2 == 0: return 0. wig3 = wigner_3j(l123, l4, l5, m1 + m2 + m3, m4, m5) if wig3 == 0: return 0. summ = wig1 * wig2 * wig3 * pow(-1., l12 - m1 - m2 + l123 - m1 - m2 - m3) return summ * pref
def compute_matrix_coeff(i): # output submatrix tmp_out = np.zeros((len(ell_1), len(ell_1))) # i is first matrix index L_1, L_2, L_3 = ell_1[i], ell_2[i], ell_3[i] pref_1 = np.sqrt((2. * L_1 + 1.) * (2. * L_2 + 1.) * (2. * L_3 + 1.)) for j in range(len(ell_1)): # j is second matrix index Lpp_1, Lpp_2, Lpp_3 = ell_1[j], ell_2[j], ell_3[j] pref_2 = pref_1 * np.sqrt( (2. * Lpp_1 + 1.) * (2. * Lpp_2 + 1.) * (2. * Lpp_3 + 1.)) # add phase pref_2 *= (-1.)**(Lpp_1 + Lpp_2 + Lpp_3) for k in range(len(ell_1)): # k indexes inner Lambda' term Lp_1, Lp_2, Lp_3 = ell_1[k], ell_2[k], ell_3[k] # Compute prefactor pref = pref_2 * np.sqrt( (2. * Lp_1 + 1.) * (2. * Lp_2 + 1.) * (2. * Lp_3 + 1.)) / (4. * np.pi)**(3. / 2.) # Compute 3j couplings three_j_piece = np.float64(wigner_3j(L_1, Lp_1, Lpp_1, 0, 0, 0)) if three_j_piece == 0: continue three_j_piece *= np.float64( wigner_3j(L_2, Lp_2, Lpp_2, 0, 0, 0)) if three_j_piece == 0: continue three_j_piece *= np.float(wigner_3j(L_3, Lp_3, Lpp_3, 0, 0, 0)) if three_j_piece == 0: continue # Compute the 9j component nine_j_piece = np.float64( wigner_9j(L_1, Lp_1, Lpp_1, L_2, Lp_2, Lpp_2, L_3, Lp_3, Lpp_3, prec=8)) if nine_j_piece == 0: continue tmp_out[j, k] = pref * three_j_piece * nine_j_piece return tmp_out
def xdipole_wigner3j_recurrence(l, wig_1llp1_000, wig_1llm1_000, wig_1llp1_1m10, wig_1llm1_1m10): #routine for computing successive Wigner3j symbols for x-polarized dipole based on recurrence #wig_1llp1_000 stores wigner symbols of the form (1 l l+1 ; 0 0 0) #wig_1llm1_000 stores wigner symbols of the form (1 l l-1 ; 0 0 0) mp.dps = mp.dps * 2 if len(wig_1llp1_000) < 2: #the m1=m2=m3=0 wigner3j symbols wig_1llp1_000.clear() wig_1llm1_000.clear() wig_1llp1_000.extend([ mp.mpf(wigner_3j(1, 1, 2, 0, 0, 0).evalf(mp.dps)), mp.mpf(wigner_3j(1, 2, 3, 0, 0, 0).evalf(mp.dps)) ]) wig_1llm1_000.extend([ mp.mpf(wigner_3j(1, 1, 0, 0, 0, 0).evalf(mp.dps)), mp.mpf(wigner_3j(1, 2, 1, 0, 0, 0).evalf(mp.dps)) ]) #the m1=1, m2=-1, m3=0 wigner3j symbols wig_1llp1_1m10.clear() wig_1llm1_1m10.clear() wig_1llp1_1m10.extend([ mp.mpf(wigner_3j(1, 1, 2, 1, -1, 0).evalf(mp.dps)), mp.mpf(wigner_3j(1, 2, 3, 1, -1, 0).evalf(mp.dps)) ]) wig_1llm1_1m10.extend([ mp.mpf(wigner_3j(1, 1, 0, 1, -1, 0).evalf(mp.dps)), mp.mpf(wigner_3j(1, 2, 1, 1, -1, 0).evalf(mp.dps)) ]) i = len(wig_1llp1_000) while i < l: i = i + 1 mp_i = mp.mpf(i) wig_1llm1_000.append(-mp.sqrt(mp_i * (2 * mp_i - 3) / ((mp_i - 1) * (2 * mp_i + 1))) * wig_1llp1_000[i - 3]) wig_1llp1_000.append(-mp.sqrt( (2 * mp_i - 1) * (mp_i + 1) / (mp_i * (2 * mp_i + 3))) * wig_1llm1_000[i - 1]) wig_1llm1_1m10.append( (wig3j_j2rec_j2m1_factor(1, i, i - 1, 1, -1, 0) * wig3j_j2rec_j2m1_factor(1, i - 1, i - 1, 1, -1, 0) + wig3j_j2rec_j2m2_factor(1, i, i - 1, 1, -1, 0)) * wig_1llp1_1m10[i - 1 - 2]) wig_1llp1_1m10.append( (wig3j_j3rec_j3m1_factor(1, i, i + 1, 1, -1, 0) * wig3j_j3rec_j3m1_factor(1, i, i, 1, -1, 0) + wig3j_j3rec_j3m2_factor(1, i, i + 1, 1, -1, 0)) * wig_1llm1_1m10[i - 1]) mp.dps = mp.dps // 2
def calc_hyperfine_transition_dipole(self, Fg, Fe, mFg, mFe, q): dFF = (self.dJJ * (-1)**(Fe + self.Jg + 1 + self.Inuc) * np.sqrt( (2 * Fe + 1) * (2 * self.Jg + 1)) * wigner_6j(self.Jg, self.Je, 1, Fe, Fg, self.Inuc)) #.evalf()) d_hf = dFF * (-1)**(Fe - 1 + mFg) * np.sqrt(2 * Fg + 1) * wigner_3j( Fe, 1, Fg, mFe, q, -mFg) #.evalf() return d_hf
def _ang_integral(S, L1, J1, MJ1, L2, J2, MJ2): """Calculate the angular integral (cached). Parameters ---------- S : int spin L1 : int orbital angular momentum, state 1 J1 : int total angular momentum, state 1 MJ1 : int projection of the total angular momentum, state 1 L2 : int orbital angular momentum, state 2 J2 : int total angular momentum, state 2 MJ2 : int projection of the total angular momentum, state 2 Returns ------- float """ return float( (-1.0)**(S + 1 + MJ2) * np.sqrt(max(L1, L2) * (2 * J2 + 1) * (2 * J1 + 1)) * wigner_3j(J2, 1, J1, -MJ2, 0, MJ1) * wigner_6j(S, L2, J2, 1, J1, L1))
def Yl_red(l1, l2, l): """ < l1 || Y_l || l2 > Note: all inputs are not not doubled """ return (-1)**l1 * np.sqrt((2 * l1 + 1) * (2 * l2 + 1) * (2 * l + 1) / (4 * np.pi)) * N(wigner_3j(l1, l, l2, 0, 0, 0))
def F_func_2(self): """ define the F in eq(14) with the l2, L, l1 order """ ell1 = self.ell1 ell = self.ell ell2 = self.ell2 spin = self.spin return self.H_func()*wigner_3j(ell2, ell, ell1, spin, 0, -spin)
def mu(N_u,J_u,F_u,F_uz,N_l,J_l,F_l,F_lz,I,q):#compute the dipole moment. from eq. 4.33 pg 55 in Laser cooling and Trapping (Metcalf) rad_el = Rad(N_u,J_u,N_l,J_l)*a_0 #q is the photon polarization q = +-1 or 0 exp = c_e*(-1.0)**(1+(J_u-0.5)+0.5+J_l+J_u+I-F_uz) sqrt = n.sqrt((2.0*J_u+1.0)*(2.0*J_l+1.0)*(2.0*F_u+1.0)*(2.0*F_l+1.0)) wig6 = wigner_6j((J_u-0.5),J_u,0.5,J_l,(J_l-0.5),1)*wigner_6j(J_u,F_u,I,F_l,J_l,1) wig3 = wigner_3j(F_l,1,F_u,F_lz,q,-F_uz) mu = rad_el*exp*sqrt*wig6*wig3 return mu
def A_calc(J_u,F_u,F_uz,J_l,F_l,F_lz,I,q):#compute the dipole moment. from eq. 4.33 pg 55 in Laser cooling and Trapping (Metcalf) #q is the photon polarization q = +-1 or 0 exp = c_e*(-1.0)**(1+(J_u-0.5)+0.5+J_l+J_u+I-F_uz) sqrt = n.sqrt((2.0*J_u+1.0)*(2.0*J_l+1.0)*(2.0*F_u+1.0)*(2.0*F_l+1.0)) wig6 = wigner_6j((J_u-0.5),J_u,0.5,J_l,(J_l-0.5),1)*wigner_6j(J_u,F_u,I,F_l,J_l,1) wig3 = float(wigner_3j(F_l,1,F_u,F_lz,q,-F_uz)) A_calc = exp*sqrt*wig6*wig3 return [A_calc,exp,sqrt,wig6,wig3]
def AC_aniso(Nmax,a2,Beta,I1,I2): ''' Calculate anisotropic ac stark shift. Generates the effect of the anisotropic AC Stark shift for a rigid-rotor like molecule. This term is calculated differently to all of the others in this work and is based off Jesus Aldegunde's FORTRAN 77 code. It iterates over N,MN,N',MN' to build a matrix without hyperfine structure then uses kronecker products to expand it into all of the hyperfine states. Args: Nmax (int) - maximum rotational quantum number to calculate a2 (float) - anisotropic polarisability Beta (float) - polarisation angle of the laser in Radians I1,I2 (float) - Nuclear spin of nucleus 1,2 Returns: H (numpy.ndarray): Hamiltonian in joules ''' I1shape = int(2*I1+1) I2shape = int(2*I2+1) shape = numpy.sum(numpy.array([2*x+1 for x in range(0,Nmax+1)])) HAC = numpy.zeros((shape,shape),dtype= numpy.complex) i=0 j=0 for N1 in range(0,Nmax+1): for M1 in range(N1,-(N1+1),-1): for N2 in range(0,Nmax+1): for M2 in range(N2,-(N2+1),-1): M = M2-M1 HAC[i,j]= -a2*(Wigner_D(2,M,0,Beta,0)*(-1)**M2*\ numpy.sqrt((2*N1+1)*(2*N2+1))*\ wigner_3j(N2,2,N1,0,0,0)*\ wigner_3j(N2,2,N1,-M2,M,M1)) j+=1 j=0 i+=1 #final check for NaN errors, mostly this is due to division by zero or # multiplication by a small prefactor. it is safe to set these terms to 0 HAC[numpy.isnan(HAC)] =0 #return the matrix, in the full uncoupled basis. return (numpy.kron(HAC,numpy.kron(numpy.identity(I1shape), numpy.identity(I2shape))))
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 N(wigner_3j(j1, j2, j3, m1, m2, m3))
def safe_3j_symbols(j1, j2, j3, m1, m2, m3): """ :args j_1, j_2, j_3, m_1, m_2, m_3 Calculates the Clebsch-Gordan coefficient for the base < j1 m1, j2 m2 | j3 m3 >. """ return float(wigner_3j(j1, j2, j3, m1, m2, m3))
def H_sr(A, B): """ Hamiltonian Spin rotation @type A: MolecularState Object @type B: MolecularState Object @rtype: float (Energy Value) """ # spin-rotation S.N H_sr = 0 for q in (-1, 0, 1): H_sr += delta(A.mI, B.mI) * delta(A.N, B.N) * delta(A.mF(), B.mF()) * \ (-1)**q * (-1) ** (A.S - A.mS) * wigner_3j(A.S, 1, B.S, -A.mS, q, B.mS) * \ (-1)**(A.N - A.mN) * wigner_3j(A.N, 1, B.N, -A.mN, -q, B.mN) H_sr = gamma * H_sr * np.sqrt(A.S * (A.S+1) * (2 * A.S+1)) \ * np.sqrt(A.N * (A.N+1) * (2 * A.N+1)) return H_sr
def M1_moment(A, B, q=0): """M1 matrix element: <A|mu|B> Units are mu_B """ if (A.P * B.P == +1): # check to see if the two states have same parity return (-1)**(A.F - A.mF) * wigner_3j(A.F, 1, B.F, -A.mF, q, B.mF) * M1_reduced_F(A, B) else: return 0
def switch_basis(theta_12, BDm0, BDm1): ''' Switch the bispectrum basis from Scocimarro to tripolar spherical harmonics by integrating over theta_12 (k1 and k2 are fixed) ''' ell1 = 1 ell2 = 0 L = 1 #{'k1': [0.002, 0.005, 0.01, 0.02], 'k2': [0.002, 0.005, 0.01, 0.02], 'b1': 1.08, 'b2': 0.0, 'be': 0.0, #'B101': [48662961.978645*sqrt(3), 78399057.5970337*sqrt(3), 76977056.1599017*sqrt(3), 37667729.8442636*sqrt(3)]} # B101_dict = {'k1': [0.002, 0.005, 0.01, 0.02], 'k2': [0.002, 0.005, 0.01, 0.02], 'b1': 1.08, 'b2': 0.0, 'be': 0.0, #'B101': [145988885.935935*sqrt(3), 235197172.791101*sqrt(3), 230931168.479705*sqrt(3), 113003189.532791*sqrt(3)]} print("switch basis to (%d,%d,%d)" % (ell1, ell2, L)) BDm0_interp = interp1d(theta_12, BDm0) BDm1_interp = interp1d(theta_12, BDm1) # B_{11} = -B_{1-1} sp_factor = np.sqrt(4. * np.pi / (2. * ell2 + 1.)) int1 = lambda costh_12: wigner_3j( ell1, ell2, L, 0, 0, 0) * sp_factor * sp.sph_harm( 0, ell2, costh_12, 0.) * BDm0_interp(np.arccos(costh_12)) # M = 0 int2 = lambda costh_12: wigner_3j( ell1, ell2, L, 0, -1, 1) * sp_factor * sp.sph_harm( -1, ell2, costh_12, 0.) * BDm1_interp(np.arccos(costh_12)) # M = 1 int3 = lambda costh_12: wigner_3j( ell1, ell2, L, 0, 1, -1) * sp_factor * sp.sph_harm( 1, ell2, costh_12, 0.) * BDm1_interp(np.arccos(costh_12)) # M = -1 tmp = integrate.nquad(int1, [[-1 + ep, 1 - ep]], full_output=True) print("tmp = ", tmp) result = tmp[0] print("result = ", result) if ell2 > 0: ###### is there a symmetry which makes the M=1 and M=-1 contributions to cancel out? tmp = integrate.nquad(int2, [[-1 + ep, 1 - ep]], full_output=True) print("tmp = ", tmp) result += tmp[0] print("result = ", result) tmp = integrate.nquad(int3, [[-1 + ep, 1 - ep]], full_output=True) print("tmp = ", tmp) result += tmp[0] print("result = ", result) H = wigner_3j(ell1, ell2, L, 0, 0, 0) N = (2. * ell1 + 1.) * (2. * ell2 + 1) * (2. * L + 1.) return -0.5 * N * H * result / np.sqrt(4. * np.pi * (2. * L + 1.))
def hunds_case_b_to_hunds_case_a(k, Q, J1, S1, N1, lam1, sig1, J, S, N, lam, sig, n=True): """ describes the transformation between the Hunds case (a) basis set and the Hunds case (b) basis set. Here, we must implicitly sum over all allowed values of sig and sig1 see Brown and Carrington 6.149 """ output = ((-1)**(J + J1 - S - S1 + lam + lam1) * sqrt((2 * N + 1) * (2 * N1 + 1)) * wigner_3j(J1, S1, N1, lam1 + sig1, -sig1, -lam1) * wigner_3j(J, S, N, lam + sig, -sig, -lam) * reduced_lab_to_mol(J, lam + sig, k, Q, J1, lam1 + sig1)) return formated_output(output, n=n)
def DC(Nmax,d0,I1,I2): ''' Generates the effect of the dc Stark shift for a rigid-rotor like molecule. This term is calculated differently to all of the others in this work and is based off Jesus Aldegunde's FORTRAN 77 code. It iterates over N,MN,N',MN' to build a matrix without hyperfine structure then uses kronecker products to expand it into all of the hyperfine states. input arguments: Nmax: maximum rotational quantum number to calculate (int) d0: Permanent electric dipole momentum (float) I1,I2: Nuclear spin of nucleus 1,2 (float) returns: H: Hamiltonian, (2*Nmax+1)*(2*I1_mag+1)*(2*I2_mag+1)x (2*Nmax+1)*(2*I1_mag+1)*(2*I2_mag+1) array. ''' shape = numpy.sum(numpy.array([2*x+1 for x in range(0,Nmax+1)])) HDC = numpy.zeros((shape,shape),dtype= numpy.complex) I1shape = int(2*I1+1) I2shape = int(2*I2+1) i =0 j =0 for N1 in range(0,Nmax+1): for M1 in range(N1,-(N1+1),-1): for N2 in range(0,Nmax+1): for M2 in range(N2,-(N2+1),-1): HDC[i,j]=-d0*numpy.sqrt((2*N1+1)*(2*N2+1))*(-1)**(M1)*\ wigner_3j(N1,1,N2,-M1,0,M2)*wigner_3j(N1,1,N2,0,0,0) j+=1 j=0 i+=1 return (numpy.kron(HDC,numpy.kron(numpy.identity(I1shape), numpy.identity(I2shape))))
def wigner_eckart(j, m, k, q, j1, m1, n=True): """ the wigner-eckart theorem allows extraction of the angular dependence of a matrix element leaving the reduced matrix element that is no longer dependent on spatial orientation (M quantum numbers). See Brown and Carrington 5.172 """ output = (-1)**(j - m) * wigner_3j(j, k, j1, -m, q, m1) return format_output(output, n=n)
def angular_overlap_wigner(L_1, L_2, M_1, M_2, **kwargs): field_angle = kwargs.get('field_angle', 0.0) if not np.mod(field_angle, 180.0) == 90.0: # parallel fields q_arr = [0] tau_arr = [1.] elif not np.mod(field_angle, 180.0) == 0.0: # perpendicular fields q_arr = [1, -1] tau_arr = [(1. / 2)**0.5, (1. / 2)**0.5] else: raise Exception('Arbitrary angles not yet supported!') # For accumulating each element in the angular component, q sum sum_q = [] for q, tau in zip(q_arr, tau_arr): sum_q.append(tau * float(wigner_3j(L_2, 1, L_1, -M_2, q, M_1))) # Calculate the angular overlap term using Wigner-3J symbols _angular_overlap = ((2*L_2+1)*(2*L_1+1))**0.5 * \ np.sum(sum_q) * \ wigner_3j(L_2, 1, L_1, 0, 0, 0) return _angular_overlap
def Wignerindex(l): """ Define Wigner 3-j symbol """ selected = [] for m1 in range(-l, l + 1): for m2 in range(-l, l + 1): for m3 in range(-l, l + 1): if m1 + m2 + m3 == 0: windex = wigner_3j(l, l, l, m1, m2, m3).evalf() selected.append(np.array([m1, m2, m3, windex])) return np.ravel(np.array(selected)).reshape(-1, 4)
def w_term(lmax, x, F): res = np.zeros((len(x), lmax + 1, lmax + 1), dtype=float) for lx in range(lmax + 1): for ly in range(lmax + 1): if lx == ly: res[:, lx, ly] = pot_cent(x, lx) + pot_int(x) else: res[:, lx, ly] = -dipole(x) * F * np.sqrt( (2 * lx + 1) * (2 * ly + 1)) * wigner_3j(lx, ly, 1, 0, 0, 0)**2 return res
def reduced_lab_to_mol(j, w, k, Q, j1, w1, n=True): """ This function describes the transformation from the laboratory frame to the molecular-axis-fixed frame. This assumes that the angular dependence has already been extracted using the wigner eckart theorem. see Brown and Carrington 5.186 """ output = ((-1)**(j - w) * wigner_3j(j, k, j1, -w, Q, w1) * sqrt((2 * j + 1) * (2 * j1 + 1))) return format_output(output, n=n)
def test_thrj(self): """ """ from sympy.physics.wigner import wigner_3j for l1 in range(0,3): for l2 in range(0,3): for l3 in range(0,3): for m1 in range(-4,4+1): for m2 in range(-4,4+1): for m3 in range(-4,4+1): w3j1 = thrj(l1, l2, l3, m1, m2, m3) w3j2 = thrj_nobuf(l1, l2, l3, m1, m2, m3) w3j3 = float(wigner_3j(l1, l2, l3, m1, m2, m3)) #print(w3j1, w3j2, w3j3, l1, l2, l3) self.assertAlmostEqual(w3j1, w3j2) self.assertAlmostEqual(w3j2, w3j3)
def dipole(self, Me, Mg, q): """ Find the q-spherical component of the dipole matrix element between Me and Mg :param M1: :param M2: :param q: :return: """ key = "%d%d%d" % (Me, Mg, q) if key not in self._cache: self._cache[key] = ( (-1)**(self.Ig + self.Je - Me) * self.reduced_dipole_element * sqrt((2*self.Fg+1)*(2*self.Fe+1)) * float(wigner_6j(self.Je, self.Fe, self.Ig, self.Fg, self.Jg, 1)) * float(wigner_3j(self.Fg, 1, self.Fe, Mg, q, -Me)) ) return self._cache[key]
def N3j(*args): """ gives numerical value of 3-j symbol """ return float(wigner.wigner_3j(*args))
def doit(self, **hints): if self.is_symbolic: raise ValueError("Coefficients must be numerical") return wigner_3j(self.j1, self.j2, self.j3, self.m1, self.m2, self.m3)
def gaunt_ref(l1, l2, l3, m1, m2, m3): return ( sqrt((2 * l1 + 1) * (2 * l2 + 1) * (2 * l3 + 1) / (4 * pi)) * wigner_3j(l1, l2, l3, 0, 0, 0) * wigner_3j(l1, l2, l3, m1, m2, m3) )