packages feed

gloss-examples-1.7.4.4: raster/Fluid/src-repa/Stage/Linear.hs

{-# LANGUAGE FlexibleContexts, BangPatterns #-}
module Stage.Linear
        (linearSolver)
where
import Model
import FieldElt                         as E
import Data.Array.Repa                  as R
import Data.Array.Repa.Stencil          as R
import Data.Array.Repa.Stencil.Dim2     as R
import Data.Array.Repa.Eval             as R
import Data.Vector.Unboxed
import Prelude as P


linearSolver 
        :: (FieldElt a, Source U a, Unbox a, Elt a, Num a, Show a)
        => Field a      -- ^ Original field.
        -> Field a      -- ^ Current field.
        -> Float
        -> Float
        -> Int          -- ^ Number of iterations to apply.
        -> IO (Field a)

linearSolver origField curField !a !c !iters
        -- If nothing would change by running the solver, then skip it.
        | 0 <- a       = return origField

        -- The solver has finished its loop
        | 0 <- iters   = return curField

        -- Do one iteration
        | otherwise
        = origField `deepSeqArray` curField `deepSeqArray`
          do    let !c' = 1/c
                let {-# INLINE zipFunc #-}
                    zipFunc !orig !new
                        = (orig ~+~ (new ~*~ a)) ~*~ c'

                newField <- {-# SCC "linearSolver.mapStencil" #-}
                           computeUnboxedP 
                         $ R.szipWith zipFunc origField
                         $ mapStencil2 (BoundConst 0) linearSolverStencil curField

                -- TODO: this boundConst thing is costing a fair bit.
                -- Do something about the branches introduced into the core code.

                linearSolver origField newField a c (iters - 1)

{-# SPECIALIZE linearSolver 
        :: Field Float
        -> Field Float 
        -> Float -> Float -> Int 
        -> IO (Field Float) #-}

{-# SPECIALIZE linearSolver 
        :: Field (Float, Float) 
        -> Field (Float, Float) 
        -> Float -> Float -> Int 
        -> IO (Field (Float, Float)) #-}



-- | Stencil function for the linear solver.
linearSolverStencil 
        :: FieldElt a
        => Stencil DIM2 a

linearSolverStencil
 = StencilStatic (Z:.3:.3) E.zero
      (\ix val acc ->
         case linearSolverCoeffs ix of
            Nothing    -> acc
            Just coeff -> acc ~+~ (val ~*~ coeff))
{-# INLINE linearSolverStencil #-}
         

-- | Linear solver stencil kernel.
linearSolverCoeffs :: DIM2 -> Maybe Float
linearSolverCoeffs (Z:.j:.i)
   | i ==  1, j ==  0 = Just 1
   | i == -1, j ==  0 = Just 1
   | i ==  0, j ==  1 = Just 1
   | i ==  0, j == -1 = Just 1
   | otherwise        = Nothing
{-# INLINE linearSolverCoeffs #-}