examples/closed-loop-graphical.rkt
#lang racket/gui

(require (planet williams/simulation/simulation-with-graphics))

(define n-runs (make-variable))
(define n-customers (make-variable))
(define n-attendants (make-variable))
(define progress (make-variable))

(define attendant #f)

(define (generator n)
  (for ((i (in-range n)))
    (wait (random-exponential 4.0))
    (schedule #:now (customer i))))

(define-process (customer i)
  (with-resource (attendant)
    (wait/work (random-flat 2.0 10.0))))

(define (run-simulation)
  (parameterize
      ((current-output-port (open-output-text-editor text)))
    (with-new-simulation-environment
     ;; Initialize graphics
     (begin-busy-cursor)
     (send run-button enable #f)
     ;; Start open loop simulation
     (let ((avg-queue-length (make-variable)))
       (tally (variable-statistics avg-queue-length))
       (tally (variable-history avg-queue-length))
       (set-variable-value! progress 0)
       (for ((i (in-range (variable-value n-runs))))
         (with-new-simulation-environment
          (set! attendant (make-resource (variable-value n-attendants)))
          (schedule #:at 0.0 (generator (variable-value n-customers)))
          (start-simulation)
          (set-variable-value!
           avg-queue-length
           (variable-mean (resource-queue-variable-n attendant)))
          (send text erase)
          (printf "Number of experiments = ~a~n"
                  (variable-n avg-queue-length))
          (printf "Minimum average queue length = ~a~n"
                  (variable-minimum avg-queue-length))
          (printf "Maximum average queue length = ~a~n"
                  (variable-maximum avg-queue-length))
          (set-variable-value! progress i)))
       (printf "Mean average queue length = ~a~n"
               (variable-mean avg-queue-length))
       (printf "Variance average queue length = ~a~n"
               (variable-variance avg-queue-length))
       (write-special (history-plot (variable-history avg-queue-length)
                                    "Average Queue Length"))
       (newline))
   ;; Finalize graphics
   (send run-button enable #t)
   (end-busy-cursor))))

;;; Simulation graphics

(define frame
  (instantiate frame%
    ("Graphical Closed Loop Example")))

(define n-runs-slider
  (instantiate variable-slider%
    ("Number of runs" 1 1000 frame)
    (variable n-runs)
    (init-value 100)
    (style '(horizontal vertical-label))))

(define n-customers-slider
  (instantiate variable-slider%
    ("Number of customers per run" 1 1000 frame)
    (variable n-customers)
    (init-value 100)
    (style '(horizontal vertical-label))))

(define n-attendants-slider
  (instantiate variable-slider%
    ("Number of attendents" 1 100 frame)
    (variable n-attendants)
    (init-value 2)
    (style '(horizontal vertical-label))))
                                
(define canvas
  (instantiate editor-canvas%
    (frame)
    (min-width 500)
    (min-height 500)))
(define text (instantiate text% ()))
(send canvas set-editor text)

(define gauge
  (instantiate variable-gauge%
    ("Progress" n-runs frame)
    (variable progress)))

(define run-button
  (instantiate button%
    ("&Run" frame
    (lambda (button event)
      (run-simulation)))))

(send frame show #t)