Simulation Control (Advanced)

12.1  Example - Harbor Model

;;; Harbor Model

(require (planet "simulation-with-graphics.ss"
                 ("williams" "simulation.plt" 1 0)))
(require (planet "random-source.ss" ("williams" "science.plt")))
(require (planet "random-distributions.ss"
                 ("williams" "science.plt")))

;;; Data collection variables
(define cycle-time #f)

;;; Model definition
(define random-sources (make-random-source-vector 2))

(define dock #f)
(define queue #f)

(define (scheduler)
  (let loop ()
    (make-object ship%)
    (wait (random-exponential (vector-ref random-sources 0)
                              (/ 4.0 3.0)))
    (loop)))

(define-process-class ship%
  (field (unloading-time (random-flat
                          (vector-ref random-sources 1)
                          1.0 2.5)))
  (let ((arrival-time (current-simulation-time)))
    (when (not (harbor-master this 'arriving))
      (set-insert! queue this)
      (suspend-process))
    (work unloading-time)
    (set-remove! dock this)
    (set-variable-value!
     cycle-time (- (current-simulation-time) arrival-time))
    (harbor-master this 'leaving)))

(define ship-unloading-time
  (class-field-accessor ship% unloading-time))

(define set-ship-unloading-time!
  (class-field-mutator ship% unloading-time))

(define (harbor-master ship action)
  (case action
    ((arriving)
     (if (< (set-n dock) 2)
         ;; Dock is not full
         (begin
           (if (set-empty? dock)
               (set-ship-unloading-time!
                ship (/ (ship-unloading-time ship) 2.0))
               (let ((other-ship (set-first dock)))
                 (send other-ship interrupt)
                 (send other-ship set-time
                       (* (send other-ship get-time) 2.0))
                 (send other-ship resume)))
           (set-insert! dock ship)
           #t)
         ;; Dock is full
        #f))
    ((leaving)
     (if (set-empty? queue)
         (if (not (set-empty? dock))
             (let ((other-ship (set-first dock)))
               (send other-ship interrupt)
               (send other-ship set-time
                     (/ (send other-ship get-time) 2.0))
               (send other-ship resume)
               #t))
         (let ((next-ship (set-remove-first! queue)))
           (set-insert! dock next-ship)
           (send next-ship resume)
           #t)))
    (else
     (error 'harbor-master "illegal action value ~a" action))))

(define (stop-sim)
  (printf "Harbor Model - report after ~a simulated days - ~a ships processed~n"
          (current-simulation-time) (variable-n cycle-time))
  (printf "Minimum unload time was ~a~n"
          (variable-minimum cycle-time))
  (printf "Maximum unload time was ~a~n"
          (variable-maximum cycle-time))
  (printf "Average queue of ships waiting to be unloaded was ~a~n"
          (variable-mean (set-variable-n queue)))
  (printf "Maximum queue was ~a~n"
          (variable-maximum (set-variable-n queue)))
  (printf "~a~n"
          (history-plot (variable-history (set-variable-n queue))
                        "History of Waiting Queue"))
  (stop-simulation))

(define (run-simulation)
  (with-new-simulation-environment
   (set! cycle-time (make-variable))
   (tally (variable-statistics cycle-time))
   (set! dock (make-set))
   (set! queue (make-set))
   (accumulate (variable-history (set-variable-n queue)))
   (schedule now (scheduler))
   (schedule (at 80.0) (stop-sim))
   (start-simulation)))

>(run-simulation)
Harbor Model - report after 80.0 simulated days - 65 ships processed
Minimum unload time was 0.5656279138989291
Maximum unload time was 3.893379568241123
Average queue of ships waiting to be unloaded was 0.24532233055969996
Maximum queue was 3

[adv-control-Z-G-1.gif]