module Simulation.Aivika.Trans.Comp.Template
(TemplateEventQueueing(..)) where
import Control.Monad
import qualified Simulation.Aivika.Trans.PriorityQueue as PQ
import Simulation.Aivika.Trans.Session
import Simulation.Aivika.Trans.ProtoRef
import Simulation.Aivika.Trans.Comp
import Simulation.Aivika.Trans.Internal.Specs
class ProtoMonadComp m => TemplateEventQueueing m
instance TemplateEventQueueing m => EventQueueing m where
data EventQueue m =
EventQueue { queuePQ :: PQ.PriorityQueue m (Point m -> m ()),
queueBusy :: ProtoRef m Bool,
queueTime :: ProtoRef m Double
}
newEventQueue session specs =
do f <- newProtoRef session False
t <- newProtoRef session $ spcStartTime specs
pq <- PQ.newQueue session
return EventQueue { queuePQ = pq,
queueBusy = f,
queueTime = t }
enqueueEvent t (Event m) =
Event $ \p ->
let pq = queuePQ $ runEventQueue $ pointRun p
in PQ.enqueue pq t m
runEventWith processing (Event e) =
Dynamics $ \p ->
do invokeDynamics p $ processEvents processing
e p
eventQueueCount =
Event $ PQ.queueCount . queuePQ . runEventQueue . pointRun
processPendingEventsCore :: ProtoMonadComp m => Bool -> Dynamics m ()
processPendingEventsCore includingCurrentEvents = Dynamics r where
r p =
do let q = runEventQueue $ pointRun p
f = queueBusy q
f' <- readProtoRef f
unless f' $
do writeProtoRef f True
call q p
writeProtoRef f False
call q p =
do let pq = queuePQ q
r = pointRun p
f <- PQ.queueNull pq
unless f $
do (t2, c2) <- PQ.queueFront pq
let t = queueTime q
t' <- readProtoRef t
when (t2 < t') $
error "The time value is too small: processPendingEventsCore"
when ((t2 < pointTime p) ||
(includingCurrentEvents && (t2 == pointTime p))) $
do writeProtoRef t t2
PQ.dequeue pq
let sc = pointSpecs p
t0 = spcStartTime sc
dt = spcDT sc
n2 = fromIntegral $ floor ((t2 t0) / dt)
c2 $ p { pointTime = t2,
pointIteration = n2,
pointPhase = 1 }
call q p
processPendingEvents :: ProtoMonadComp m => Bool -> Dynamics m ()
processPendingEvents includingCurrentEvents = Dynamics r where
r p =
do let q = runEventQueue $ pointRun p
t = queueTime q
t' <- readProtoRef t
if pointTime p < t'
then error $
"The current time is less than " ++
"the time in the queue: processPendingEvents"
else invokeDynamics p m
m = processPendingEventsCore includingCurrentEvents
processEventsIncludingCurrent :: ProtoMonadComp m => Dynamics m ()
processEventsIncludingCurrent = processPendingEvents True
processEventsIncludingEarlier :: ProtoMonadComp m => Dynamics m ()
processEventsIncludingEarlier = processPendingEvents False
processEventsIncludingCurrentCore :: ProtoMonadComp m => Dynamics m ()
processEventsIncludingCurrentCore = processPendingEventsCore True
processEventsIncludingEarlierCore :: ProtoMonadComp m => Dynamics m ()
processEventsIncludingEarlierCore = processPendingEventsCore True
processEvents :: ProtoMonadComp m => EventProcessing -> Dynamics m ()
processEvents CurrentEvents = processEventsIncludingCurrent
processEvents EarlierEvents = processEventsIncludingEarlier
processEvents CurrentEventsOrFromPast = processEventsIncludingCurrentCore
processEvents EarlierEventsOrFromPast = processEventsIncludingEarlierCore