summaryrefslogtreecommitdiff
path: root/testsuite/tests/dph/nbody/Main.hs
blob: ad2c809a1cdd42684a0ac4171a695ce9777b77b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
{-# LANGUAGE ParallelListComp, BangPatterns #-}

import Config
import Dump
import World
import Body
import Util
import Solver
import Generate
import Control.Monad
import Data.Maybe
import qualified Data.Vector.Unboxed            as V
import qualified Data.Array.Parallel    as P
import qualified Data.Array.Parallel.PArray     as P


main :: IO ()
main 
 = let  config          = defaultConfig
        calcAccels      = calcAccels_nb
        
        -- Setup initial world
        vPoints         = genPointsDisc 
                                (configBodyCount config)
                                (0, 0) 
                                (configStartDiscSize config)

        vBodies         = V.map (setStartVelOfBody $ configStartSpeed config)
                        $ V.map (setMassOfBody     $ configBodyMass   config)
                        $ V.map (uncurry unitBody) 
                        $ vPoints

        worldStart      = World
                        { worldBodies   = vBodies
                        , worldSteps    = 0 }

    in  mainBatch config calcAccels worldStart 


-- | Run the simulation in batch mode.
mainBatch :: Config -> Solver -> World -> IO ()
mainBatch config calcAccels worldStart
 = do   let world' = mainBatchRun config calcAccels worldStart
        mainEnd (configDumpFinal config) 
                (configPrintFinal config)
                world'


mainBatchRun config calcAccels worldStart 
 = go worldStart
 where  go !world
          = let world' = advanceWorld
                                (calcAccels $ configEpsilon config)
                                (configTimeStep config)
                                world

            in if worldSteps world' < configMaxSteps config
                        then go world'
                        else world'


-- | Called at end of run to dump final world state.
mainEnd :: Maybe FilePath       -- ^ Write final bodies to this file.
        -> Bool                 -- ^ Print final bodies to stdout
        -> World                -- ^ Final world state.
        -> IO ()

mainEnd mDumpFinal printFinal world
 = do   -- Dump the final world state to file if requested.
        maybe   (return ())  (dumpWorld world) mDumpFinal
        when    printFinal   (printWorld world)


-- Solver ---------------------------------------------------------------------
type Solver     = Double -> V.Vector MassPoint -> V.Vector Accel

-- | Nested Data Parallelism + Barnes-Hut algorithm.
calcAccels_nb   :: Solver
calcAccels_nb epsilon mpts
 = let  
        -- bounds finding isn't vectorised yet.
        (llx, lly, rux, ruy)    = findBounds mpts

        mpts'   = P.fromList $ V.toList mpts
        accels' = calcAccelsWithBoxPA epsilon llx lly rux ruy mpts'
        
   in   V.fromList $ P.toList accels'


-- | Find the coordinates of the bounding box that contains these points.
findBounds :: V.Vector MassPoint -> (Double, Double, Double, Double)
{-# INLINE findBounds #-}
findBounds bounds
 = V.foldl' acc (x1, y1, x1, y1) bounds
 where
        (x1, y1, _)     = bounds V.! 0

        acc (!llx, !lly, !rux, !ruy) (x, y, _)
         = let  !llx'   = min llx  x
                !lly'   = min lly  y
                !rux'   = max rux  x
                !ruy'   = max ruy  y
           in   (llx', lly', rux', ruy')