examples/model-3-graphical.ss
#lang scheme/gui
; Model 3 - Continuous Simulation Model

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

;; Simulation Parameters
(define end-time 720.0)
(define n-pits 7)
(define initial-furnace-temp 1000.0)

; Data collection variables
(define total-ingots 0)
(define wait-time #f)
(define heat-time #f)
(define leave-temp #f)

;;; Model Definition
(define random-sources (make-random-source-vector 4))

(define furnace-set #f)
(define furnace-temp #f)
(define pit #f)

(define (scheduler)
  (let loop ((i 0))
    (schedule now (ingot i))
    (wait (random-exponential (vector-ref random-sources 0) 1.5))
    (loop (+ i 1))))

(define-process (furnace)
  (set! furnace-temp (make-continuous-variable initial-furnace-temp))
  (work/continuously
    (set-variable-dt!
     furnace-temp (* (- 2500.0 (variable-value furnace-temp)) 0.05))))

(define-process (ingot i)
  (let* ((initial-temp (random-flat (vector-ref random-sources 1) 100.0 200.0))
         (heat-coeff (+ (random-gaussian
                         (vector-ref random-sources 2) 0.05 0.01) 0.07))
         (final-temp (random-flat (vector-ref random-sources 3) 800.0 1000.0))
         (current-temp (make-continuous-variable initial-temp))
         (arrive-time (current-simulation-time))
         (start-time #f))
    (when (= (modulo i 100) 0)
      (accumulate (variable-history current-temp)))
    (with-resource (pit)
      (set-variable-value! wait-time (- (current-simulation-time) arrive-time))
      (set-insert! furnace-set self)
      (set! start-time (current-simulation-time))
      (work/continuously
        until (>= (variable-value current-temp) final-temp)
        (set-variable-dt!
         current-temp
         (* (- (variable-value furnace-temp) (variable-value current-temp))
            heat-coeff)))
      (set-variable-value! heat-time (- (current-simulation-time) start-time))
      (set-variable-value! leave-temp (variable-value current-temp))
      (set-remove! furnace-set self))
    (when (variable-history current-temp)
      (write-special
       (history-plot (variable-history current-temp)
                     (format "Ingot ~a Temperature History" i)))
      (newline))
    (set! total-ingots (+ total-ingots 1))))

(define (stop-sim)
  (printf "Report after ~a Simulated Hours - ~a Ingots Processed~n"
          (current-simulation-time) total-ingots)
  (printf "~n-- Ingot Waiting Time Statistics --~n")
  (printf "Mean Wait Time        = ~a~n" (variable-mean wait-time))
  (printf "Variance              = ~a~n" (variable-variance wait-time))
  (printf "Maximum Wait Time     = ~a~n" (variable-maximum wait-time))
  (printf "~n-- Ingot Heating Time Statistics --~n")
  (printf "Mean Heat Time        = ~a~n" (variable-mean heat-time))
  (printf "Variance              = ~a~n" (variable-variance heat-time))
  (printf "Maximum Heat Time     = ~a~n" (variable-maximum heat-time))
  (printf "Minimum Heat Time     = ~a~n" (variable-minimum heat-time))
  (printf "~n-- Final Temperature Statistics --~n")
  (printf "Mean Leave Temp       = ~a~n" (variable-mean leave-temp))
  (printf "Variance              = ~a~n" (variable-variance leave-temp))
  (printf "Maximum Leave Temp    = ~a~n" (variable-maximum leave-temp))
  (printf "Minimum Leave Temp    = ~a~n" (variable-minimum leave-temp))
  (write-special (history-plot (variable-history leave-temp)
                               "Final Temperature Histogram"))
  (newline)
  (printf "~n-- Furnace Utilization Statistics --~n")
  (printf "Mean No. of Ingots    = ~a~n"
          (variable-mean (set-variable-n furnace-set)))
  (printf "Variance              = ~a~n"
          (variable-variance (set-variable-n furnace-set)))
  (printf "Maximum No. of Ingots = ~a~n"
          (variable-maximum (set-variable-n furnace-set)))
  (printf "Minimum No. of Ingots = ~a~n"
          (variable-minimum (set-variable-n furnace-set)))
  (write-special (history-plot (variable-history (set-variable-n furnace-set))
                               "Furnace Utilization History"))
  (newline)
  (stop-simulation))

(define (initialize)
  (current-simulation-max-step-size (/ 1.0 60.0))
  (set! total-ingots 0)
  (set! wait-time (make-variable))
  (set! heat-time (make-variable))
  (set! leave-temp (make-variable))
  (set! pit (make-resource n-pits))
  (set! furnace-set (make-set))
  (accumulate (variable-history (set-variable-n furnace-set)))
  (tally (variable-statistics wait-time))
  (tally (variable-statistics heat-time))
  (tally (variable-statistics leave-temp))
  (tally (variable-history leave-temp))
  (schedule (at end-time) (stop-sim))
  (schedule (at 0.0) (scheduler))
  (schedule now (furnace))
  )

(define (run-simulation)
  (parameterize
      ((current-output-port (open-output-text-editor text)))
     ;; Initialize graphics
     (begin-busy-cursor)
     (send run-button enable #f)
     (send gauge set-range
           (inexact->exact (round end-time)))
     (send gauge set-value 0)
     (let ((t (make-variable 0.0)))         ; Used for progress gauge
       (with-new-simulation-environment
        (current-simulation-monitor
         (lambda ()
           (set-variable-value! t (current-simulation-time))))
       (monitor after (set-variable-value! t v)
                (send gauge set-value
                      (inexact->exact (round v))))
       (initialize)
       (start-simulation)
       (send run-button enable #t)
       (end-busy-cursor)))))

;; Simulation graphics

(define frame (instantiate frame% ("Furnace Model")))

(define menu-bar (instantiate menu-bar% (frame)))

(define file-menu (instantiate menu% ("&File" menu-bar)))

(define exit-menu-item (instantiate menu-item% ("E&xit" file-menu)
                         (callback (lambda (mi e)
                                     (exit)))))

(define edit-menu (instantiate menu% ("&Edit" menu-bar)))

(define panel-1 (instantiate horizontal-panel% (frame)
                  (alignment '(right center))))

(define run-button (instantiate button% ("&Run" panel-1)
                     (horiz-margin 4)
                     (callback (lambda (b e)
                                 (run-simulation)))))

(define canvas (instantiate editor-canvas% (frame)
                 (min-width 500)
                 (min-height 500)))

(define text (instantiate text% ()))

(send canvas set-editor text)

(define gauge (instantiate gauge% ("Progress" 1 frame)))

(send frame show #t)