module TBit.Magnetic.OrbitalMagnetization ( orbMag , dichroism , dichroicIntegrand , intrinsicOM , integrandMk , bandIntrinsicOM ) where import TBit.Types import TBit.Framework import TBit.Hamiltonian.Eigenstates import TBit.Numerical.Derivative import TBit.Parameterization import Data.List.Stream (delete) import Control.Monad.Except import Prelude hiding (mapM, sequence) import Numeric.LinearAlgebra.HMatrix -- |Returns the total orbital magnetization due to filling the first -- n bands. orbMag :: Filling -> Hamiltonian -> Parameterized Magnetization orbMag n h = bzIntegral (integrandOM n h) -- |Returns the gauge-invariant self-rotational orbital magnetization, i.e. -- the circular dichroism, of the occupied bands, accomplished by integrating -- 'dichroicIntegrand'. dichroism :: Filling -> Hamiltonian -> Parameterized Magnetization dichroism n h = bzIntegral (dichroicIntegrand n h) -- |Returns the intrinsic orbital magnetization of the n/th/ band, namely -- the integral of _m_(k) from (Xiao et al., 2005). bandIntrinsicOM :: BandIndex -> Hamiltonian -> Parameterized Magnetization bandIntrinsicOM n h = bzIntegral (integrandMk n h) -- |Sums 'bandIntrinsicOM' over the first n bands. intrinsicOM :: Filling -> Hamiltonian -> Parameterized Magnetization intrinsicOM n h = liftM sum $ sequence [ bandIntrinsicOM j h | j <- [0 .. pred n] ] -- |Essentially equation (12) from PRB _77_, 054438 (2008) with alpha, beta set -- to x, y respectively so as to give the z-component of the (expectation -- value of) the circular dichroism pseudovector. This form takes a double sum over -- occupied and then unoccupied states, which improves over the implementation of -- 'integrandMk' by allowing for intra-(un)occupied band degeneracies as long as -- there is still an electronic band gap. -- -- As is consistent with our API for these types of functions, the -- 'TBit.Types.Filling' argument should be a positive integer counting the -- number of filled bands. dichroicIntegrand :: Filling -> Hamiltonian -> Wavevector -> Parameterized Magnetization dichroicIntegrand b h k = do ket <- eigenkets h k bra <- eigenbras h k eng <- eigenenergies h k (Spacing s) <- getMesh return . negate . imagPart . sum $ zipWith (/) [ num $ (bra!!n) <> hx s <> (ket!!m) <> (bra!!m) <> hy s <> (ket!!n) | m <- occ , n <- unocc ] [ (eng!!m - eng!!n) :+ 0.0 | m <- occ , n <- unocc ] where num m = m ! 0 ! 0 occ = [0 .. pred b] unocc = [b .. pred dim] dim = fst $ size $ h k twice = (*) 2.0 kx = k ! 0 ky = k ! 1 hx s = diff (s :+ 0.0) (\x -> h $ vector [realPart x, ky]) (kx :+ 0.0) hy s = diff (s :+ 0.0) (\y -> h $ vector [kx, realPart y]) (ky :+ 0.0) -- |Gives the gauge-invariant self-rotational orbital magnetism, which is -- proportional to the circular dichroism for a particular band index. -- This is m(k) in Xiao et al's semiclassical approach (hence the name). integrandMk :: BandIndex -> Hamiltonian -> Wavevector -> Parameterized Magnetization integrandMk n h k = do ket <- eigenkets h k bra <- eigenbras h k eng <- eigenenergies h k (Spacing s) <- getMesh if (close eng n (pred n)) || (close eng n (succ n)) then throwError $ UndefinedError (degenErr eng) else return $ imagPart . sum $ zipWith (/) [ num $! (bra!!m) <> hx s <> (ket!!n) <> (bra!!n) <> hy s <> (ket!!m) | m <- delete n [0 .. pred dim]] [ (eng!!n - eng!!m) :+ 0.0 | m <- delete n [0 .. pred dim]] where num m = m ! 0 ! 0 dim = fst $ size $ h k kx = k ! 0 ky = k ! 1 eps = 0.000000001 hx s = diff (s :+ 0.0) (\x -> h $ vector [realPart x, ky]) (kx :+ 0.0) hy s = diff (s :+ 0.0) (\y -> h $ vector [kx, realPart y]) (ky :+ 0.0) close _ (-1) _ = False close _ _ (-1) = False close eng i j = (abs $ eng!!i - eng!!j) < eps degenErr eng = case (close eng n (pred n), close eng n (succ n)) of (True, _) -> errMsg $ pred n (_, True) -> errMsg $ succ n otherwise -> "This error was in error." errMsg j = "Cannot integrate Berry curvature due to a gap " ++"closing between bands "++(show $ succ j)++" and " ++(show $ succ n)++"." -- |The full orbital magnetization for a particular wavevector; integrating over -- the Brillouin zone would give the actual OM due to a particular band filling. integrandOM :: Filling -> Hamiltonian -> Wavevector -> Parameterized Magnetization integrandOM n h k = do ket <- eigenkets h k bra <- eigenbras h k eng <- eigenenergies h k (Spacing s) <- getMesh if any (< eps) (diffs eng) then throwError $ UndefinedError (degenErr eng) else return $ imagPart . sum $ zipWith (/) [ (*) ((eng!!m + eng!!l) :+ 0.0) . num $! (bra!!m) <> hx s <> (ket!!l) <> (bra!!l) <> hy s <> (ket!!m) | m <- occ , l <- unocc ] [ (eng!!m - eng!!l)^2 :+ 0.0 | m <- occ , l <- unocc ] where num m = m ! 0 ! 0 occ = [0 .. pred n] unocc = [n .. pred dim] dim = fst $ size $ h k diffs eng = [ abs $ (eng!!m) - (eng!!l) | m <- occ, l <- unocc ] kx = k ! 0 ky = k ! 1 eps = 0.000000001 hx s = diff (s :+ 0.0) (\x -> h $ vector [realPart x, ky]) (kx :+ 0.0) hy s = diff (s :+ 0.0) (\y -> h $ vector [kx, realPart y]) (ky :+ 0.0) degenErr eng = let (j,l,_) = head $ filter (\(_,_,z) -> (z < eps)) $ [ (m,p,abs $ eng!!m - eng!!p) | m <- occ, p <- unocc ] in "Cannot integrate Berry curvature due to a gap " ++"closing between bands "++(show $ succ j)++" and " ++(show $ succ l)++"."