module Simulation.Aivika.Lattice.Internal.LIO
(LIOParams(..),
LIO(..),
invokeLIO,
runLIO,
lioParams,
rootLIOParams,
parentLIOParams,
upSideLIOParams,
downSideLIOParams,
shiftLIOParams,
latticeTimeIndex,
latticeMemberIndex,
latticeTime,
latticeTimeStep,
latticePoint) 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
| di <= 0 = error "The time index shift must be positive: 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
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
i = lioTimeIndex ps
t = spcStartTime sc + (fromInteger $ toInteger i) * (spcDT sc)
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