module Simulation.Aivika.Lattice.Internal.LIO
(LIOParams(..),
LIO(..),
invokeLIO,
runLIO,
lioParams,
rootLIOParams,
parentLIOParams,
upSideLIOParams,
downSideLIOParams,
shiftLIOParams,
lioParamsAt,
latticeTimeIndex,
latticeMemberIndex,
latticeTime,
latticeTimeStep,
latticePoint,
latticeSize,
findLatticeTimeIndex) where
import Data.IORef
import Data.Maybe
import Control.Applicative
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Fix
import Control.Exception (throw, catch, finally)
import Simulation.Aivika.Trans.Exception
import Simulation.Aivika.Trans.Internal.Types
import Simulation.Aivika.Trans.Parameter
newtype LIO a = LIO { unLIO :: LIOParams -> IO a
}
data LIOParams =
LIOParams { lioTimeIndex :: !Int,
lioMemberIndex :: !Int
} deriving (Eq, Ord, Show)
instance Monad LIO where
return = LIO . const . return
(LIO m) >>= k = LIO $ \ps ->
m ps >>= \a ->
let m' = unLIO (k a) in m' ps
instance Applicative LIO where
pure = return
(<*>) = ap
instance Functor LIO where
fmap f (LIO m) = LIO $ fmap f . m
instance MonadIO LIO where
liftIO = LIO . const . liftIO
instance MonadFix LIO where
mfix f =
LIO $ \ps ->
do { rec { a <- invokeLIO ps (f a) }; return a }
instance MonadException LIO where
catchComp (LIO m) h = LIO $ \ps ->
catch (m ps) (\e -> unLIO (h e) ps)
finallyComp (LIO m1) (LIO m2) = LIO $ \ps ->
finally (m1 ps) (m2 ps)
throwComp e = LIO $ \ps ->
throw e
invokeLIO :: LIOParams -> LIO a -> IO a
invokeLIO ps (LIO m) = m ps
runLIO :: LIO a -> IO a
runLIO m = unLIO m rootLIOParams
lioParams :: LIO LIOParams
lioParams = LIO return
rootLIOParams :: LIOParams
rootLIOParams = LIOParams { lioTimeIndex = 0,
lioMemberIndex = 0 }
parentLIOParams :: LIOParams -> Maybe LIOParams
parentLIOParams ps
| i == 0 = Nothing
| otherwise = Just $ ps { lioTimeIndex = i 1, lioMemberIndex = max 0 (k 1) }
where i = lioTimeIndex ps
k = lioMemberIndex ps
upSideLIOParams :: LIOParams -> LIOParams
upSideLIOParams ps = ps { lioTimeIndex = 1 + i }
where i = lioTimeIndex ps
downSideLIOParams :: LIOParams -> LIOParams
downSideLIOParams ps = ps { lioTimeIndex = 1 + i, lioMemberIndex = 1 + k }
where i = lioTimeIndex ps
k = lioMemberIndex ps
shiftLIOParams :: Int
-> Int
-> LIOParams
-> LIOParams
shiftLIOParams di dk ps
| i' < 0 = error "The time index cannot be negative: shiftLIOParams"
| k' < 0 = error "The member index cannot be negative: shiftLIOParams"
| k' > i' = error "The member index cannot be greater than the time index: shiftLIOParams"
| otherwise = ps { lioTimeIndex = i', lioMemberIndex = k' }
where i = lioTimeIndex ps
i' = i + di
k = lioMemberIndex ps
k' = k + dk
lioParamsAt :: Int
-> Int
-> LIOParams
lioParamsAt i k
| i < 0 = error "The time index cannot be negative: lioParamsAt"
| k < 0 = error "The member index cannot be negative: lioParamsAt"
| k > i = error "The member index cannot be greater than the time index: lioParamsAt"
| otherwise = LIOParams { lioTimeIndex = i, lioMemberIndex = k }
latticeTimeIndex :: LIO Int
latticeTimeIndex = LIO $ return . lioTimeIndex
latticeMemberIndex :: LIO Int
latticeMemberIndex = LIO $ return . lioMemberIndex
latticeTime :: Parameter LIO Double
latticeTime =
Parameter $ \r ->
LIO $ \ps ->
let sc = runSpecs r
t0 = spcStartTime sc
dt = spcDT sc
i = lioTimeIndex ps
t = t0 + (fromInteger $ toInteger i) * dt
in return t
latticePoint :: Parameter LIO (Point LIO)
latticePoint =
Parameter $ \r ->
do t <- invokeParameter r latticeTime
let sc = runSpecs r
t0 = spcStartTime sc
dt = spcDT sc
n = fromIntegral $ floor ((t t0) / dt)
return Point { pointSpecs = sc,
pointRun = r,
pointTime = t,
pointIteration = n,
pointPhase = 1 }
latticeTimeStep :: Parameter LIO Double
latticeTimeStep = dt
latticeSize :: Parameter LIO Int
latticeSize =
Parameter $ \r ->
do let sc = runSpecs r
t0 = spcStartTime sc
t2 = spcStopTime sc
dt = spcDT sc
i = fromIntegral $ floor ((t2 t0) / dt)
return (i + 1)
findLatticeTimeIndex :: Double -> Parameter LIO Double
findLatticeTimeIndex t =
Parameter $ \r ->
do let sc = runSpecs r
t0 = spcStartTime sc
dt = spcDT sc
i = fromIntegral $ floor ((t t0) / dt)
return i