repa-examples-1.0.0.0: Laplace/src/Solver.hs
{-# LANGUAGE BangPatterns #-}
module Solver
(solveLaplace)
where
import Data.Array.Repa as A
import qualified Data.Array.Repa.Shape as S
import Data.Array.Parallel.Unlifted (Elt)
import qualified Data.Array.Parallel.Unlifted as U
-- | Solver for the Laplace equation.
solveLaplace
:: Int -- ^ Number of iterations to use.
-> Array DIM2 Double -- ^ Boundary value mask.
-> Array DIM2 Double -- ^ Boundary values.
-> Array DIM2 Double -- ^ Initial state.
-> Array DIM2 Double
{-# INLINE solveLaplace #-}
solveLaplace steps arrBoundMask@Manifest{} arrBoundValue@Manifest{} arrInit
= go steps arrInit
where go i arr@Manifest{}
| i == 0 = arr
| otherwise = go (i - 1)
$ force
$ applyBoundary arrBoundMask arrBoundValue
$ relaxLaplace arr
-- | Perform matrix relaxation for the Laplace equation,
-- using a stencil function.
--
-- Computation fn is
-- u'(i,j) = (u(i-1,j) + u(i+1,j) + u(i,j-1) + u(i,j+1)) / 4
--
relaxLaplace
:: Array DIM2 Double
-> Array DIM2 Double
{-# INLINE relaxLaplace #-}
relaxLaplace !arr
= traverse arr id elemFn
where
_ :. height :. width
= extent arr
{-# INLINE elemFn #-}
elemFn get d@(sh :. i :. j)
= if isBorder i j
then get d
else (get (sh :. (i-1) :. j)
+ get (sh :. i :. (j-1))
+ get (sh :. (i+1) :. j)
+ get (sh :. i :. (j+1))) / 4
-- Check if this element is on the border of the matrix.
-- If so we can't apply the stencil because we don't have all the neighbours.
{-# INLINE isBorder #-}
isBorder i j
= (i == 0) || (i >= width - 1)
|| (j == 0) || (j >= height - 1)
-- | Apply the boundary conditions to this matrix.
-- The mask matrix has 0 in places where boundary conditions hold
-- and 1 otherwise.
--
-- The value matrix has the boundary condition value in places where it holds,
-- and 0 otherwise.
--
applyBoundary
:: Array DIM2 Double -- ^ Boundary condition mask.
-> Array DIM2 Double -- ^ Boundary condition values.
-> Array DIM2 Double -- ^ Initial matrix.
-> Array DIM2 Double -- ^ Matrix with boundary conditions applied.
{-# INLINE applyBoundary #-}
applyBoundary arrBoundMask arrBoundValue arr
= A.zipWith (+) arrBoundValue
$ A.zipWith (*) arrBoundMask arr