module DSMC.Cells
(
Cells
, CellContents
, getCell
, cellMap
, Classifier
, classifyParticles
, Grid(..)
, makeUniformClassifier
, makeUniformIndexer
, GridMonad
, GridWares(..)
, runGrid
, cellVolumes
)
where
import Prelude hiding (Just, Nothing, Maybe)
import Control.Monad.ST
import Control.Monad.Trans.Reader
import Data.Strict.Maybe
import qualified Data.Array.Repa as R
import qualified Data.Array.Repa.Repr.Vector as R
import qualified Data.Vector.Unboxed as VU
import qualified Data.Vector.Unboxed.Mutable as VUM
import qualified Data.Vector as V
import Control.Parallel.Stochastic
import DSMC.Domain
import DSMC.Particles
import DSMC.Traceables
import DSMC.Util
import DSMC.Util.Vector
type CellContents = VU.Vector Particle
data Cells = Cells !CellContents !Int !(VU.Vector Int) !(VU.Vector Int)
type Classifier = Particle -> Int
getCell :: Cells
-> Int
-> Maybe CellContents
getCell !(Cells ens _ starts lengths) !n =
case (lengths VU.! n) of
0 -> Nothing
cl -> Just $ VU.slice (starts VU.! n) cl ens
cellMap :: (Int -> Maybe CellContents -> a) -> Cells -> R.Array R.D R.DIM1 a
cellMap f !cells@(Cells _ l _ _) =
R.fromFunction (R.ix1 $ l) (\(R.Z R.:. cellNumber) ->
f cellNumber $! getCell cells cellNumber)
classifyAll :: Classifier -> Ensemble -> (VU.Vector Int)
classifyAll classify ens = runST $ do
classes' <- R.computeP $ R.map classify ens
return $ R.toUnboxed classes'
classifyParticles :: (Int, Classifier)
-> Ensemble
-> Cells
classifyParticles (cellCount, classify) ens' = runST $ do
let ens = R.toUnboxed ens'
particleCount = VU.length ens
classes = classifyAll classify ens'
posns' <- VUM.replicate particleCount 0
lengths' <- VUM.replicate cellCount 0
iforM_ classes (\(particleNumber, cellNumber) -> do
pos <- VUM.unsafeRead lengths' cellNumber
VUM.unsafeWrite posns' particleNumber pos
VUM.unsafeWrite lengths' cellNumber (pos + 1)
return ())
posns <- VU.unsafeFreeze posns'
lengths <- VU.unsafeFreeze lengths'
let starts = VU.prescanl' (+) 0 lengths
classifiedIds' <- VUM.replicate particleCount 0
iforM_ classes (\(particleNumber, cellNumber) -> do
let i = (starts VU.! cellNumber) + (posns VU.! particleNumber)
VUM.unsafeWrite classifiedIds' i particleNumber
return ())
classifiedIds <- VU.unsafeFreeze classifiedIds'
classifiedEns <- R.computeP $
R.fromFunction
(R.ix1 $ particleCount)
(\(R.Z R.:. position) ->
ens VU.! (classifiedIds VU.! position))
return $ Cells (R.toUnboxed classifiedEns) cellCount starts lengths
data Grid = UniformGrid !Domain !Double !Double !Double
deriving Show
makeUniformClassifier :: Grid -> (Int, Classifier)
makeUniformClassifier (UniformGrid d@(Domain xmin _ ymin _ zmin _) hx hy hz) =
(xsteps * ysteps * zsteps, classify)
where
(w, l, h) = getDimensions d
xsteps = ceiling $ w / hx
ysteps = ceiling $ l / hy
zsteps = ceiling $ h / hz
classify ((x, y, z), _) =
let
nx = floor $ (x xmin) / hx
ny = floor $ (y ymin) / hy
nz = floor $ (z zmin) / hz
in
nx + ny * xsteps + nz * xsteps * ysteps
type Indexer = Int -> Point
makeUniformIndexer :: Grid -> Indexer
makeUniformIndexer (UniformGrid d@(Domain xmin _ ymin _ zmin _) hx hy hz) =
indefy
where
(w, l, _) = getDimensions d
xsteps = ceiling $ w / hx
ysteps = ceiling $ l / hy
zf = xsteps * ysteps
indefy i =
let
(nz, i') = i `divMod` zf
z = zmin + fromIntegral nz * hz + hz / 2
(ny, nx) = i' `divMod` ysteps
y = ymin + fromIntegral ny * hy + hy / 2
x = xmin + fromIntegral nx * hx + hx / 2
in
(x, y, z)
gridDomains :: Grid -> V.Vector Domain
gridDomains g@(UniformGrid _ hx hy hz) =
let
ixer = makeUniformIndexer g
(count, _) = makeUniformClassifier g
in runST $ do
doms <- R.computeP $ R.fromFunction (R.ix1 $ count)
(\(R.Z R.:. cellNumber) ->
makeDomain (ixer cellNumber) hx hy hz)
return $ R.toVector doms
cellVolumes :: ParallelSeeds
-> Grid
-> Body
-> Int
-> (VU.Vector Double)
cellVolumes seeds grid b testPoints =
fst $
splitParMapST (freeVolumes b testPoints)
(gridDomains grid) seeds
type GridMonad = ReaderT GridWares DSMCRootMonad
data GridWares =
GridWares { classifier :: (Int, Classifier)
, indexer :: Int -> Point
, volumes :: !(VU.Vector Double)
}
runGrid :: GridMonad a
-> ParallelSeeds
-> Grid
-> Body
-> Int
-> DSMCRootMonad a
runGrid r seeds grid b testPoints =
runReaderT r $
GridWares
(makeUniformClassifier grid)
(makeUniformIndexer grid)
(cellVolumes seeds grid b testPoints)