-- It corresponds to model MachRep3 described in document -- Introduction to Discrete-Event Simulation and the SimPy Language -- [http://heather.cs.ucdavis.edu/~matloff/156/PLN/DESimIntro.pdf]. -- SimPy is available on [http://simpy.sourceforge.net/]. -- -- The model description is as follows. -- -- Variation of models MachRep1, MachRep2. Two machines, but -- sometimes break down. Up time is exponentially distributed with mean -- 1.0, and repair time is exponentially distributed with mean 0.5. In -- this example, there is only one repairperson, and she is not summoned -- until both machines are down. We find the proportion of up time. It -- should come out to about 0.45. import System.Random import Control.Monad import Control.Monad.Trans import Simulation.Aivika.Specs import Simulation.Aivika.Simulation import Simulation.Aivika.Dynamics import Simulation.Aivika.Event import Simulation.Aivika.Ref import Simulation.Aivika.QueueStrategy import Simulation.Aivika.Resource import Simulation.Aivika.Process import Simulation.Aivika.Experiment import Simulation.Aivika.Experiment.Histogram import Simulation.Aivika.Experiment.LastValueView import Simulation.Aivika.Experiment.TableView import Simulation.Aivika.Experiment.TimeSeriesView import Simulation.Aivika.Experiment.DeviationChartView import Simulation.Aivika.Experiment.FinalHistogramView import Simulation.Aivika.Experiment.FinalXYChartView import Simulation.Aivika.Experiment.ExperimentSpecsView import Simulation.Aivika.Experiment.FinalStatsView specs = Specs { spcStartTime = 0.0, spcStopTime = 1000.0, spcDT = 1.0, spcMethod = RungeKutta4 } experiment :: Experiment experiment = defaultExperiment { experimentSpecs = specs, experimentRunCount = 200, experimentDescription = "Experiment Description", experimentGenerators = [outputView defaultExperimentSpecsView, outputView $ defaultDeviationChartView { deviationChartSeries = [Left "t", Right "x"] }, outputView $ defaultFinalXYChartView { finalXYChartPlotTitle = "The proportion up time for simulation runs < 50 and > 100", finalXYChartXSeries = Just "n", finalXYChartYSeries = [Right "x"], finalXYChartPredicate = do i <- liftSimulation simulationIndex return $ (i < 50) || (i > 100) }, outputView $ defaultFinalHistogramView { finalHistogramPlotTitle = "Final Histogram (Default)", finalHistogramSeries = ["x", "x"] }, outputView $ defaultFinalHistogramView { finalHistogramPlotTitle = "Final Histogram (Default)", finalHistogramSeries = ["t", "t"] }, outputView $ defaultFinalStatsView { finalStatsSeries = ["x"] }, outputView $ defaultFinalHistogramView { finalHistogramPlotTitle = "Final Histogram (Default)", finalHistogramSeries = ["x"] }, outputView $ defaultFinalHistogramView { finalHistogramPlotTitle = "Final Histogram (Bin Size = 0.001)", finalHistogramBuild = histogramBinSize 0.001, finalHistogramSeries = ["x"] }, outputView $ defaultFinalHistogramView { finalHistogramPlotTitle = "Final Histogram (Bin Num = 10)", finalHistogramBuild = histogramNumBins 10, finalHistogramSeries = ["x"] }, outputView $ defaultFinalHistogramView { finalHistogramPlotTitle = "Final Histogram (Sturges)", finalHistogramBuild = histogram binSturges, finalHistogramSeries = ["x"] }, outputView $ defaultFinalHistogramView { finalHistogramPlotTitle = "Final Histogram (Doane)", finalHistogramBuild = histogram binDoane, finalHistogramSeries = ["x"] }, outputView $ defaultFinalHistogramView { finalHistogramPlotTitle = "Final Histogram (Sqrt)", finalHistogramBuild = histogram binSqrt, finalHistogramSeries = ["x"] }, outputView $ defaultFinalHistogramView { finalHistogramPlotTitle = "Final Histogram (Scott)", finalHistogramBuild = histogram binScott, finalHistogramSeries = ["x"] } ] } upRate = 1.0 / 1.0 -- reciprocal of mean up time repairRate = 1.0 / 0.5 -- reciprocal of mean repair time exprnd :: Double -> IO Double exprnd lambda = do x <- getStdRandom random return (- log x / lambda) model :: Simulation ExperimentData model = do -- number of machines currently up nUp <- newRef 2 -- total up time for all machines totalUpTime <- newRef 0.0 repairPerson <- newResource FCFS 1 pid1 <- newProcessId pid2 <- newProcessId let machine :: ProcessId -> Process () machine pid = do startUpTime <- liftDynamics time upTime <- liftIO $ exprnd upRate holdProcess upTime finishUpTime <- liftDynamics time liftEvent $ modifyRef totalUpTime (+ (finishUpTime - startUpTime)) liftEvent $ modifyRef nUp $ \a -> a - 1 nUp' <- liftEvent $ readRef nUp if nUp' == 1 then passivateProcess else liftEvent $ do n <- resourceCount repairPerson when (n == 1) $ reactivateProcess pid requestResource repairPerson repairTime <- liftIO $ exprnd repairRate holdProcess repairTime liftEvent $ modifyRef nUp $ \a -> a + 1 releaseResource repairPerson machine pid runProcessInStartTime IncludingCurrentEvents pid1 (machine pid2) runProcessInStartTime IncludingCurrentEvents pid2 (machine pid1) let result = do x <- readRef totalUpTime y <- liftDynamics time return $ x / (2 * y) experimentDataInStartTime [("x", seriesEntity "The proportion of up time" result), ("t", seriesEntity "Total up time" totalUpTime), ("n", seriesEntity "Simulation run" simulationIndex)] main = runExperiment experiment model