{-# LANGUAGE BangPatterns #-}

{-|

Gas-surface interaction models.

-}

module DSMC.Surface
    ( Reflector
    , Surface(..)
    , makeReflector
    )

where

import Control.Monad.ST

import System.Random.MWC
import System.Random.MWC.Distributions (normal)

import DSMC.Util.Constants
import DSMC.Util.Vector


-- | A function which takes PRNG state, molecular velocity, surface
-- normal and samples post-collisional wrt to impregnable wall
-- boundary condition.
type Reflector s = GenST s -> Vec3 -> Vec3 -> ST s Vec3


-- | Surface models.
data Surface = CLL { bodyTemperature :: !Double
                   -- ^ Absolute temperature of surface.
                   , alpha :: !Double
                   -- ^ Kinetic energy accomodation for normal
                   -- velocity component.
                   , sigma :: !Double
                   -- ^ Accomodation for tangential momentum.
                   } |
               -- ^ Cercignani-Lampis-Lord model.
               Diffuse { bodyTemperature :: !Double
                       -- ^ Absolute temperature of surface.
                       , mass :: !Double
                       -- ^ Mass of reflected molecules (usually equal
                       -- to that in incident flow).
                       } |
               -- ^ Diffuse reflection.
               Mirror
               -- ^ Surface with specular reflection.


-- | Produce reflector depending on surface type.
makeReflector :: Surface -> Reflector s
makeReflector (CLL t alphanor sigmatan) =
    let
        f = sqrt (2 * t * unigas)
        alphatan = sigmatan * (2 - sigmatan)
        cll :: Reflector s
        cll !g !n !vel =
            let
                !e1 = normalize $ n >< vel
                !e2 = normalize $ n >< e1
                !ui = -(vel .* n)
                !vi = vel .* e2
                !urm = ui * sqrt (1 - alphanor) / f
                !vrm = vi * (1 - sigmatan)
            in do
              !angle <- uniformR (0.0, pi * 2) g
              !angle' <- uniformR (0.0, pi * 2) g
              !v2 <- uniform g
              !v2' <- uniform g
              let !r = sqrt (- (alphatan * log v2))
                  !vr = r * (cos angle) * f + vrm
                  !wr = r * (sin angle) * f
                  !r' = sqrt (- (alphanor * log v2'))
                  !ur = sqrt (urm * urm + 2 * r' * urm * (cos angle') + r' * r') * f

              return $! ((e1 .^ wr) <+> (e2 .^ vr) <+> (n .^ ur))
        {-# INLINE cll #-}
    in
      cll

makeReflector Mirror =  \_ !v !n -> return $! v <-> (n .^ (v .* n) .^ 2)

makeReflector (Diffuse t m) =
    let
        s = sqrt $ boltzmann * t / m
        beta = 1 / (s * (sqrt 2))
        diffuse :: Reflector s
        diffuse g n vel =
            let
                e1 = normalize $ n >< vel
                e2 = normalize $ n >< e1
            in do
              w <- normal 0 s g
              v <- normal 0 s g
              u' <- uniform g
              let u = (sqrt (- (log u'))) / beta
              return $ (e1 .^ v) <+> (e2 .^ w) <+> (n .^ u)
        {-# INLINE diffuse #-}
    in
      diffuse
