def test_clebsch_gordan3(): j_1 = S(3)/2 j_2 = S(3)/2 m = S(3) j = S(3) m_1 = S(3)/2 m_2 = S(3)/2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = S(3)/2 j_2 = S(3)/2 m = S(2) j = S(2) m_1 = S(3)/2 m_2 = S(1)/2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1/sqrt(2) j_1 = S(3)/2 j_2 = S(3)/2 m = S(2) j = S(3) m_1 = S(3)/2 m_2 = S(1)/2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1/sqrt(2)
def test_clebsch_gordan4(): j_1 = S(2) j_2 = S(2) m = S(4) j = S(4) m_1 = S(2) m_2 = S(2) assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = S(2) j_2 = S(2) m = S(3) j = S(3) m_1 = S(2) m_2 = 1 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1/sqrt(2) j_1 = S(2) j_2 = S(2) m = S(2) j = S(3) m_1 = 1 m_2 = 1 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 0
def test_clebsch_gordan5(): j_1 = S(5)/2 j_2 = S(1) m = S(7)/2 j = S(7)/2 m_1 = S(5)/2 m_2 = 1 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = S(5)/2 j_2 = S(1) m = S(5)/2 j = S(5)/2 m_1 = S(5)/2 m_2 = 0 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(5)/sqrt(7) j_1 = S(5)/2 j_2 = S(1) m = S(3)/2 j = S(3)/2 m_1 = S(1)/2 m_2 = 1 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1/sqrt(15)
def AME(self, state1, state2, p): l1, j1, m1 = state1.angular_momentum() l2, j2, m2 = state2.angular_momentum() res =(-1)**int(j1+l2-0.5)*sqrt((2*j1+1)*(2*l1+1)) res *= clebsch_gordan(j1, 1, j2, m1, p, m2) res *= clebsch_gordan(l1, 1, l2, 0, 0, 0) res *= wigner_6j(l1,0.5,j1,j2,1,l2) return res
def test_clebsch_gordan_docs(): assert clebsch_gordan(S(3) / 2, S(1) / 2, 2, S(3) / 2, S(1) / 2, 2) == 1 assert clebsch_gordan(S(3) / 2, S(1) / 2, 1, S(3) / 2, -S(1) / 2, 1) == sqrt(3) / 2 assert clebsch_gordan(S(3) / 2, S(1) / 2, 1, -S(1) / 2, S(1) / 2, 0) == -sqrt(2) / 2
def get_matrix_element(self, a, b, c, d): """ Compute the J^2 operator in a two-body M-scheme basis. Calculation is done by expanding the bra and the ket (given in M-scheme basis) in coupled J basis in the following manner. <a,b|J^2|c,d> = \sum_J <J_a,M_a,J_b,M_b|Jtot,M_a+M_b>*<J_c,M_c,J_d,M_d|Jtot,M_c+M_d>*<(J_a,J_b)Jtot|J^2|(J_c,J_d)Jtot> = \sum_J <J_a,M_a,J_b,M_b|Jtot,M_a+M_b>*<J_c,M_c,J_d,M_d|Jtot,M_c+M_d>*Jtot(Jtot+1). The sum is over J even only. :param a: :param b: :param c: :param d: :return: """ if ((not comp_shell(a, c)) or (not comp_shell(b, d)) or (a.get_m_j() + b.get_m_j() != c.get_m_j() + d.get_m_j())): return 0 min_jab = abs(a.get_j() - b.get_j()) max_jab = a.get_j() + b.get_j() min_jcd = abs(c.get_j() - d.get_j()) max_jcd = c.get_j() + d.get_j() pauli = False N = 1 if (comp_shell(a, d) ^ comp_shell(b, c)): N = -1 if comp_shell(a, b): pauli = True N *= sqrt(2) if comp_shell(c, d): pauli = True N *= sqrt(2) contrib = 0 #if a == c and b == d: # contrib-=a.get_j()*0.5*(a.get_j()*0.5+1)+b.get_j()*0.5*(b.get_j()*0.5+1) for J_tot in range(max(min_jab, min_jcd), min(max_jab, max_jcd) + 1, 2): if pauli and (J_tot / 2) % 2 == 1: continue cg1 = clebsch_gordan( S(a.get_j()) / 2, S(b.get_j()) / 2, S(J_tot) / 2, S(a.get_m_j()) / 2, S(b.get_m_j()) / 2, S(a.get_m_j() + b.get_m_j()) / 2).evalf(15) cg2 = clebsch_gordan( S(c.get_j()) / 2, S(d.get_j()) / 2, S(J_tot) / 2, S(c.get_m_j()) / 2, S(d.get_m_j()) / 2, S(c.get_m_j() + d.get_m_j()) / 2).evalf(15) contrib += cg1 * cg2 * J_tot * 0.5 * (J_tot * 0.5 + 1) return contrib * N
def zeeman_me_fs(B: float, b_pol: SphericalVector, lo: moment, j: moment, mj: moment, jp: moment, mp: moment) -> float: """ Computes the matrix element between two states in the fine structure basis given a DC magnetic field. <a, lo, jp, mp | H_B | a, lo, j, mj> where H_B is the perturbing Hamiltonian due to the Zeeman effect and a abstracts away all other quantum numbers Args: B : magnitude of the magnetic field perturbing the atoms. (T) b_pol : SphericalVector describing the direction of the magnetic field. lo : orbital angular momentum quantum number of the states. Integer or half-integer j : fine structure angular momentum quantum number of the un-primed state. Integer or half-integer mj : azimuthal angular momentum quantum number of the un-primed state. Integer or half-integer jp : fine structure angular momentum quantum number of the primed state. Integer or half-integer mp : azimuthal angular momentum quantum number of the primed state. Integer or half-integer Returns: Matrix element between the states provided. (J) """ s = 0 for q in [-1, 0, 1]: for ms in [-1 / 2, 1 / 2]: ml = mj - ms if abs(ml) > lo: continue for msp in [-1 / 2, 1 / 2]: mlp = mp - msp if abs(mlp) > lo: continue # print(f"lo,j,mj,ml,ms,jp,mp,mlp,msp : {lo,j,mj,ml,ms,jp,mp,mlp,msp}") clgd = clebsch_gordan(lo, 1 / 2, jp, mlp, msp, mp) * clebsch_gordan( lo, 1 / 2, j, ml, ms, mj) # print(f"clgd : {clgd}") if ml != mlp: s_cont = 0 else: s_cont = gs * np.sqrt(3) / 2 * clebsch_gordan( 1, 1 / 2, 1 / 2, q, ms, msp) if ms != msp: l_cont = 0 else: l_cont = gl_cs * np.sqrt(lo * (lo + 1)) * clebsch_gordan( 1, lo, lo, q, ml, mlp) s += b_pol[-q] * clgd * (s_cont + l_cont) * (-1)**q # print(f"s : {s}") return B * mub * s
def PseudoPotential(n,l,m): sumrange = np.linspace(-l,l,int(2*l)+1,endpoint=True) result = 0.0 for m1 in sumrange: for m2 in sumrange: for m3 in sumrange: for m4 in sumrange: tmp = Kdelta(m1+m2,m3+m4)*Kdelta(m1+m2,2*l-m) #try: tmp*=clebsch_gordan(l,l,2*l-m,m1,m2,m1+m2)*clebsch_gordan(l,l,2*l-m,m3,m4,m3+m4)*DoubletTwoBodyElement(l-n,m4,m3,m2,m1,l) #except: # tmp*=0.0 result += tmp return result/math.sqrt(float(l-n))
def diamagnetic_1o_fs(B, n, lo, j, mj): """ Computes the diamagnetic response of a state |n, lo, j, mj> to a magnetic field along the quantization axis. TODO: perform the numerical integral so this works for Cesium not Hydrogen Args: B : Field strength of the perturbing magnetic field along the quantization axis (T) n : principle quantum number of the state lo : orbital angular momentum quantum number of the state. Integer or half-integer j : fine structure angular momentum quantum number of the state. Integer or half-integer mj : azimuthal angular quantum number of the state . Integer or half-integer Returns: Correction to the state's energy due to the diamagnetic term. (Hz) """ s = 0 for ms in np.arange(-1 / 2, 1 / 2 + 1, 1): ml = mj - ms if abs(ml) > lo: continue clgd = clebsch_gordan(lo, 1 / 2, j, ml, ms, mj)**2 dia = diamagnetic_1o(B, n, lo, ml) # print(dia / h) s += clgd * dia return s
def filter_molecular_states(atom, state1, state2, mol_angmon, F_cut, R0, n1_range, n2_range): # save states as tuples first, then convert into State classes # since I doubt that the set stuff will work correctly with classes newStates = set() E0 = abs(consts.c*(TermEnergy(atom, state1)[0] + TermEnergy(atom, state2)[0])) # Hz for ang_states in mol_angmon: #print ang_states p = ang_states[0][-1] - state1.mj dl1 = state1.l - ang_states[0][0] dl2 = state2.l - ang_states[1][0] if (abs(p)<=1) and (abs(dl1)==1) and (abs(dl2)==1): # rme database lookups l1b, j1b, mj1b = ang_states[0] l2b, j2b, mj2b = ang_states[1] # precalculate angular factors ang_factor = atom.AME(state1, State(0,l1b,j1b,mj1b), p) ang_factor *= atom.AME(state2, State(0,l2b,j2b,mj2b), -p) ang_factor *= clebsch_gordan(1,1,2,p,-p,0) # calculate threshold to add molecular state to the basis if ang_factor != 0: cut = abs(N(F_cut*R0**3/(ang_factor*atom.GHz_um3_factor*sqrt(6.0)))) #print("cut: {}".format(cut)) # now check all permutations of the n-levels in the range s1bs = [ [ (x[0],)+ang_states[0], x[1]] for x in atom.RMEs(state1,n1_range,l1b,j1b) ] s2bs = [ [ (x[0],)+ang_states[1], x[1]] for x in atom.RMEs(state2,n2_range,l2b,j2b) ] for ms in itertools.product(s1bs,s2bs): state1b = State(ms[0][0][0],ms[0][0][1],ms[0][0][2],ms[0][0][3]) state2b = State(ms[1][0][0],ms[1][0][1],ms[1][0][2],ms[1][0][3]) # check the energy first since its easier E = abs(consts.c*(TermEnergy(atom, state1b)[0] + TermEnergy(atom, state2b)[0])) # Hz if abs(ms[0][1]*ms[1][1]/((E-E0)*1e-9)) > cut: #print("E (GHz): {}".format((E-E0)*1e-9)) newStates.add((ms[0][0],ms[1][0])) return newStates
def dump_cg(tjmax, use_sympy=False): name = "cg" if use_sympy: import sympy.physics.wigner as spw name = "sym" + name for write in dump_output(name, tjmax): for tj1, tm1, tj2, tm2, tj12, tm12 in iter_12tjms(tjmax): if use_sympy: z = spw.clebsch_gordan( Fraction(tj1, 2), Fraction(tj2, 2), Fraction(tj12, 2), Fraction(tm1, 2), Fraction(tm2, 2), Fraction(tm12, 2), ) write("\t".join( map(str, ( tj1, tm1, tj2, tm2, tj12, tm12, show_signedsqrtfrac(z), ))) + "\n") else: s, r = clebschgordansq(tj1, tm1, tj2, tm2, tj12, tm12) write("\t".join( map(str, (tj1, tm1, tj2, tm2, tj12, tm12, "{0}/{1}".format( s * r.numerator, r.denominator)))) + "\n")
def expected_JJ2b(mp_basis): if (len(mp_basis[0]) != 2): print "Expects a 2 body basis" exit(1) mat = np.zeros((len(mp_basis), len(mp_basis))) for i, a in enumerate(mp_basis): min_jta = abs(a[0].get_j() - a[1].get_j()) max_jta = a[0].get_j() + a[1].get_j() paulia = False Na = 1 if comp_shell(a[0], a[1]): Na = sqrt(2) paulia = True for j, b in enumerate(mp_basis): min_jtb = abs(b[0].get_j() - b[1].get_j()) max_jtb = b[0].get_j() + b[1].get_j() Nb = 1 paulib = False if comp_shell(b[0], b[1]): Nb = sqrt(2) paulib = True if comp_shell(a[0], b[0]) and comp_shell(a[1], b[1]): for J_tot in range(max(min_jta, min_jtb), min(max_jta, max_jtb) + 1, 2): if (paulia or paulib) and (J_tot / 2) % 2 == 0: continue cg1 = clebsch_gordan( S(a[0].get_j()) / 2, S(a[1].get_j()) / 2, S(J_tot) / 2, S(a[0].get_m_j()) / 2, S(a[1].get_m_j()) / 2, S(a[0].get_m_j() + a[1].get_m_j()) / 2).evalf(15) if (abs(cg1) < 1e-5): continue cg2 = clebsch_gordan( S(b[0].get_j()) / 2, S(b[1].get_j()) / 2, S(J_tot) / 2, S(b[0].get_m_j()) / 2, S(b[1].get_m_j()) / 2, S(b[0].get_m_j() + b[1].get_m_j()) / 2).evalf(15) if (abs(cg2) < 1e-5): continue mat[i, j] += cg1 * cg2 * (J_tot * 0.5) * ( (J_tot) * 0.5 + 1) * Na * Nb return mat
def stark_interaction_Wigner_3j(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 field_orientation = 'parallel' elif not np.mod(field_angle, 180.0) == 0.0: # perpendicular fields field_orientation = 'perpendicular' 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 # Projection of spin, cannot change if abs(delta_L) == 1 and delta_S == 0 and \ ((field_orientation=='parallel' and delta_MJ == 0) or \ (field_orientation=='perpendicular' and abs(delta_MJ) == 1)): # For accumulating each element in the ML sum sum_ML = [] # Loop through all combination of ML for each state for MS_1 in np.arange(-state_1.S, state_1.S + 1): for MS_2 in np.arange(-state_2.S, state_2.S + 1): delta_MS = MS_1 - MS_2 # Change in projection of spin: 0, +/- 1 if ((field_orientation=='parallel' and abs(delta_MS) in [0]) or \ (field_orientation=='perpendicular' and abs(delta_MS) in [0,1])): ML_1 = state_1.M - MS_1 ML_2 = state_2.M - MS_2 if (abs(ML_1) <= state_1.L) and (abs(ML_2) <= state_2.L): _angular_overlap = angular_overlap( state_1.L, state_2.L, ML_1, ML_2, **kwargs) if _angular_overlap != 0.0: sum_ML.append(float(clebsch_gordan(state_1.L, state_1.S, state_1.J, ML_1, state_1.M - ML_1, state_1.M)) * \ float(clebsch_gordan(state_2.L, state_2.S, state_2.J, ML_2, state_2.M - ML_2, state_2.M)) * \ _angular_overlap) # Stark interaction return np.sum(sum_ML) * radial_overlap(state_1.n_eff, state_1.L, state_2.n_eff, state_2.L) else: return 0.0
def _interactionConstantsForCOM_Iteration(self): # no special internal c.o.m interaction constants for the Central ME factor = safe_racah(self.L_bra, self.L_ket, self._l, self._l_q, 2, self._L) if self.isNullValue(factor): return 0 factor *= float(clebsch_gordan(self._l, 2, self._l_q, 0, 0, 0)) return factor * np.sqrt(2 * self._l + 1)
def safe_clebsch_gordan(j1, j2, j3, m1, m2, m3): """ :args j1, j2, j3, m1, m2, m3 Calculates the Clebsch-Gordan coefficient < j1 m1, j2 m2 | j3 m3 >. Return float value for Zero Clebsh-Gordan coefficient, avoid Zero object """ return float(clebsch_gordan(j1, j2, j3, m1, m2, m3))
def dipole_trans_oper(l1, l2): from sympy import N n1, n2 = 2 * l1 + 1, 2 * l2 + 1 op = np.zeros((3, n1, n2), dtype=np.complex128) for i1, m1 in enumerate(range(-l1, l1 + 1)): for i2, m2 in enumerate(range(-l2, l2 + 1)): tmp1 = clebsch_gordan(l2, 1, l1, m2, -1, m1) tmp2 = clebsch_gordan(l2, 1, l1, m2, 1, m1) tmp3 = clebsch_gordan(l2, 1, l1, m2, 0, m1) tmp1, tmp2, tmp3 = N(tmp1), N(tmp2), N(tmp3) op[0, i1, i2] = (tmp1 - tmp2) * np.sqrt(2.0) / 2.0 op[1, i1, i2] = (tmp1 + tmp2) * 1j * np.sqrt(2.0) / 2.0 op[2, i1, i2] = tmp3 op_spin = np.zeros((3, 2 * n1, 2 * n2), dtype=np.complex128) for i in range(3): op_spin[i, 0:2 * n1:2, 0:2 * n2:2] = op[i] op_spin[i, 1:2 * n1:2, 1:2 * n2:2] = op[i] return op_spin
def test_clebsch_gordan1(): j_1 = S.Half j_2 = S.Half m = 1 j = 1 m_1 = S.Half m_2 = S.Half assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = S.Half j_2 = S.Half m = -1 j = 1 m_1 = Rational(-1, 2) m_2 = Rational(-1, 2) assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = S.Half j_2 = S.Half m = 0 j = 1 m_1 = S.Half m_2 = S.Half assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 0 j_1 = S.Half j_2 = S.Half m = 0 j = 1 m_1 = S.Half m_2 = Rational(-1, 2) assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(2) / 2 j_1 = S.Half j_2 = S.Half m = 0 j = 0 m_1 = S.Half m_2 = Rational(-1, 2) assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(2) / 2 j_1 = S.Half j_2 = S.Half m = 0 j = 1 m_1 = Rational(-1, 2) m_2 = S.Half assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(2) / 2 j_1 = S.Half j_2 = S.Half m = 0 j = 0 m_1 = Rational(-1, 2) m_2 = S.Half assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == -sqrt(2) / 2
def test_clebsch_gordan1(): j_1 = S(1)/2 j_2 = S(1)/2 m = 1 j = 1 m_1 = S(1)/2 m_2 = S(1)/2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = S(1)/2 j_2 = S(1)/2 m = -1 j = 1 m_1 = -S(1)/2 m_2 = -S(1)/2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = S(1)/2 j_2 = S(1)/2 m = 0 j = 1 m_1 = S(1)/2 m_2 = S(1)/2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 0 j_1 = S(1)/2 j_2 = S(1)/2 m = 0 j = 1 m_1 = S(1)/2 m_2 = -S(1)/2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(2)/2 j_1 = S(1)/2 j_2 = S(1)/2 m = 0 j = 0 m_1 = S(1)/2 m_2 = -S(1)/2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(2)/2 j_1 = S(1)/2 j_2 = S(1)/2 m = 0 j = 1 m_1 = -S(1)/2 m_2 = S(1)/2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(2)/2 j_1 = S(1)/2 j_2 = S(1)/2 m = 0 j = 0 m_1 = -S(1)/2 m_2 = S(1)/2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == -sqrt(2)/2
def test_clebsch_gordan1(): j_1 = S(1) / 2 j_2 = S(1) / 2 m = 1 j = 1 m_1 = S(1) / 2 m_2 = S(1) / 2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = S(1) / 2 j_2 = S(1) / 2 m = -1 j = 1 m_1 = -S(1) / 2 m_2 = -S(1) / 2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = S(1) / 2 j_2 = S(1) / 2 m = 0 j = 1 m_1 = S(1) / 2 m_2 = S(1) / 2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 0 j_1 = S(1) / 2 j_2 = S(1) / 2 m = 0 j = 1 m_1 = S(1) / 2 m_2 = -S(1) / 2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(2) / 2 j_1 = S(1) / 2 j_2 = S(1) / 2 m = 0 j = 0 m_1 = S(1) / 2 m_2 = -S(1) / 2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(2) / 2 j_1 = S(1) / 2 j_2 = S(1) / 2 m = 0 j = 1 m_1 = -S(1) / 2 m_2 = S(1) / 2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(2) / 2 j_1 = S(1) / 2 j_2 = S(1) / 2 m = 0 j = 0 m_1 = -S(1) / 2 m_2 = S(1) / 2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == -sqrt(2) / 2
def test_clebsch_gordan2(): j_1 = S(1) j_2 = S(1) / 2 m = S(3) / 2 j = S(3) / 2 m_1 = 1 m_2 = S(1) / 2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = S(1) j_2 = S(1) / 2 m = S(1) / 2 j = S(3) / 2 m_1 = 1 m_2 = -S(1) / 2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 / sqrt(3) j_1 = S(1) j_2 = S(1) / 2 m = S(1) / 2 j = S(1) / 2 m_1 = 1 m_2 = -S(1) / 2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(2) / sqrt(3) j_1 = S(1) j_2 = S(1) / 2 m = S(1) / 2 j = S(1) / 2 m_1 = 0 m_2 = S(1) / 2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == -1 / sqrt(3) j_1 = S(1) j_2 = S(1) / 2 m = S(1) / 2 j = S(3) / 2 m_1 = 0 m_2 = S(1) / 2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(2) / sqrt(3)
def test_clebsch_gordan2(): j_1 = S(1) j_2 = S(1)/2 m = S(3)/2 j = S(3)/2 m_1 = 1 m_2 = S(1)/2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = S(1) j_2 = S(1)/2 m = S(1)/2 j = S(3)/2 m_1 = 1 m_2 = -S(1)/2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1/sqrt(3) j_1 = S(1) j_2 = S(1)/2 m = S(1)/2 j = S(1)/2 m_1 = 1 m_2 = -S(1)/2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(2)/sqrt(3) j_1 = S(1) j_2 = S(1)/2 m = S(1)/2 j = S(1)/2 m_1 = 0 m_2 = S(1)/2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == -1/sqrt(3) j_1 = S(1) j_2 = S(1)/2 m = S(1)/2 j = S(3)/2 m_1 = 0 m_2 = S(1)/2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(2)/sqrt(3)
def dipole_rabi_frequency( electric_field: complex, q: SphericalVector, d_rme: complex, j: moment, m: moment, jp: moment, mp: moment, ) -> complex: """ Computes rabi frequency between two states zeeman states given electric field strength and the reduced dipole moment between them. Our two states can be described as |a,j,m> and |ap,jp,mp> where p represents primed states, and a/ap correspond to unaccounted for quantum numbers between the states. The returned value is given by the Wigner–Eckart theorem. rabi_frequency = electric_field/hb * c_a * clebsch_gordan(1, jp, j, q_a, mp, m) * d / sqrt(2*jp+1) where: hb = reduced planck constant, as provided in constants.py c_a = weight of polarization that is allowed for dipole coupling between m and mp q_a = polarization that is allowed for dipole coupling between m and mp clebsch_gordan = function from sympy.physics.wigner Args: electric_field : electric field amplitude of the oscillating field coupling two states (V/m) q : length three list describing the relative polarization of the oscillating field in the spherical basis Components should be indexed [e_0, e_+1, e_-1]. d_rme : reduced dipole matrix element between the states (Cm) j : angular momentum quantum number for initial state. Int or half-int. m : zeeman state quantum number for initial state. Int or half-int. jp : angular momentum quantum number for primed state. Int or half-int. mp : zeeman state quantum number for primed state. Int or half-int. Returns: rabi frequency coupling |a,j,m> and |ap,jp,mp> in Hz (assuming values passed in were in correct units) """ q_a = mp-m # dipole allowed field polarization if abs(q_a) > 1: # dipole only allows change of 1 return 0 # proportion of field in that polarization state c_a = q[int(q_a)] # print(f"m-mp:{q_a},polarization_array:{q},c_a:{c_a}") return N( electric_field / hb * c_a * clebsch_gordan(1, j, jp, q_a, m, mp) * d_rme / np.sqrt(2 * jp + 1) )
def compute_s(self, shell): shell = shell.copy() shell.m_j = 1 / 2 in_states = self.nucleus1.get_eigenstates() out_states = self.nucleus2.get_eigenstates() in_j = self.nucleus1.get_total_j() out_j = self.nucleus2.get_total_j() in_basis = self.nucleus1.get_m_scheme_basis() out_basis = self.nucleus2.get_m_scheme_basis() # Enough to compute it for m = 1/2 and then use Wigner-Eckart # Therefore the code now determines which states contains shell filtered_in_basis = [ (list(out_basis).index(np.array([s for s in state if s != shell])), i, list(state).index(shell)) for i, state in enumerate(np.transpose(in_basis)) if shell in state ] print("filtered_in_basis = {}".format(filtered_in_basis)) print in_basis #for i in xrange(len(in_basis)): # if shell in in_basis( specs = [] #for i,inv in enumerate(in_states): i = 0 inv = in_states[:, 0] cur_specs = [] for j in xrange(len(out_states)): outv = out_states[:, j] print "|{1}-{2}|<={0}<={1}+{2}".format(shell.get_j() / 2.0, in_j[i], out_j[j]) if shell.get_j() <= 2 * abs(in_j[i] - out_j[j]) or shell.get_j( ) >= 2 * (in_j[i] + out_j[j]): continue Sm = np.sum( np.array([ outv[comp[0]] * inv[comp[1]] * ((-1)**comp[2]) for comp in filtered_in_basis ])) print "Sm = {}".format(Sm) cur_specs.append((Sm / (clebsch_gordan( S(int(2 * out_j[j])) / 2, S(shell.get_j()) / 2, S(int(2 * in_j[i])) / 2, S(self.nucleus2.get_m()) / 2, S(shell.get_m_j()) / 2, S(self.nucleus1.get_m()) / 2).evalf(10)))**2) specs.append(cur_specs) return specs
def hf_zeeman(states, gJ, gI, Bz=None, units='Joules'): """ Return Zeeman Hamiltonian in hyperfine basis |L J I F mF>. Assumes the field is along the z axis, i.e. q = 0. 'states': list-like, pair of quantum states given by [I,J,F,mF,FF,mFF] If Bz is none initially, the sympy free_symbol is the magnetic dipole energy, uB*B, not just B. 'units': 'Joules' (default), 'eV', 'UB' (units of the magnetic dipole energy). From Mark's notes for the general hf Zeeman matrix elements. Units are determined by UB. Could implement decorator function to change units. """ ## TODO: build in better unit functionality or remove option to choose units I, J, F, mF, FF, mFF = states q = 0 # assume B = Bz for now elem = 0 if mF == mFF: # q=0 => selection rule mF = mF' elem += N(clebsch_gordan(F,1,FF,mF,q,mFF) \ *sqrt(2*F+1)*(-1)**(1+J+I) \ *(gJ*(-1)**F*sqrt(J*(J+1)*(2*J+1)) \ *wigner_6j(J,I,F,FF,1,J) \ +gI*(-1)**FF*sqrt(I*(I+1)*(2*I+1)) \ *wigner_6j(I,J,F,FF,1,I))) # N() is used to ensure diagnolization doesn't get tripped up if Bz is not None: elem *= uB * Bz # hmm check the sign if units == 'Joules': return elem elif units == 'eV': return JToeV(elem) elif units == 'GHz': return eVToGHz(JToeV(elem)) else: print(f"invalid unit [{units}] for non-zero Bz. Result in 'J'.") return elem else: if units == 'UB': return elem else: UB = symbols('U_B') # symbolic B field P.E. for now elem *= UB return elem
def test_clebsch_gordan3(): j_1 = S(3) / 2 j_2 = S(3) / 2 m = S(3) j = S(3) m_1 = S(3) / 2 m_2 = S(3) / 2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = S(3) / 2 j_2 = S(3) / 2 m = S(2) j = S(2) m_1 = S(3) / 2 m_2 = S(1) / 2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 / sqrt(2) j_1 = S(3) / 2 j_2 = S(3) / 2 m = S(2) j = S(3) m_1 = S(3) / 2 m_2 = S(1) / 2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 / sqrt(2)
def test_clebsch_gordan5(): j_1 = S(5) / 2 j_2 = S(1) m = S(7) / 2 j = S(7) / 2 m_1 = S(5) / 2 m_2 = 1 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = S(5) / 2 j_2 = S(1) m = S(5) / 2 j = S(5) / 2 m_1 = S(5) / 2 m_2 = 0 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(5) / sqrt(7) j_1 = S(5) / 2 j_2 = S(1) m = S(3) / 2 j = S(3) / 2 m_1 = S(1) / 2 m_2 = 1 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 / sqrt(15)
def diamagnetic_1o(Bz: float, n: int, lo: moment, m: moment) -> float: """ Computes the diamagnetic response of an atom to a magnetic field along the quantization axis, to first order. TODO: perform the numerical integral so this works for Cesium not Hydrogen Args: Bz : Magnetic field strength perturbing the atom, along the quantization axis n : principle quantum number lo : orbital angular momentum quantum number of the state. Should be an integer or half-integer m : azimuthal angular momentum quantum number of the state. Should be an integer or half-integer Returns: <H_diamag> : diagonal matrix element of the diamagnetic response of an atom to a magnetic field. (J) """ rsq = n**2 * (5 * n**2 + 1 - 3 * lo * (lo + 1)) / 2 # True for hydrogen, need cs function sn_lm = 2 / 3 * (1 - clebsch_gordan(lo, 2, lo, 0, 0, 0) * clebsch_gordan(lo, 2, lo, m, 0, m)) return (mub * Bz)**2 / (Eh * 4) * rsq * sn_lm
def test_clebsch_gordan5(): j_1 = Rational(5, 2) j_2 = S.One m = Rational(7, 2) j = Rational(7, 2) m_1 = Rational(5, 2) m_2 = 1 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = Rational(5, 2) j_2 = S.One m = Rational(5, 2) j = Rational(5, 2) m_1 = Rational(5, 2) m_2 = 0 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(5) / sqrt(7) j_1 = Rational(5, 2) j_2 = S.One m = Rational(3, 2) j = Rational(3, 2) m_1 = S.Half m_2 = 1 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 / sqrt(15)
def test_clebsch_gordan3(): j_1 = Rational(3, 2) j_2 = Rational(3, 2) m = S(3) j = S(3) m_1 = Rational(3, 2) m_2 = Rational(3, 2) assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = Rational(3, 2) j_2 = Rational(3, 2) m = S(2) j = S(2) m_1 = Rational(3, 2) m_2 = S.Half assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 / sqrt(2) j_1 = Rational(3, 2) j_2 = Rational(3, 2) m = S(2) j = S(3) m_1 = Rational(3, 2) m_2 = S.Half assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 / sqrt(2)
def test_clebsch_gordan4(): j_1 = S(2) j_2 = S(2) m = S(4) j = S(4) m_1 = S(2) m_2 = S(2) assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = S(2) j_2 = S(2) m = S(3) j = S(3) m_1 = S(2) m_2 = 1 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 / sqrt(2) j_1 = S(2) j_2 = S(2) m = S(2) j = S(3) m_1 = 1 m_2 = 1 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 0
def quadrupole_rabi_frequency( electric_field: complex, frequency: float, q_ar: SphericalVector, k_ar: SphericalVector, q_rme: complex, j: moment, m: moment, jp: moment, mp: moment ) -> complex: """ Computes the rabi frequency between two zeeman states given the electric field strength, reduced quadrupole moment between them, the field polarization, and the field k-vector polarization. The two zeeman states can be denoted as |a, j, m> and |ap, jp, mp>, where p denotes primed states, and a/ap abstract away all unaccounted for quantum numbers that describe the states. Args: electric_field : electric field amplitude of the oscillating field coupling two states (V/m) frequency : radial oscillation frequency of the field coupling the two states (Hz) q_ar : length three list describing the relative polarization of the oscillating field in the spherical basis. Components should be indexed [e_0, e_+1, e_-1]. k_ar : length three list describing the relative polarizatio of the oscillating field's k-vector in the spherical basis. Components should be indexed [e_0, e_+1, e_-1] q_rme : reduced quadrupole matrix element between the states (Cm^2) j : angular momentum quantum number for initial state. Int or half-int. m : zeeman state quantum number for initial state. Int or half-int. jp : angular momentum quantum number for primed state. Int or half-int. mp : zeeman state quantum number for primed state. Int or half-int. Returns: """ def m_q(qs: SphericalVector, ks: SphericalVector, q: int) -> float: ret = 0 for moo in range(-1, 2): # supposed to be $\mu$ for nuu in range(-1, 2): # supposed to be $\nu$ ret += clebsch_gordan(1, 1, 2, moo, nuu, -q)*ks[moo]*qs[nuu] return (-1)**q * np.sqrt(10) * ret pre = 1j * k_mag(frequency*2*pi) * electric_field * q_rme / (hb * np.sqrt(2 * jp + 1)) # print(pre) # print(electric_field) # print(f"f = {frequency*1e-12}THz") # print(f"k = {k_mag(frequency*2*pi)}m^-1") m_sum = sum([m_q(q_ar, k_ar, q)*clebsch_gordan(2, j, jp, q, m, mp) for q in range(-2, 3)]) return complex(N(pre * m_sum))
def filter_molecular_states(atom, state1, state2, mol_angmon, F_cut, R0, n1_range, n2_range): # save states as tuples first, then convert into State classes # since I doubt that the set stuff will work correctly with classes newStates = set() E0 = abs(consts.c * (TermEnergy(atom, state1)[0] + TermEnergy(atom, state2)[0])) # Hz for ang_states in mol_angmon: #print ang_states p = ang_states[0][-1] - state1.mj dl1 = state1.l - ang_states[0][0] dl2 = state2.l - ang_states[1][0] if (abs(p) <= 1) and (abs(dl1) == 1) and (abs(dl2) == 1): # rme database lookups l1b, j1b, mj1b = ang_states[0] l2b, j2b, mj2b = ang_states[1] # precalculate angular factors ang_factor = atom.AME(state1, State(0, l1b, j1b, mj1b), p) ang_factor *= atom.AME(state2, State(0, l2b, j2b, mj2b), -p) ang_factor *= clebsch_gordan(1, 1, 2, p, -p, 0) # calculate threshold to add molecular state to the basis if ang_factor != 0: cut = abs( N(F_cut * R0**3 / (ang_factor * atom.GHz_um3_factor * sqrt(6.0)))) #print("cut: {}".format(cut)) # now check all permutations of the n-levels in the range s1bs = [[(x[0], ) + ang_states[0], x[1]] for x in atom.RMEs(state1, n1_range, l1b, j1b)] s2bs = [[(x[0], ) + ang_states[1], x[1]] for x in atom.RMEs(state2, n2_range, l2b, j2b)] for ms in itertools.product(s1bs, s2bs): state1b = State(ms[0][0][0], ms[0][0][1], ms[0][0][2], ms[0][0][3]) state2b = State(ms[1][0][0], ms[1][0][1], ms[1][0][2], ms[1][0][3]) # check the energy first since its easier E = abs(consts.c * (TermEnergy(atom, state1b)[0] + TermEnergy(atom, state2b)[0])) # Hz if abs(ms[0][1] * ms[1][1] / ((E - E0) * 1e-9)) > cut: #print("E (GHz): {}".format((E-E0)*1e-9)) newStates.add((ms[0][0], ms[1][0])) return newStates
def hf_coupling(F, mF, J, q, FF, mFF, JJ, I, RME=None): """ Returns the matrix element <F,mF,J|T_q|F',mF',J'>. 'RME': the reduced matrix element, e.g. the D2 line matrix element. If RME=None, the matrix element is in units of [RME]. I is the nuclear spin of the atom. """ rme = 1 if RME != None: rme = RME ## From Mark's notes, eqs. A-50,51 mat_elem = rme*pow(-1,F+JJ+1+I)*sqrt((2*F+1)*(2*JJ+1)) \ *wigner_6j(J,I,F,FF,1,JJ) \ *clebsch_gordan(1,F,FF,q,mF,mFF) return mat_elem
def F(k, jf, l1, l2, ji): verbose = False # cg_coeff_homebrew = float(clebsch_gordan(l1, 1, l2, -1, k, 0)) # works, but takes arguments in different order compared to the sympy version cg_coeff = float(wg.clebsch_gordan(l1, l2, k, 1, -1, 0)) if cg_coeff == 0: return 0 w = float(wg.racah(ji, ji, l1, l2, k, jf)) # w = racah_w(ji, ji, l1, l2, k, jf) # returning strange values if w == 0: return 0 if verbose: print(f'GC: {cg_coeff} W: {w}') return pow( (-1), (jf - ji - 1)) * (pow((2 * l1 + 1) * (2 * l2 + 1) * (2 * ji + 1), (1.0 / 2.0))) * cg_coeff * w
def hf_coupling(F, mF, J, q, FF, mFF, JJ, I): """ Returns the constant relating matrix element <J,mJ|T_q|J',mJ'> to the reduced fine structure matrix element. Args: I is the nuclear spin of the atom. Returns: 'coupling': ## From Mark's notes, eqs. A-50,51. Also see Steck Rb datasheet. mat_elem = rme*pow(-1,F+JJ+1+I)*sqrt((2*F+1)*(2*JJ+1)) \ *wigner_6j(J,I,F,FF,1,JJ) \ *clebsch_gordan(1,F,FF,q,mF,mFF) """ ## From Mark's notes, eqs. A-50,51 coupling = pow(-1,F+JJ+1+I)*sqrt((2*F+1)*(2*JJ+1)) \ *wigner_6j(J,I,F,FF,1,JJ) \ *clebsch_gordan(1,F,FF,q,mF,mFF) return coupling
def c3(self, stateI1, stateI2, stateF1, stateF2): # electric dipole transitions #print stateI1 #print stateI2 if(abs(stateI1.l-stateF1.l) != 1): #print(1,stateI1, stateF1, stateI1.l, stateF1.l) return 0 if(abs(stateI2.l-stateF2.l) != 1): #print(2,stateI2, stateF2, stateI2.l, stateF2.l) return 0 p = stateF1.mj - stateI1.mj # -1,0,+1 if abs(p)>1: return 0 if stateI2.mj - stateF2.mj != p: # dmj = 0 return 0 a = self.AME(stateI1, stateF1, p)*self.RME(stateI1, stateF1)[0] b = self.AME(stateI2, stateF2, -p)*self.RME(stateI2, stateF2)[0] c = clebsch_gordan(1,1,2,p,-p,0) return [N(-self.GHz_um3_factor*sqrt(6)*c*a*b), 'GHz/um**3', None]
def dump_cg(tjmax, use_sympy=False): name = "cg" if use_sympy: import sympy.physics.wigner as spw name = "sym" + name for write in dump_output(name, tjmax): for tj1, tm1, tj2, tm2, tj12, tm12 in iter_12tjms(tjmax): if use_sympy: z = spw.clebsch_gordan( Fraction(tj1, 2), Fraction(tj2, 2), Fraction(tj12, 2), Fraction(tm1, 2), Fraction(tm2, 2), Fraction(tm12, 2), ) write("\t".join(map(str, ( tj1, tm1, tj2, tm2, tj12, tm12, show_signedsqrtfrac(z), ))) + "\n") else: s, r = clebschgordansq(tj1, tm1, tj2, tm2, tj12, tm12) write("\t".join(map(str, ( tj1, tm1, tj2, tm2, tj12, tm12, "{0}/{1}".format(s * r.numerator, r.denominator) ))) + "\n")
def c3(self, stateI1, stateI2, stateF1, stateF2): # electric dipole transitions #print stateI1 #print stateI2 if (abs(stateI1.l - stateF1.l) != 1): #print(1,stateI1, stateF1, stateI1.l, stateF1.l) return 0 if (abs(stateI2.l - stateF2.l) != 1): #print(2,stateI2, stateF2, stateI2.l, stateF2.l) return 0 p = stateF1.mj - stateI1.mj # -1,0,+1 if abs(p) > 1: return 0 if stateI2.mj - stateF2.mj != p: # dmj = 0 return 0 a = self.AME(stateI1, stateF1, p) * self.RME(stateI1, stateF1)[0] b = self.AME(stateI2, stateF2, -p) * self.RME(stateI2, stateF2)[0] c = clebsch_gordan(1, 1, 2, p, -p, 0) return [ N(-self.GHz_um3_factor * sqrt(6) * c * a * b), 'GHz/um**3', None ]
def f_coupling(L, J, mJ, q, LL, JJ, mJJ, I): """ Returns the constant relating matrix element <J,mJ|T_q|J',mJ'> to the reduced fine structure matrix element. Args: 'RME': the reduced matrix element <alpha;J||r||alpha'J'> with alpha including quantum numbers not relevant to the coupling, e.g. n. If RME=None, the matrix element is in units of [RME]. I is the nuclear spin of the atom. Returns: 'mat_elem': ## From Mark's notes, eqs. A-50,51. Also see Steck Rb datasheet. mat_elem = rme*pow(-1,F+JJ+1+I)*sqrt((2*F+1)*(2*JJ+1)) \ *wigner_6j(J,I,F,FF,1,JJ) \ *clebsch_gordan(1,F,FF,q,mF,mFF) """ ## From Mark's notes, eqs. A-50,51 mat_elem = clebsch_gordan(1, J, JJ, q, mJ, mJJ) return mat_elem
def cg(*args): return float(wigner.clebsch_gordan(*args))
def doit(self, **hints): if self.is_symbolic: raise ValueError("Coefficients must be numerical") return clebsch_gordan(self.j1,self.j2, self.j3, self.m1, self.m2, self.m3)
def test_clebsch_gordan_docs(): assert clebsch_gordan(S(3)/2, S(1)/2, 2, S(3)/2, S(1)/2, 2) == 1 assert clebsch_gordan(S(3)/2, S(1)/2, 1, S(3)/2, -S(1)/2, 1) == sqrt(3)/2 assert clebsch_gordan(S(3)/2, S(1)/2, 1, -S(1)/2, S(1)/2, 0) == -sqrt(2)/2