-- Example: A Truck Hauling Situation
--
-- It is described in different sources [1, 2]. So, this is chapter 9 of [2] and section 7.16 of [1].
--
-- The system to be modeled in this example consists of one bulldozer, four trucks,
-- and two man-machine loaders. The bulldozer stockpiles material for the loaders.
-- Two piles of material must be stocked prior to the initiation of any load operation.
-- The time for the bulldozer to stockpile material is Erlang distributed and consists
-- of the sum of two exponential variables each with a men of 4. (This corresponds to
-- an Erlang variable with a mean of 8 and a variance of 32.) In addition to this
-- material, a loader and an unloaded truck must be available before the loading
-- operations can begin. Loading time is exponentially distributed with a mean time of
-- 14 minutes for server 1 and 12 minutes for server 2.
--
-- After a truck is loaded, it is hauled, then dumped and must be returned before
-- the truck is available for further loading. Hauling time is normally distributed.
-- When loaded, the average hauling time is 22 minutes. When unloaded, the average
-- time is 18 minutes. In both cases, the standard deviation is 3 minutes. Dumping
-- time is uniformly distributed between 2 and 8 minutes. Following a loading
-- operation, the loaded must rest for a 5 minute period before he is available
-- to begin loading again. The system is to be analyzed for 8 hours and all operations
-- in progress at the end of 8 hours should be completed before terminating
-- the operations for a run.
--
-- [1] A. Alan B. Pritsker, Simulation with Visual SLAM and AweSim, 2nd ed.
-- [2] Труб И.И., Объектно-ориентированное моделирование на C++: Учебный курс. - СПб.: Питер, 2006
module Model (model) where
import Control.Monad
import Control.Monad.Trans
import Control.Arrow
import Data.Monoid
import Data.List
import Data.Array
import Simulation.Aivika
import qualified Simulation.Aivika.Queue.Infinite as IQ
data Truck = Truck
data Pile = Pile
data Loader = Loader1
| Loader2
deriving (Eq, Ord, Show, Ix)
awaitQueuesNonEmpty q1 q2 q3 =
do n1 <- liftEvent $ IQ.queueCount q1
n2 <- liftEvent $ IQ.queueCount q2
n3 <- liftEvent $ IQ.queueCount q3
when (n1 == 0 || n2 == 0 || n3 == 0) $
do let signal = IQ.queueCountChanged_ q1 <>
IQ.queueCountChanged_ q2 <>
IQ.queueCountChanged_ q3
processAwait signal
awaitQueuesNonEmpty q1 q2 q3
-- | The simulation model.
model :: Simulation Results
model = do
truckQueue <- runEventInStartTime IQ.newFCFSQueue
loadQueue <- runEventInStartTime IQ.newFCFSQueue
loaderQueue <- runEventInStartTime IQ.newFCFSQueue
loaderOp1 <- runEventInStartTime $
newRandomExponentialOperation 14
loaderOp2 <- runEventInStartTime $
newRandomExponentialOperation 12
let loaderOps = array (Loader1, Loader2)
[(Loader1, loaderOp1),
(Loader2, loaderOp2)]
let start :: Process ()
start =
do randomErlangProcess_ 4 2
randomErlangProcess_ 4 2
liftEvent $
IQ.enqueue loadQueue Pile
t <- liftDynamics time
when (t <= 480) start
begin :: Process ()
begin =
do awaitQueuesNonEmpty truckQueue loadQueue loaderQueue
truck <- IQ.dequeue truckQueue
pile <- IQ.dequeue loadQueue
loader <- IQ.dequeue loaderQueue
-- the load operation
operationProcess (loaderOps ! loader) ()
-- truck hauling
liftEvent $
do runProcess $
do holdProcess 5
liftEvent $
IQ.enqueue loaderQueue loader
runProcess $
do randomNormalProcess_ 22 3
randomUniformProcess_ 2 8
randomNormalProcess_ 18 3
liftEvent $
IQ.enqueue truckQueue truck
begin
runEventInStartTime $
do forM_ [1..4] $ \i ->
IQ.enqueue truckQueue Truck
IQ.enqueue loaderQueue Loader1
IQ.enqueue loaderQueue Loader2
runProcessInStartTime begin
runProcessInStartTime begin
runProcessInStartTime start
return $
results
[ resultSource
"loadQueue" "Queue Load"
loadQueue,
--
resultSource
"truckQueue" "Queue Trucks"
truckQueue,
--
resultSource
"loaderQueue" "Queue Loader"
loaderQueue,
--
resultSource
"loaderOps" "Loader Operations"
loaderOps]