module Simulation.Aivika.Signal
(
Signal(..),
handleSignal_,
handleSignalComposite,
SignalSource,
newSignalSource,
publishSignal,
triggerSignal,
mapSignal,
mapSignalM,
apSignal,
filterSignal,
filterSignal_,
filterSignalM,
filterSignalM_,
emptySignal,
merge2Signals,
merge3Signals,
merge4Signals,
merge5Signals,
arrivalSignal,
newSignalInTimes,
newSignalInIntegTimes,
newSignalInStartTime,
newSignalInStopTime,
delaySignal,
delaySignalM,
SignalHistory,
signalHistorySignal,
newSignalHistory,
newSignalHistoryStartingWith,
readSignalHistory,
Signalable(..),
signalableChanged,
emptySignalable,
appendSignalable,
traceSignal) where
import Data.IORef
import Data.Monoid
import Data.List
import Data.Array
import Control.Monad
import Control.Monad.Trans
import Simulation.Aivika.Internal.Specs
import Simulation.Aivika.Internal.Parameter
import Simulation.Aivika.Internal.Simulation
import Simulation.Aivika.Internal.Dynamics
import Simulation.Aivika.Internal.Event
import Simulation.Aivika.Internal.Arrival
import Simulation.Aivika.Composite
import qualified Simulation.Aivika.Vector as V
import qualified Simulation.Aivika.Vector.Unboxed as UV
data SignalSource a =
SignalSource { publishSignal :: Signal a,
triggerSignal :: a -> Event ()
}
data Signal a =
Signal { handleSignal :: (a -> Event ()) -> Event DisposableEvent
}
data SignalHandlerQueue a =
SignalHandlerQueue { queueList :: IORef [SignalHandler a] }
data SignalHandler a =
SignalHandler { handlerComp :: a -> Event (),
handlerRef :: IORef () }
instance Eq (SignalHandler a) where
x == y = (handlerRef x) == (handlerRef y)
handleSignal_ :: Signal a -> (a -> Event ()) -> Event ()
handleSignal_ signal h =
do x <- handleSignal signal h
return ()
handleSignalComposite :: Signal a -> (a -> Event ()) -> Composite ()
handleSignalComposite signal h =
do x <- liftEvent $ handleSignal signal h
disposableComposite x
newSignalSource :: Simulation (SignalSource a)
newSignalSource =
Simulation $ \r ->
do list <- newIORef []
let queue = SignalHandlerQueue { queueList = list }
signal = Signal { handleSignal = handle }
source = SignalSource { publishSignal = signal,
triggerSignal = trigger }
handle h =
Event $ \p ->
do x <- enqueueSignalHandler queue h
return $
DisposableEvent $
Event $ \p -> dequeueSignalHandler queue x
trigger a =
Event $ \p -> triggerSignalHandlers queue a p
return source
triggerSignalHandlers :: SignalHandlerQueue a -> a -> Point -> IO ()
triggerSignalHandlers q a p =
do hs <- readIORef (queueList q)
forM_ hs $ \h ->
invokeEvent p $ handlerComp h a
enqueueSignalHandler :: SignalHandlerQueue a -> (a -> Event ()) -> IO (SignalHandler a)
enqueueSignalHandler q h =
do r <- newIORef ()
let handler = SignalHandler { handlerComp = h,
handlerRef = r }
modifyIORef (queueList q) (handler :)
return handler
dequeueSignalHandler :: SignalHandlerQueue a -> SignalHandler a -> IO ()
dequeueSignalHandler q h =
modifyIORef (queueList q) (delete h)
instance Functor Signal where
fmap = mapSignal
instance Monoid (Signal a) where
mempty = emptySignal
mappend = merge2Signals
mconcat [] = emptySignal
mconcat [x1] = x1
mconcat [x1, x2] = merge2Signals x1 x2
mconcat [x1, x2, x3] = merge3Signals x1 x2 x3
mconcat [x1, x2, x3, x4] = merge4Signals x1 x2 x3 x4
mconcat [x1, x2, x3, x4, x5] = merge5Signals x1 x2 x3 x4 x5
mconcat (x1 : x2 : x3 : x4 : x5 : xs) =
mconcat $ merge5Signals x1 x2 x3 x4 x5 : xs
mapSignal :: (a -> b) -> Signal a -> Signal b
mapSignal f m =
Signal { handleSignal = \h ->
handleSignal m $ h . f }
filterSignal :: (a -> Bool) -> Signal a -> Signal a
filterSignal p m =
Signal { handleSignal = \h ->
handleSignal m $ \a ->
when (p a) $ h a }
filterSignal_ :: (a -> Bool) -> Signal a -> Signal ()
filterSignal_ p m =
Signal { handleSignal = \h ->
handleSignal m $ \a ->
when (p a) $ h () }
filterSignalM :: (a -> Event Bool) -> Signal a -> Signal a
filterSignalM p m =
Signal { handleSignal = \h ->
handleSignal m $ \a ->
do x <- p a
when x $ h a }
filterSignalM_ :: (a -> Event Bool) -> Signal a -> Signal ()
filterSignalM_ p m =
Signal { handleSignal = \h ->
handleSignal m $ \a ->
do x <- p a
when x $ h () }
merge2Signals :: Signal a -> Signal a -> Signal a
merge2Signals m1 m2 =
Signal { handleSignal = \h ->
do x1 <- handleSignal m1 h
x2 <- handleSignal m2 h
return $ x1 <> x2 }
merge3Signals :: Signal a -> Signal a -> Signal a -> Signal a
merge3Signals m1 m2 m3 =
Signal { handleSignal = \h ->
do x1 <- handleSignal m1 h
x2 <- handleSignal m2 h
x3 <- handleSignal m3 h
return $ x1 <> x2 <> x3 }
merge4Signals :: Signal a -> Signal a -> Signal a ->
Signal a -> Signal a
merge4Signals m1 m2 m3 m4 =
Signal { handleSignal = \h ->
do x1 <- handleSignal m1 h
x2 <- handleSignal m2 h
x3 <- handleSignal m3 h
x4 <- handleSignal m4 h
return $ x1 <> x2 <> x3 <> x4 }
merge5Signals :: Signal a -> Signal a -> Signal a ->
Signal a -> Signal a -> Signal a
merge5Signals m1 m2 m3 m4 m5 =
Signal { handleSignal = \h ->
do x1 <- handleSignal m1 h
x2 <- handleSignal m2 h
x3 <- handleSignal m3 h
x4 <- handleSignal m4 h
x5 <- handleSignal m5 h
return $ x1 <> x2 <> x3 <> x4 <> x5 }
mapSignalM :: (a -> Event b) -> Signal a -> Signal b
mapSignalM f m =
Signal { handleSignal = \h ->
handleSignal m (f >=> h) }
apSignal :: Event (a -> b) -> Signal a -> Signal b
apSignal f m =
Signal { handleSignal = \h ->
handleSignal m $ \a -> do { x <- f; h (x a) } }
emptySignal :: Signal a
emptySignal =
Signal { handleSignal = \h -> return mempty }
data SignalHistory a =
SignalHistory { signalHistorySignal :: Signal a,
signalHistoryTimes :: UV.Vector Double,
signalHistoryValues :: V.Vector a }
newSignalHistory :: Signal a -> Composite (SignalHistory a)
newSignalHistory =
newSignalHistoryStartingWith Nothing
newSignalHistoryStartingWith :: Maybe a -> Signal a -> Composite (SignalHistory a)
newSignalHistoryStartingWith init signal =
do ts <- liftIO UV.newVector
xs <- liftIO V.newVector
case init of
Nothing -> return ()
Just a ->
do t <- liftDynamics time
liftIO $
do UV.appendVector ts t
V.appendVector xs a
handleSignalComposite signal $ \a ->
Event $ \p ->
do UV.appendVector ts (pointTime p)
V.appendVector xs a
return SignalHistory { signalHistorySignal = signal,
signalHistoryTimes = ts,
signalHistoryValues = xs }
readSignalHistory :: SignalHistory a -> Event (Array Int Double, Array Int a)
readSignalHistory history =
do xs <- liftIO $ UV.freezeVector (signalHistoryTimes history)
ys <- liftIO $ V.freezeVector (signalHistoryValues history)
return (xs, ys)
triggerSignalWithCurrentTime :: SignalSource Double -> Event ()
triggerSignalWithCurrentTime s =
Event $ \p -> invokeEvent p $ triggerSignal s (pointTime p)
newSignalInTimes :: [Double] -> Event (Signal Double)
newSignalInTimes xs =
do s <- liftSimulation newSignalSource
enqueueEventWithTimes xs $ triggerSignalWithCurrentTime s
return $ publishSignal s
newSignalInIntegTimes :: Event (Signal Double)
newSignalInIntegTimes =
do s <- liftSimulation newSignalSource
enqueueEventWithIntegTimes $ triggerSignalWithCurrentTime s
return $ publishSignal s
newSignalInStartTime :: Event (Signal Double)
newSignalInStartTime =
do s <- liftSimulation newSignalSource
t <- liftParameter starttime
enqueueEvent t $ triggerSignalWithCurrentTime s
return $ publishSignal s
newSignalInStopTime :: Event (Signal Double)
newSignalInStopTime =
do s <- liftSimulation newSignalSource
t <- liftParameter stoptime
enqueueEvent t $ triggerSignalWithCurrentTime s
return $ publishSignal s
data Signalable a =
Signalable { readSignalable :: Event a,
signalableChanged_ :: Signal ()
}
signalableChanged :: Signalable a -> Signal a
signalableChanged x = mapSignalM (const $ readSignalable x) $ signalableChanged_ x
instance Functor Signalable where
fmap f x = x { readSignalable = fmap f (readSignalable x) }
instance Monoid a => Monoid (Signalable a) where
mempty = emptySignalable
mappend = appendSignalable
emptySignalable :: Monoid a => Signalable a
emptySignalable =
Signalable { readSignalable = return mempty,
signalableChanged_ = mempty }
appendSignalable :: Monoid a => Signalable a -> Signalable a -> Signalable a
appendSignalable m1 m2 =
Signalable { readSignalable = liftM2 (<>) (readSignalable m1) (readSignalable m2),
signalableChanged_ = (signalableChanged_ m1) <> (signalableChanged_ m2) }
arrivalSignal :: Signal a -> Signal (Arrival a)
arrivalSignal m =
Signal { handleSignal = \h ->
Event $ \p ->
do r <- newIORef Nothing
invokeEvent p $
handleSignal m $ \a ->
Event $ \p ->
do t0 <- readIORef r
let t = pointTime p
writeIORef r (Just t)
invokeEvent p $
h Arrival { arrivalValue = a,
arrivalTime = t,
arrivalDelay =
case t0 of
Nothing -> Nothing
Just t0 -> Just (t t0) }
}
delaySignal :: Double -> Signal a -> Signal a
delaySignal delta m =
Signal { handleSignal = \h ->
do r <- liftIO $ newIORef False
h <- handleSignal m $ \a ->
Event $ \p ->
invokeEvent p $
enqueueEvent (pointTime p + delta) $
do x <- liftIO $ readIORef r
unless x $ h a
return $ DisposableEvent $
disposeEvent h >>
(liftIO $ writeIORef r True)
}
delaySignalM :: Event Double -> Signal a -> Signal a
delaySignalM delta m =
Signal { handleSignal = \h ->
do r <- liftIO $ newIORef False
h <- handleSignal m $ \a ->
Event $ \p ->
do delta' <- invokeEvent p delta
invokeEvent p $
enqueueEvent (pointTime p + delta') $
do x <- liftIO $ readIORef r
unless x $ h a
return $ DisposableEvent $
disposeEvent h >>
(liftIO $ writeIORef r True)
}
traceSignal :: String -> Signal a -> Signal a
traceSignal message m =
Signal { handleSignal = \h ->
handleSignal m $ traceEvent message . h }