packages feed

aivika-experiment-chart-4.2: examples/PortOperations/Model.hs

{-# 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 ]