packages feed

accelerate-examples-0.14.0.0: examples/n-body/Main.hs

--
-- An N-Body simulation
--

-- friends
import Config
import Monitoring
import ParseArgs
import Common.Body
import Common.World
import Gloss.Draw
import Gloss.Event
import Gloss.Simulate
import Random.Array
import Random.Position
import qualified Solver.Naive1                  as Naive1
import qualified Solver.Naive2                  as Naive2
import qualified Solver.BarnsHut                as BarnsHut

import Data.Array.Accelerate                    as A hiding ( size )

-- system
import Prelude                                  as P
import Data.Label
import System.Environment
import Criterion.Main                           ( defaultMainWith, bench, whnf )
import Graphics.Gloss.Interface.Pure.Game


main :: IO ()
main
  = do  beginMonitoring
        argv                    <- getArgs
        (conf, cconf, nops)     <- parseArgs configHelp configBackend options defaults header footer argv

        let solver      = case get configSolver conf of
                            Naive1      -> Naive1.calcAccels
                            Naive2      -> Naive2.calcAccels
                            BarnsHut    -> BarnsHut.calcAccels

            n           = get configBodyCount conf
            size        = get configWindowSize conf
            fps         = get configRate conf
            epsilon     = get configEpsilon conf
            mass        = get configBodyMass conf
            radius      = get configStartDiscSize conf
            backend     = get configBackend conf

            -- Generate random particle positions in a disc layout centred at
            -- the origin. Start the system rotating with particle speed
            -- proportional to distance from the origin
            --
            positions   = randomArray (cloud (size,size) radius) (Z :. n)
            masses      = randomArray (uniformR (1, mass)) (Z :. n)

            bodies      = run backend
                        $ A.map (setStartVelOfBody . constant $ get configStartSpeed conf)
                        $ A.zipWith setMassOfBody (A.use masses)
                        $ A.map unitBody
                        $ A.use positions

            -- The initial simulation state
            --
            universe    = initialise world
            world       = World { worldBodies   = bodies
                                , worldSteps    = 0
                                , worldTime     = 0 }

            -- Advancing the simulation
            --
            advance     = advanceWorld step
            step        = P.curry
                        $ run1 backend
                        $ A.uncurry
                        $ advanceBodies (solver $ constant epsilon)

        -- Forward unto dawn
        --
        if get configBenchmark conf
           then withArgs nops $ defaultMainWith cconf (return ())
                  [ bench "n-body" $ whnf (advance 0.1) world ]

           else play
                  (InWindow "N-Body" (size, size) (10, 10))     -- window size & position
                  black                                         -- background colour
                  fps                                           -- number of simulation steps per second
                  universe                                      -- initial world
                  (draw conf)                                   -- fn to convert a world into a picture
                  react                                         -- fn to handle input events
                  (simulate advance)                            -- fn to advance the world