{-# LANGUAGE RecursiveDo #-}
-- Example: Port Operations
--
-- It is described in different sources [1, 2]. So, this is chapter 12 of [2] and section 6.13 of [1].
--
-- [1] A. Alan B. Pritsker, Simulation with Visual SLAM and AweSim, 2nd ed.
-- [2] Труб И.И., Объектно-ориентированное моделирование на C++: Учебный курс. - СПб.: Питер, 2006
--
-- A port in Africa is used to load tankers with crude oil for overwater shipment.
-- The port has facilities for loading as many as three tankers simultaneously.
-- The tankers, which arrive at the port every 11 +/- 7 hours, are of three different
-- types. The relative frequency of the various types, and their loading time
-- requirements, are as follows:
--
-- Type Relative Frequency Loading Time, Hours
-- 1 0.25 18 +/- 2
-- 2 0.55 24 +/- 3
-- 3 0.20 36 +/- 4
--
-- There is one tug at the port. Tankers of all types require the services of this tug
-- to move into a berth, and later to move out of a berth. When the tug is available,
-- any berthing or de-berthing activity takes about one hour. Top priority is given to
-- the berthing activity.
--
-- A shipper is considering bidding on a contract to transport oil from the port to
-- the United Kingdom. He has determined that 5 tankers of a particular type would
-- have to be committed to this task to meet contract specifications. These tankers
-- would require 21 +/- 3 hours to load oil at the port. After loading and de-berthing,
-- they would travel to the United Kingdom, offload the oil, and return to the port for
-- reloading. Their round-trip travel time, including offloading, is estimated to be
-- 240 +/- hours.
--
-- A complicated factor is that the port experiences storms. The time between
-- the onset of storms is exponentially distributed with a mean of 48 hours and a
-- storm lasts 4 +/- 2 hours. No tug can start an operation until a storm is over.
--
-- Before the port authorities can commit themselves to accommodating the
-- proposed 5 tankers, the effect of the additional port traffic on the in-port residence
-- time of the current port users must be determined. It is desired to simulate the
-- operation of the port for a one-year period (= 8640 hours) under the proposed new
-- commitment to measure in-port residence time of the proposed additional tankers,
-- as well as the three types of tankers which already use the port. All durations
-- given as ranges are uniformly distributed.
module Model (model) where
import Control.Monad
import Control.Monad.Trans
import Data.Array
import Simulation.Aivika
import qualified Simulation.Aivika.Resource as R
data Tunker =
Tunker { tunkerLoadingTime :: Double,
tunkerType :: Int }
model :: Simulation Results
model = mdo
portTime' <- forM [1..4] $ \i ->
newRef emptySamplingStats
let portTime =
array (1, 4) $ zip [1..] portTime'
berth <-
runEventInStartTime $
R.newFCFSResource 3
tug <-
runEventInStartTime $
R.newFCFSResource 1
let tunkers13 = randomUniformStream 4 18
tunkers4 = takeStream 5 $
randomUniformStream 48 48
runProcessInStartTime $
flip consumeStream tunkers13 $ \x ->
do p <- liftParameter $
randomUniform 0 1
let tp | p <= 0.25 = 1
| p <= 0.25 + 0.55 = 2
| otherwise = 3
case tp of
1 -> liftEvent arv1
2 -> liftEvent arv2
3 -> liftEvent arv3
runProcessInStartTime $
flip consumeStream tunkers4 $ \x ->
liftEvent arv4
let arv1 :: Event ()
arv1 = do
loadingTime <- liftParameter $
randomUniform 16 20
let t = Tunker loadingTime 1
runProcess (port t)
arv2 :: Event ()
arv2 = do
loadingTime <- liftParameter $
randomUniform 21 27
let t = Tunker loadingTime 2
runProcess (port t)
arv3 :: Event ()
arv3 = do
loadingTime <- liftParameter $
randomUniform 32 40
let t = Tunker loadingTime 3
runProcess (port t)
arv4 :: Event ()
arv4 = do
loadingTime <- liftParameter $
randomUniform 18 24
let t = Tunker loadingTime 4
runProcess (port t)
let port :: Tunker -> Process ()
port t = do
t0 <- liftDynamics time
R.requestResource berth
R.requestResource tug
holdProcess 1
R.releaseResource tug
holdProcess (tunkerLoadingTime t)
R.requestResource tug
holdProcess 1
R.releaseResource tug
R.releaseResource berth
t1 <- liftDynamics time
let tp = tunkerType t
liftEvent $
modifyRef (portTime ! tp) $
addSamplingStats (t1 - t0)
when (tp == 4) $
liftEvent $
runProcess $
do randomUniformProcess_ 216 264
liftEvent arv4
storm :: Process ()
storm = do
randomExponentialProcess_ 48
R.decResourceCount tug 1
randomUniformProcess_ 2 6
liftEvent $
R.incResourceCount tug 1
storm
runProcessInStartTime storm
return $
results
[resultSource
"portTime" "Port Time"
portTime,
--
resultSource
"berth" "Berth"
berth,
--
resultSource
"tug" "Tug"
tug ]