1+ function rotation_unitary (J:: Real , n:: Vector{<:Real} , phi:: Real ):: Matrix{ComplexF64}
2+ Jx = spin_operators (J, " x" )
3+ Jy = spin_operators (J, " y" )
4+ Jz = spin_operators (J, " z" )
5+ nnorm = normalize (n)
6+ Jproj = sum (nnorm .* [Jx, Jy, Jz])
7+ U = exp (- 1im * phi * Jproj)
8+ @assert isunitary (U)
9+ return U
10+ end
11+
12+
13+ function ZYZ_rotmatrix (alpha:: Real , beta:: Real , gamma:: Real ):: Matrix{Float64}
14+ a, b, g = map (Float64, [alpha, beta, gamma])
15+ return Z_rot (a) * Y_rot (b) * Z_rot (g)
16+ end
17+
18+
19+ X_rot (theta:: Float64 ):: Matrix{Float64} = [1 0 0 ;
20+ 0 cos (theta) - sin (theta);
21+ 0 sin (theta) cos (theta)]
22+
23+
24+ Y_rot (theta:: Float64 ):: Matrix{Float64} = [cos (theta) 0 sin (theta);
25+ 0 1 0 ;
26+ - sin (theta) 0 cos (theta)]
27+
28+
29+ Z_rot (theta:: Float64 ):: Matrix{Float64} = [cos (theta) - sin (theta) 0 ;
30+ sin (theta) cos (theta) 0 ;
31+ 0 0 1 ]
32+
33+
34+ function get_euler_angles (v:: Vector{<:Real} ):: Tuple{Float64, Float64, Float64}
35+ if isequal (zeros (Real, 3 ), v)
36+ return (0.0 , 0.0 , 0.0 )
37+ end
38+ v_norm = v / norm (v)
39+ alpha = atan (v_norm[2 ], v_norm[1 ])# / pi * 180.0
40+ beta = atan ((v_norm[1 ]^ 2 + v_norm[2 ]^ 2 ), v_norm[3 ])# / pi * 180.0
41+ gamma = 0.0
42+ return (alpha, beta, gamma) # in radian
43+ end
44+
45+
46+ function wigner_D (l:: Int , alpha:: Real , beta:: Real , gamma:: Real ):: Matrix{ComplexF64}
47+ mdim = Int (2 * l+ 1 )
48+ ml = - l: 1 : l
49+ rotmat = Matrix {ComplexF64} (undef, (mdim, mdim))
50+ for (idmp, mm) in enumerate (ml)
51+ for (idm, mp) in enumerate (ml)
52+ rotmat[idmp, idm] = (- 1 )^ (mp - mm) * rotation_matrix_element (l, mm, mp, alpha, beta, gamma)
53+ end
54+ end
55+ return round .(rotmat, digits= SDIG)
56+ end
57+
58+
59+ function rotation_matrix_element (l:: Int , m:: Int , mp:: Int , alpha:: Real , beta:: Real , gamma:: Real ):: ComplexF64
60+ return exp (- 1.0im * mp* alpha) * small_d (l, mp, m, beta) * exp (- 1.0im * m* gamma)
61+ end
62+
63+
64+ function small_d (l:: Int , mp:: Int , m:: Int , beta:: Real ):: Float64
65+ if iszero (beta)
66+ return isequal (m, mp) * 1.0 # delta function d_m'm if beta=0
67+ end
68+ djmpm = 0.0
69+ smin = Int (maximum ([0 , - (m+ mp)]))
70+ smax = Int (minimum ([l- m, l- mp]))
71+ for s in smin: 1 : smax
72+ djmpm += (- 1 )^ (l- m- s)*
73+ ((cos (beta/ 2 ))^ (2 s+ mp+ m))*
74+ ((sin (beta/ 2 ))^ (2 l- 2 s- m- mp))*
75+ binomial (Int (l+ m), Int (l- mp- s))*
76+ binomial (Int (l- m), Int (s))
77+ end
78+ djmpm *= sqrt ((factorial (Int (l+ mp))* factorial (Int (l- mp)))/
79+ (factorial (Int (l+ m))* factorial (Int (l- m))))
80+ if isequal (djmpm, NaN ) || isequal (djmpm, Inf )
81+ err_message =
82+ " Matrix element djmpm is NaN or Inf!\n " *
83+ " Likely there's an issue in the inputted values of l, m or mp."
84+ @error err_message
85+ else
86+ return djmpm
87+ end
88+ end
89+
90+
91+ function rotate_blm (cefparams:: DataFrame , alpha:: Real , beta:: Real , gamma:: Real ):: DataFrame
92+ cefparams_rotated = DataFrame (B = Float64[], l = Int[], m = Int[])
93+ ls = sort (collect (Set (cefparams[:, :l ])))
94+ for l in ls
95+ S_matrix = rotate_stevens (l, alpha, beta, gamma)
96+ cefparams_ori = zeros (Float64, Int (2 l+ 1 )) # original CEF parameters
97+ cefparams_rot = zeros (ComplexF64, Int (2 l+ 1 )) # rotated CEF params (complex)
98+ cefparams_res = zeros (Float64, Int (2 l+ 1 )) # rotated CEF parameters (real)
99+ for (i, m) in enumerate (- l: 1 : l)
100+ try
101+ cefparams_ori[i] = cefparams[(cefparams. l .== l) .& (cefparams. m .== m), :B ][1 ]
102+ catch ex
103+ if isa (ex, BoundsError)
104+ cefparams_ori[i] = 0.0
105+ end
106+ end
107+ end
108+ # S * cefparams where cefparams is a (2l+1) vector
109+ cefparams_rot .= S_matrix * cefparams_ori
110+ @assert norm (imag (cefparams_rot)) < PREC
111+ cefparams_res .= real (cefparams_rot)
112+ append! (cefparams_rotated, DataFrame (" B" => cefparams_res, " l" => fill (l, Int (2 l+ 1 )), " m" => - l: 1 : l))
113+ end
114+ return cefparams_rotated
115+ end
116+
117+
118+ function rotate_stevens (l:: Int , alpha:: Real , beta:: Real , gamma:: Real ):: Matrix{ComplexF64}
119+ return transpose (inv (Alm_matrix (l))) * wigner_D (l, alpha, beta, gamma)' * transpose (Alm_matrix (l))
120+ end
121+
122+
123+ function Alm_matrix (l:: Int ):: Matrix{ComplexF64}
124+ alm_coeff = OffsetArray (SMatrix {6, 7} ([
125+ 1 1 / sqrt (2 ) 0 0 0 0 0 ;
126+ sqrt (6 ) 1 / 2 1 0 0 0 0 ;
127+ sqrt (10 ) sqrt (10 / 3 ) 1 / sqrt (3 ) sqrt (2 ) 0 0 0 ;
128+ 2 * sqrt (70 ) sqrt (7 / 2 ) sqrt (7 ) 1 / sqrt (2 ) 2 2 0 ;
129+ 6 * sqrt (14 ) 2 * sqrt (21 / 5 ) sqrt (3 / 5 ) 6 * sqrt (2 / 5 ) 2 / sqrt (5 ) 2 * sqrt (2 ) 0 ;
130+ 4 * sqrt (231 ) sqrt (22 ) 4 * sqrt (11 / 5 ) 2 * sqrt (11 / 5 ) 4 * sqrt (11 / 6 ) 2 / sqrt (3 ) 4 ;
131+ ]), 1 : 6 , 0 : 6 )
132+ a_matrix = OffsetArray (zeros (ComplexF64, (2 l+ 1 , 2 l+ 1 )), - l: l, - l: l)
133+ for m in - l: 1 : l
134+ if iszero (m)
135+ a_matrix[m, m] = alm_coeff[l, abs (m)]
136+ elseif m > 0
137+ a_matrix[m, - m] = alm_coeff[l, abs (m)]
138+ a_matrix[m, m] = alm_coeff[l, abs (m)] * (- 1 )^ abs (m)
139+ else
140+ a_matrix[m, - abs (m)] = alm_coeff[l, abs (m)] * 1im
141+ a_matrix[m, abs (m)] = alm_coeff[l, abs (m)] * (- 1 )^ m * - 1im
142+ end
143+ end
144+ return parent (a_matrix)
145+ end
0 commit comments