module Simulation.Aivika.Experiment.Base.TimingStatsView
(TimingStatsView(..),
defaultTimingStatsView) where
import Control.Monad
import Control.Monad.Trans
import qualified Data.Map as M
import Data.IORef
import Data.Maybe
import Data.Monoid
import Simulation.Aivika
import Simulation.Aivika.Experiment.Types
import Simulation.Aivika.Experiment.Base.WebPageRenderer
import Simulation.Aivika.Experiment.Base.ExperimentWriter
import Simulation.Aivika.Experiment.Base.HtmlWriter
import Simulation.Aivika.Experiment.Base.TimingStatsWriter
import Simulation.Aivika.Experiment.Utils (replace)
data TimingStatsView =
TimingStatsView { timingStatsTitle :: String,
timingStatsRunTitle :: String,
timingStatsDescription :: String,
timingStatsWriter :: TimingStatsWriter Double,
timingStatsPredicate :: Event Bool,
timingStatsTransform :: ResultTransform,
timingStatsSeries :: ResultTransform
}
defaultTimingStatsView :: TimingStatsView
defaultTimingStatsView =
TimingStatsView { timingStatsTitle = "Statistics for Time-Persistent Variables",
timingStatsRunTitle = "$TITLE / Run $RUN_INDEX of $RUN_COUNT",
timingStatsDescription = "The statistical data are gathered in the time points.",
timingStatsWriter = defaultTimingStatsWriter,
timingStatsPredicate = return True,
timingStatsTransform = id,
timingStatsSeries = id }
instance ExperimentView TimingStatsView (WebPageRenderer a) where
outputView v =
let reporter exp renderer dir =
do st <- newTimingStats v exp
let context =
WebPageContext $
WebPageWriter { reporterWriteTOCHtml = timingStatsTOCHtml st,
reporterWriteHtml = timingStatsHtml st }
return ExperimentReporter { reporterInitialise = return (),
reporterFinalise = return (),
reporterSimulate = simulateTimingStats st,
reporterContext = context }
in ExperimentGenerator { generateReporter = reporter }
data TimingStatsViewState =
TimingStatsViewState { timingStatsView :: TimingStatsView,
timingStatsExperiment :: Experiment,
timingStatsMap :: M.Map Int (IORef [(String, IORef (TimingStats Double))]) }
newTimingStats :: TimingStatsView -> Experiment -> ExperimentWriter TimingStatsViewState
newTimingStats view exp =
do let n = experimentRunCount exp
rs <- forM [0..(n 1)] $ \i -> liftIO $ newIORef []
let m = M.fromList $ zip [0..(n 1)] rs
return TimingStatsViewState { timingStatsView = view,
timingStatsExperiment = exp,
timingStatsMap = m }
simulateTimingStats :: TimingStatsViewState -> ExperimentData -> Composite ()
simulateTimingStats st expdata =
do let view = timingStatsView st
rs = timingStatsSeries view $
timingStatsTransform view $
experimentResults expdata
exts = resultsToDoubleValues rs
signals = experimentPredefinedSignals expdata
signal = filterSignalM (const predicate) $
pureResultSignal signals $
resultSignal rs
predicate = timingStatsPredicate view
i <- liftParameter simulationIndex
let r = fromJust $ M.lookup (i 1) $ timingStatsMap st
forM_ exts $ \ext ->
do stats <- liftIO $ newIORef emptyTimingStats
let name = resultValueName ext
liftIO $ modifyIORef r ((:) (name, stats))
handleSignalComposite signal $ \_ ->
do t <- liftDynamics time
x <- resultValueData ext
liftIO $
do y <- readIORef stats
let y' = addTimingStats t x y
y' `seq` writeIORef stats y'
timingStatsHtml :: TimingStatsViewState -> Int -> HtmlWriter ()
timingStatsHtml st index =
let n = experimentRunCount $ timingStatsExperiment st
in if n == 1
then timingStatsHtmlSingle st index
else timingStatsHtmlMultiple st index
timingStatsHtmlSingle :: TimingStatsViewState -> Int -> HtmlWriter ()
timingStatsHtmlSingle st index =
do header st index
let r = fromJust $ M.lookup 0 (timingStatsMap st)
pairs <- liftIO $ readIORef r
forM_ (reverse pairs) $ \(name, r) ->
do stats <- liftIO $ readIORef r
let writer = timingStatsWriter (timingStatsView st)
write = timingStatsWrite writer
write writer name stats
timingStatsHtmlMultiple :: TimingStatsViewState -> Int -> HtmlWriter ()
timingStatsHtmlMultiple st index =
do header st index
let n = experimentRunCount $ timingStatsExperiment st
forM_ [0..(n 1)] $ \i ->
do let subtitle =
replace "$RUN_INDEX" (show $ i + 1) $
replace "$RUN_COUNT" (show n) $
replace "$TITLE" (timingStatsTitle $ timingStatsView st)
(timingStatsRunTitle $ timingStatsView st)
writeHtmlHeader4 $
writeHtmlText subtitle
let r = fromJust $ M.lookup i (timingStatsMap st)
pairs <- liftIO $ readIORef r
forM_ (reverse pairs) $ \(name, r) ->
do stats <- liftIO $ readIORef r
let writer = timingStatsWriter (timingStatsView st)
write = timingStatsWrite writer
write writer name stats
header :: TimingStatsViewState -> Int -> HtmlWriter ()
header st index =
do writeHtmlHeader3WithId ("id" ++ show index) $
writeHtmlText (timingStatsTitle $ timingStatsView st)
let description = timingStatsDescription $ timingStatsView st
unless (null description) $
writeHtmlParagraph $
writeHtmlText description
timingStatsTOCHtml :: TimingStatsViewState -> Int -> HtmlWriter ()
timingStatsTOCHtml st index =
writeHtmlListItem $
writeHtmlLink ("#id" ++ show index) $
writeHtmlText (timingStatsTitle $ timingStatsView st)