{-|
Module      : TBit.Topological.Spillage
Description : calculate spin-orbit and other spillages
Copyright   : (c) Matthew Daniels, 2014
License     : New BSD
Maintainer  : danielsmw@gmail.com
Stability   : experimental

Provide routines for determining the spillage, and in particular
Vanderbilt and Liu's spin-orbit spillage, given a Hamiltonian whose
spin-orbit coupling term can be turned on and off.
-}
module TBit.Topological.Spillage (spillage) where

import TBit.Types
import TBit.Parameterization (crunch, getScalar)
import TBit.Hamiltonian.Eigenstates (eigenbras,eigenkets)
import Debug.Trace

import Numeric.LinearAlgebra.HMatrix ((<>), fromBlocks, size, (!), Matrix)

import Control.Monad (liftM)
import Control.Monad.State

import Data.Map (adjust)
import Data.Complex

                        
spillage :: String -> Filling -> Parameterized Hamiltonian -> Wavevector -> Parameterized Double
spillage ps n m k = do h' <- (modify (setScalar ps 0) >> m)
                       h  <- m
                       s  <- spillMatrix h h' k
                       return $ (fromIntegral n) 
                              - sum [ (realPart $ abs $ s!j!k)^2 
                                      | j <- [0 .. pred n]
                                      , k <- [0 .. pred n]]
    where setScalar str val ps = ps { scalarParams = adjust (\_ -> val :+ 0.0) str 
                                                   $ scalarParams ps }
                                                   
spillMatrix :: Hamiltonian 
            -> Hamiltonian 
            -> Wavevector
            -> Parameterized (Matrix (Complex Double))
spillMatrix h h' k = do es  <- eigenkets h  k
                        es' <- eigenbras h' k
                        let dim = fst . size . h $ k
                        return $ fromBlocks
                               $ [[ (es'!!m) <> (es!!n) | m <- [0 .. pred dim]]
                                                        | n <- [0 .. pred dim]]
