packages feed

sde-solver-0.1.0.0: src/Numeric/DSDE.hs

{-# LANGUAGE ConstraintKinds #-}
--------------------------------------------------------------------
-- |
-- Module : Numeric.DSDE
--
-- Main entry point in the distributed SDE solver.
--
-- This module provides wrappers for the most common use cases, 
-- and the user only needs to choose if to perform a distributed calculation
-- and supply the problem parameters.
--
-- Here follows an example of solving the Langevin equation over
-- the interval [0,2] with the result being written to a file on the main MPI node.
-- This produces a file with 1000 entries, corresponding to the final value
-- in all realisations.
--
-- @
--    let r = 1.0
--        sigma = 0.1
--        y_0 = 3.0
--        end = 0.2
--        stepSize = 0.01
--        runs = 1000
--    withSolver Milstein (distribute (Langevin r sigma) y_0 end stepSize runs) >>=
--      writeResult "out"
-- @

module Numeric.DSDE (
  -- * Abstract solver interface
  distribute,
  local,
  SDEResult(..),

  -- ** Supplied SDE Solvers 
  Milstein(..),
  EulerMaruyama(..),

  -- * Helper functions
  withSolver, writeResult
) where

import qualified Data.Vector.Unboxed as V
import Numeric.DSDE.Distribute
import GHC.Conc
import Numeric.DSDE.RNG
import Numeric.DSDE.SDE
import Numeric.DSDE.SDESolver
import System.IO

-- | distribute: Perform a distributed MPI calculation over a set of hosts supplied through the MPI environment.
--   Each host is fully utilized by running a number of GHC threads equivalent to the number cores available.
--   Internally it uses the highly performant MWC PRNG over the IO monad.
--
--   local: Skips the MPI runtime and only runs locally on GHC threads.
distribute, local :: (SDE sde, SDESolver solver)
  => sde Double    -- ^ SDE Instance
  -> Double        -- ^ Initial y_0 value
  -> Double        -- ^ End of interval, evaluating over [0, end]
  -> Double        -- ^ Step size used by solver
  -> Int           -- ^ Number of realisations
  -> solver        -- ^ Solving method
  -> IO SDEResult  -- ^ Result 

distribute = evalWrapper [Distr MPI]
local = evalWrapper [] 

-- | Wrapper function providing access to the internal API.
evalWrapper :: (SDE sde, SDESolver solver) => [DistributeInstance IO] -> sde Double -> Double -> Double -> Double -> Int -> solver -> IO SDEResult
evalWrapper distr sde y_0 end step runs solver = do
  let rng = initialize
  cores <- getNumCapabilities
  evaluate (distr, Local cores) (sde, solver, rng, IP (End end) y_0 step runs)

-- | Use the specified solver with an IO action.
withSolver :: (SDESolver solver, Monad m) => solver -> (solver -> m a) ->  m a
withSolver = flip id

-- | Write a 'SDEResult' to the supplied filename, output as ASCII text.
writeResult :: FilePath -> SDEResult -> IO ()
writeResult file result = withFile file WriteMode $ output result
  where
  output (Scalar value count) h = hPutStr h $ unwords [show value, show count]
  output (Distribution samples) h = V.mapM_ (hPrint h) samples