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

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

(define n-runs (make-variable))
(define n-customers (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 ((k (make-variable 0))
           (max-attendants (make-variable)))
       (tally (variable-statistics max-attendants))
       (tally (variable-history max-attendants))
       (set-variable-value! progress 0)
       (for ((i (in-range (variable-value n-runs))))
         (with-new-simulation-environment
          (set! attendant (make-resource +inf.0))
          (schedule #:at 0.0 (generator (variable-value n-customers)))
          (start-simulation)
          (set-variable-value!
           max-attendants
           (variable-maximum (resource-satisfied-variable-n attendant)))
          (send text erase)
          (printf "Number of experiments = ~a~n"
                  (variable-n max-attendants))
          (printf "Minimum maximum attendants = ~a~n"
                  (variable-minimum max-attendants))
          (printf "Maximum maximum attendants = ~a~n"
                  (variable-maximum max-attendants))
          (set-variable-value! k i)))
       (printf "Mean maximum attendants = ~a~n"
               (variable-mean max-attendants))
       (printf "Variance maximum attendants = ~a~n"
               (variable-variance max-attendants))
       (write-special (history-plot (variable-history max-attendants)
                                    "Maximum Attendants")))
     ;; Finalize graphics
     (send run-button enable #t)
     (end-busy-cursor))))

;;; Simulation graphics

(define frame
  (instantiate frame%
    ("Graphical Open 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 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)