aivika-3.1: examples/WorkStationsInSeries.hs
-- Example: Work Stations in Series
--
-- This is a model of two work stations connected in a series and separated by finite queues.
--
-- It is described in different sources [1, 2]. So, this is chapter 7 of [2] and section 5.14 of [1].
--
-- [1] A. Alan B. Pritsker, Simulation with Visual SLAM and AweSim, 2nd ed.
--
-- [2] Труб И.И., Объектно-ориентированное моделирование на C++: Учебный курс. - СПб.: Питер, 2006
import Prelude hiding (id, (.))
import Control.Monad
import Control.Monad.Trans
import Control.Arrow
import Control.Category (id, (.))
import Simulation.Aivika
import Simulation.Aivika.Queue
-- | The simulation specs.
specs = Specs { spcStartTime = 0.0,
spcStopTime = 300.0,
spcDT = 0.1,
spcMethod = RungeKutta4,
spcGeneratorType = SimpleGenerator }
-- the mean delay of the input arrivals distributed exponentially
meanOrderDelay = 0.4
-- the capacity of the queue before the first work places
queueMaxCount1 = 4
-- the capacity of the queue before the second work places
queueMaxCount2 = 2
-- the mean processing time distributed exponentially in
-- the first work stations
meanProcessingTime1 = 0.25
-- the mean processing time distributed exponentially in
-- the second work stations
meanProcessingTime2 = 0.5
-- the number of the first work stations
-- (in parallel but the commented code allocates them sequentially)
workStationCount1 = 1
-- the number of the second work stations
-- (in parallel but the commented code allocates them sequentially)
workStationCount2 = 1
-- create a work station (server) with the exponential processing time
newWorkStationExponential meanTime =
newServer $ \a ->
do holdProcess =<<
(liftParameter $
randomExponential meanTime)
return a
model :: Simulation Results
model = do
-- it will gather the statistics of the processing time
arrivalTimer <- newArrivalTimer
-- define a stream of input events
let inputStream = randomExponentialStream meanOrderDelay
-- create a queue before the first work stations
queue1 <-
runEventInStartTime $
newFCFSQueue queueMaxCount1
-- create a queue before the second work stations
queue2 <-
runEventInStartTime $
newFCFSQueue queueMaxCount2
-- create the first work stations (servers)
workStation1s <- forM [1 .. workStationCount1] $ \_ ->
newWorkStationExponential meanProcessingTime1
-- create the second work stations (servers)
workStation2s <- forM [1 .. workStationCount2] $ \_ ->
newWorkStationExponential meanProcessingTime2
-- processor for the queue before the first work station
let queueProcessor1 =
queueProcessor
(\a -> liftEvent $ enqueueOrLost_ queue1 a)
(dequeue queue1)
-- processor for the queue before the second work station
let queueProcessor2 =
queueProcessor
(enqueue queue2)
(dequeue queue2)
-- the entire processor from input to output
let entireProcessor =
queueProcessor1 >>>
processorParallel (map serverProcessor workStation1s) >>>
-- processorSeq (map serverProcessor workStation1s) >>>
queueProcessor2 >>>
processorParallel (map serverProcessor workStation2s) >>>
-- processorSeq (map serverProcessor workStation2s) >>>
arrivalTimerProcessor arrivalTimer
-- start simulating the model
runProcessInStartTime $
sinkStream $ runProcessor entireProcessor inputStream
-- return the simulation results
return $
results
[resultSource
"queue1" "Queue no. 1"
queue1,
--
resultSource
"workStation1s" "Work Stations of line no. 1"
workStation1s,
--
resultSource
"queue2" "Queue no. 2"
queue2,
--
resultSource
"workStation2s" "Work Stations of line no. 2"
workStation2s,
--
resultSource
"arrivalTimer" "The arrival timer"
arrivalTimer]
modelSummary :: Simulation Results
modelSummary =
fmap resultSummary model
main =
printSimulationResultsInStopTime
printResultSourceInEnglish
-- model specs
modelSummary specs