packages feed

gloss-examples-1.7.3.1: raster/Fluid/Args.hs

module Args where
import Config
import Data.Array.Repa                  as R
import Data.Array.Repa.Algorithms.Pixel as R
import Data.Array.Repa.IO.BMP           as R
import System.Console.GetOpt
import Data.IORef
import Prelude                          as P
import Control.Monad

-- | Command line options.
loadConfig :: [String] -> IO Config
loadConfig args
 = do   
        batchModeArg    <- newIORef False
        maxStepsArg     <- newIORef 0
        widthArg        <- newIORef 100
        scaleArg        <- newIORef 5
        rateArg         <- newIORef 25
        deltaArg        <- newIORef 0.1
        diffArg         <- newIORef 0
        viscArg         <- newIORef 0
        densArg         <- newIORef 100
        velArg          <- newIORef (20, 20)

        densityBmpArg   <- newIORef Nothing
        velocityBmpArg  <- newIORef Nothing
        
        let setWidthArg arg     = writeIORef widthArg         (read arg)
        let setScaleArg arg     = writeIORef scaleArg         (read arg)
        let setDeltaArg arg     = writeIORef deltaArg         (read arg)
        let setDiffArg  arg     = writeIORef diffArg          (read arg)
        let setViscArg  arg     = writeIORef viscArg          (read arg)
        let setDensArg  arg     = writeIORef densArg          (read arg)
        let setVelArg   arg     = let a = read arg in writeIORef velArg (a, a)
        let setRate     arg     = writeIORef rateArg          (read arg)
        let setMaxSteps arg     = writeIORef maxStepsArg      (read arg)
        let setBatchArg         = writeIORef batchModeArg     True
        let setDensityBMP  arg  = writeIORef densityBmpArg    (Just arg)
        let setVelocityBMP arg  = writeIORef velocityBmpArg   (Just arg)

        let options :: [OptDescr (IO ())]
            options
             = [Option [] ["batch"]             (NoArg  setBatchArg            )
                        "Run a fixed number of steps instead of displaying in a window.",

                Option [] ["max"]               (ReqArg setMaxSteps     "INT")
                        "Quit after this number of steps.",

                Option [] ["width"]             (ReqArg setWidthArg     "INT")
                        "Size of simulation (100)",

                Option [] ["scale"]             (ReqArg setScaleArg     "INT")
                        "Width of cell in window (4)",

                Option [] ["rate"]              (ReqArg setRate         "INT")
                        "Frame rate of simulator (25)",

                Option [] ["delta"]             (ReqArg setDeltaArg     "FLOAT")
                        "Length of time steps (0.1)",

                Option [] ["diffusion"]         (ReqArg setDiffArg      "FLOAT")
                        "Diffusion rate for the density (0)",

                Option [] ["viscosity"]         (ReqArg setViscArg      "FLOAT")
                        "Viscosity rate for the velocity (0)",

                Option [] ["user-density"]      (ReqArg setDensArg      "FLOAT")
                        "Magnitude of a user inserted density (100)",

                Option [] ["user-velocity"]     (ReqArg setVelArg       "FLOAT")
                        "Magnitude of a user inserted velocity (20)",

                Option [] ["bmp-density"]       (ReqArg setDensityBMP   "FILE.bmp")
                        "File for initial fluid density",

                Option [] ["bmp-velocity"]      (ReqArg setVelocityBMP  "FILE.bmp")
                        "File for initial fluid velocity"
                ]

        case getOpt RequireOrder options args of
         (actions,      [],   []) 
          -> foldl (>>) (return ()) actions

         (      _, nonOpts,   []) 
          -> error $ "unrecognized arguments: " P.++ unwords nonOpts

         (      _,       _, msgs) 
          -> error $ concat msgs P.++ usageInfo "Usage: fluid [OPTION...]" options


        batchMode       <- readIORef batchModeArg
        maxSteps        <- readIORef maxStepsArg
        width           <- readIORef widthArg
        let height      = width
        scale           <- readIORef scaleArg
        rate            <- readIORef rateArg
        delta           <- readIORef deltaArg
        diff            <- readIORef diffArg
        visc            <- readIORef viscArg
        dens            <- readIORef densArg
        vel             <- readIORef velArg
        densityBmp      <- readIORef densityBmpArg
        velocityBmp     <- readIORef velocityBmpArg


        -- Load the initial desity bmp if we were given one.
        initialDensity
         <- case densityBmp of
                -- No density file given, so just set the field to zero.
                Nothing 
                 -> return
                        $ R.fromListUnboxed (Z :. height :. width)
                        $ replicate (height * width) 0

                -- Load density from a .bmp, using the luminance as
                -- the scalar density value.
                Just filePath
                 -> do  result   <- readImageFromBMP filePath
                        let arr  =  case result of
                                        Right arr'      -> arr'
                                        Left err        -> error $ show err

                        let Z :. height' :. width' 
                                 = extent arr

                        when (height /= height' || width /= width')
                         $ error "Fluid: bmp size does not match --width argument"

                        density  <- computeUnboxedP 
                                  $ R.map floatLuminanceOfRGB8 arr
                        return density


        -- Load the initial velocity bmp if we were given one
        initialVelocity
         <- case velocityBmp of
                -- No velocity file given, so just set the field to zero.
                Nothing
                 -> return 
                        $ R.fromListUnboxed (Z :. height :. width)
                        $ replicate (height * width) (0, 0)

                -- Load 
                Just filePath
                 -> do  result  <- readImageFromBMP filePath
                        let arr  =  case result of
                                        Right arr'      -> arr'
                                        Left err        -> error $ show err

                        let Z :. height' :. width' 
                                 = extent arr

                        when (height /= height' || width /= width')
                         $ error "Fluid: bmp size does not match --width argument"

                        let {-# INLINE conv #-}
                            conv (r, g, _b) 
                             = let r'   = fromIntegral (-128 + fromIntegral r :: Int)
                                   g'   = fromIntegral (-128 + fromIntegral g :: Int)
                               in  (r' * 0.0001, g' * 0.0001)

                        velocity  <- computeUnboxedP $ R.map conv arr
                        return velocity

        return  Config
                { configRate            = rate
                , configWindowSize      = (scale * width, scale * width)
                , configMaxSteps        = maxSteps
                , configBatchMode       = batchMode 
                , configModelSize       = (width, width)
                , configDelta           = delta
                , configDiffusion       = diff
                , configViscosity       = visc
                , configDensity         = dens
                , configVelocity        = vel 
                , configInitialDensity  = initialDensity
                , configInitialVelocity = initialVelocity }