module Simulation.Aivika.Trans.Experiment.Types where
import Control.Monad
import Control.Exception
import Data.Maybe
import Data.Monoid
import Data.Either
import GHC.Conc (getNumCapabilities)
import Simulation.Aivika.Trans
data Experiment m =
Experiment { experimentSpecs :: Specs m,
experimentTransform :: ResultTransform m,
experimentLocalisation :: ResultLocalisation,
experimentRunCount :: Int,
experimentTitle :: String,
experimentDescription :: String,
experimentVerbose :: Bool,
experimentNumCapabilities :: IO Int
}
defaultExperiment :: Experiment m
defaultExperiment =
Experiment { experimentSpecs = Specs 0 10 0.01 RungeKutta4 SimpleGenerator,
experimentTransform = id,
experimentLocalisation = englishResultLocalisation,
experimentRunCount = 1,
experimentTitle = "Simulation Experiment",
experimentDescription = "",
experimentVerbose = True,
experimentNumCapabilities = getNumCapabilities }
class ExperimentMonadProviding r (m :: * -> *) where
type ExperimentMonad r m :: * -> *
type ExperimentMonadTry r m a = ExperimentMonad r m (Either SomeException a)
class ExperimentMonadProviding r m => ExperimentRendering r m where
data ExperimentContext r m :: *
type ExperimentEnvironment r m :: *
prepareExperiment :: Experiment m -> r -> ExperimentMonad r m (ExperimentEnvironment r m)
renderExperiment :: Experiment m -> r -> [ExperimentReporter r m] -> ExperimentEnvironment r m -> ExperimentMonad r m ()
onExperimentCompleted :: Experiment m -> r -> ExperimentEnvironment r m -> ExperimentMonad r m ()
onExperimentFailed :: Exception e => Experiment m -> r -> ExperimentEnvironment r m -> e -> ExperimentMonad r m ()
data ExperimentGenerator r m =
ExperimentGenerator { generateReporter :: Experiment m -> r -> ExperimentEnvironment r m -> ExperimentMonad r m (ExperimentReporter r m)
}
class ExperimentRendering r m => ExperimentView v r m where
outputView :: v m -> ExperimentGenerator r m
data ExperimentData m =
ExperimentData { experimentResults :: Results m,
experimentPredefinedSignals :: ResultPredefinedSignals m
}
data ExperimentReporter r m =
ExperimentReporter { reporterInitialise :: ExperimentMonad r m (),
reporterFinalise :: ExperimentMonad r m (),
reporterSimulate :: ExperimentData m -> Composite m (),
reporterContext :: ExperimentContext r m
}
runExperiment_ :: (MonadDES m,
ExperimentRendering r m,
Monad (ExperimentMonad r m),
MonadException (ExperimentMonad r m))
=> (m () -> ExperimentMonad r m a)
-> Experiment m
-> [ExperimentGenerator r m]
-> r
-> Simulation m (Results m)
-> ExperimentMonadTry r m ()
runExperiment_ executor0 e generators r simulation =
do x <- runExperimentWithExecutor executor e generators r simulation
return (x >> return ())
where executor = sequence_ . map executor0
runExperiment :: (MonadDES m,
ExperimentRendering r m,
Monad (ExperimentMonad r m),
MonadException (ExperimentMonad r m))
=> (m () -> ExperimentMonad r m a)
-> Experiment m
-> [ExperimentGenerator r m]
-> r
-> Simulation m (Results m)
-> ExperimentMonadTry r m [a]
runExperiment executor0 = runExperimentWithExecutor executor
where executor = sequence . map executor0
runExperimentWithExecutor :: (MonadDES m,
ExperimentRendering r m,
Monad (ExperimentMonad r m),
MonadException (ExperimentMonad r m))
=> ([m ()] -> ExperimentMonad r m a)
-> Experiment m
-> [ExperimentGenerator r m]
-> r
-> Simulation m (Results m)
-> ExperimentMonadTry r m a
runExperimentWithExecutor executor e generators r simulation =
do let specs = experimentSpecs e
runCount = experimentRunCount e
env <- prepareExperiment e r
let c1 =
do reporters <- mapM (\x -> generateReporter x e r env)
generators
forM_ reporters reporterInitialise
let simulate =
do signals <- newResultPredefinedSignals
results <- simulation
let d = ExperimentData { experimentResults = experimentTransform e results,
experimentPredefinedSignals = signals }
((), fs) <- runDynamicsInStartTime $
runEventWith EarlierEvents $
flip runComposite mempty $
forM_ reporters $ \reporter ->
reporterSimulate reporter d
let m1 =
runEventInStopTime $
return ()
m2 =
runEventInStopTime $
disposeEvent fs
mh (SimulationAbort e') =
return ()
finallySimulation (catchSimulation m1 mh) m2
a <- executor $
runSimulations simulate specs runCount
forM_ reporters reporterFinalise
renderExperiment e r reporters env
onExperimentCompleted e r env
return (Right a)
ch z@(SomeException e') =
do onExperimentFailed e r env e'
return (Left z)
catchComp c1 ch
runExperimentByIndex :: (MonadDES m,
ExperimentRendering r m,
Monad (ExperimentMonad r m),
MonadException (ExperimentMonad r m))
=> (m () -> ExperimentMonad r m a)
-> Experiment m
-> [ExperimentGenerator r m]
-> r
-> Simulation m (Results m)
-> Int
-> ExperimentMonadTry r m a
runExperimentByIndex executor e generators r simulation runIndex =
do let specs = experimentSpecs e
runCount = experimentRunCount e
env <- prepareExperiment e r
let c1 =
do reporters <- mapM (\x -> generateReporter x e r env)
generators
forM_ reporters reporterInitialise
let simulate =
do signals <- newResultPredefinedSignals
results <- simulation
let d = ExperimentData { experimentResults = experimentTransform e results,
experimentPredefinedSignals = signals }
((), fs) <- runDynamicsInStartTime $
runEventWith EarlierEvents $
flip runComposite mempty $
forM_ reporters $ \reporter ->
reporterSimulate reporter d
let m1 =
runEventInStopTime $
return ()
m2 =
runEventInStopTime $
disposeEvent fs
mh (SimulationAbort e') =
return ()
finallySimulation (catchSimulation m1 mh) m2
a <- executor $
runSimulationByIndex simulate specs runCount runIndex
forM_ reporters reporterFinalise
renderExperiment e r reporters env
onExperimentCompleted e r env
return (Right a)
ch z@(SomeException e') =
do onExperimentFailed e r env e'
return (Left z)
catchComp c1 ch
runExperimentByIndex_ :: (MonadDES m,
ExperimentRendering r m,
Monad (ExperimentMonad r m),
MonadException (ExperimentMonad r m))
=> (m () -> ExperimentMonad r m a)
-> Experiment m
-> [ExperimentGenerator r m]
-> r
-> Simulation m (Results m)
-> Int
-> ExperimentMonadTry r m ()
runExperimentByIndex_ executor e generators r simulation runIndex =
do x <- runExperimentByIndex executor e generators r simulation runIndex
return (x >> return ())
runExperimentContByIndex :: (MonadDES m,
ExperimentRendering r m,
Monad (ExperimentMonad r m),
MonadException (ExperimentMonad r m))
=> (m () -> ExperimentMonad r m (a, ExperimentMonad r m b))
-> Experiment m
-> [ExperimentGenerator r m]
-> r
-> Simulation m (Results m)
-> Int
-> ExperimentMonadTry r m (a, ExperimentMonadTry r m b)
runExperimentContByIndex executor e generators r simulation runIndex =
do let specs = experimentSpecs e
runCount = experimentRunCount e
env <- prepareExperiment e r
let c1 =
do reporters <- mapM (\x -> generateReporter x e r env)
generators
forM_ reporters reporterInitialise
let simulate =
do signals <- newResultPredefinedSignals
results <- simulation
let d = ExperimentData { experimentResults = experimentTransform e results,
experimentPredefinedSignals = signals }
((), fs) <- runDynamicsInStartTime $
runEventWith EarlierEvents $
flip runComposite mempty $
forM_ reporters $ \reporter ->
reporterSimulate reporter d
let m1 =
runEventInStopTime $
return ()
m2 =
runEventInStopTime $
disposeEvent fs
mh (SimulationAbort e') =
return ()
finallySimulation (catchSimulation m1 mh) m2
(a, m) <- executor $
runSimulationByIndex simulate specs runCount runIndex
let m2 =
do b <- m
forM_ reporters reporterFinalise
renderExperiment e r reporters env
onExperimentCompleted e r env
return (Right b)
mh z@(SomeException e') =
do onExperimentFailed e r env e'
return (Left z)
return (Right (a, catchComp m2 mh))
ch z@(SomeException e') =
do onExperimentFailed e r env e'
return (Left z)
catchComp c1 ch
runExperimentContByIndex_ :: (MonadDES m,
ExperimentRendering r m,
Monad (ExperimentMonad r m),
MonadException (ExperimentMonad r m))
=> (m () -> ExperimentMonad r m (a, ExperimentMonad r m b))
-> Experiment m
-> [ExperimentGenerator r m]
-> r
-> Simulation m (Results m)
-> Int
-> ExperimentMonadTry r m (a, ExperimentMonadTry r m ())
runExperimentContByIndex_ executor e generators r simulation runIndex =
do x <- runExperimentContByIndex executor e generators r simulation runIndex
case x of
Left e -> return (Left e)
Right (a, cont) -> return $ Right (a, cont >> return (Right ()))