1. --
  2. -- Explicit Euler method for 1D linear diffusion equation
  3. -- (using lists)
  4. --
  5.  
  6. module Euler1D ( stepEuler, evalEuler, makeu0 ) where
  7.  
  8. -- impose zero flux condition
  9. zeroflux mu (boundary:inner:xs) = boundary+mu*2*(inner-boundary)
  10.  
  11. -- one step of integration
  12. stepEuler mu u0 = (applyBC . (diffused mu)) $ u0
  13.     where
  14.           diffused mu (left:x:[]) = []    -- ignore outer points
  15.           diffused mu (left:x:right:xs) = -- integrate inner points
  16.                    let y = (x+mu*(left+right-2*x))
  17.                        in y `seq` y : diffused mu (x:right:xs)
  18.           applyBC inner = [lbc] ++ inner ++ [rbc] -- boundary conditions
  19.                where
  20.                      lbc = zeroflux mu ((head u0):(take 1 inner))           -- left boundary
  21.                      rbc = zeroflux mu ((last u0):(take 1 $ reverse inner)) -- right boundary
  22.  
  23. -- initial condition
  24. makeu0 n = [ f x n | x <- [0..n]]
  25.  
  26. f x n = ((^2) . sin . (pi*) . xi) x
  27.     where xi x = fromIntegral x / fromIntegral n
  28.  
  29. -- integrate until time t with time step dt
  30. evalEuler :: (Floating a, Ord a) => a -> a -> a -> [a] -> [a]
  31. evalEuler dt t mu u
  32.   | t <= 0.0 = u
  33.   | otherwise =
  34.       let prevstep = stepEuler mu u
  35.       in  evalEuler (min dt (t-dt)) (t-dt) mu $! prevstep