#lang scheme/base
(require "simulation-environment.ss"
"process.ss"
"statistics.ss"
"history.ss")
(provide (all-defined-out))
(define-values (struct:variable
variable-constructor
variable?
variable-field-ref
set-variable-field!)
(make-struct-type 'variable #f 10 0))
(define make-variable
(case-lambda
((value)
(variable-constructor value
value
(current-simulation-time)
(make-statistics #t (current-simulation-time))
#f
#f
-1
'()
'()
#f))
(()
(make-variable 'uninitialized))))
(define make-continuous-variable
(case-lambda
((value)
(let ((process (current-simulation-process))
(cv (variable-constructor value
value
(current-simulation-time)
#f #f
#t
-1
'()
'()
#f)))
(set-process-continuous-variables!
process
(cons cv (process-continuous-variables process)))
cv))
(()
(make-continuous-variable 'uninitialized))))
(define (make-vector-variable value-or-length)
(cond ((vector? value-or-length)
(variable-constructor value-or-length
value-or-length
(current-simulation-time)
#f #f
#f
-1
'()
'()
(vector-length value-or-length)))
((exact-positive-integer? value-or-length)
(variable-constructor (make-vector value-or-length 'uninitialized)
(make-vector value-or-length 'uninitialized)
(current-simulation-time)
#f #f
#f
-1
'()
'()
value-or-length))
(else
(error 'make-vector-variable
"expected vector of reals or exact positive integer, given ~a"
value-or-length))))
(define (make-continuous-vector-variable value-or-length)
(cond ((vector? value-or-length)
(let ((process (current-simulation-process))
(cv (variable-constructor value-or-length
value-or-length
(current-simulation-time)
#f #f
#t
-1
'()
'()
(vector-length value-or-length))))
(set-process-continuous-variables!
process
(cons cv (process-continuous-variables process)))
cv))
((exact-positive-integer? value-or-length)
(let ((process (current-simulation-process))
(cv (variable-constructor 'uninitialized
'uninitialized
(current-simulation-time)
#f #f
#t
-1
'()
'()
value-or-length)))
(set-process-continuous-variables!
process
(cons cv (process-continuous-variables process)))
cv))
(else
(error 'make-continuousvector-variable
"expected vector of reals or exact positive integer, given ~a"
value-or-length))))
(define variable-initial-value
(make-struct-field-accessor variable-field-ref 0 'initial-value))
(define set-variable-initial-value!
(make-struct-field-mutator set-variable-field! 0 'initial-value))
(define (variable-value variable)
(let ((value #f))
(for-each
(lambda (monitor)
(when (eq? (car monitor) 'before)
((cdr monitor) variable value)))
(variable-get-monitors variable))
(when (eq? (variable-field-ref variable 1) 'uninitialized)
(error 'variable-value "Attempt to reference an uninitialized variable"))
(if (and (not (= (variable-state-index variable) -1))
(current-simulation-y))
(set! value (vector-ref
(current-simulation-y)
(variable-state-index variable)))
(set! value (variable-field-ref variable 1)))
(for-each
(lambda (monitor)
(when (eq? (car monitor) 'after)
((cdr monitor) variable value)))
(variable-get-monitors variable))
value))
(define (set-variable-value! variable value)
(for-each
(lambda (monitor)
(when (eq? (car monitor) 'before)
((cdr monitor) variable value)))
(variable-set-monitors variable))
(variable-synchronize! variable)
(set-variable-field! variable 1 value)
(when (and (variable-field-ref variable 3)
(not (statistics-time-dependant?
(variable-field-ref variable 3))))
(statistics-tally! (variable-field-ref variable 3) value))
(when (and (variable-field-ref variable 4)
(not (history-time-dependant?
(variable-field-ref variable 4))))
(history-tally! (variable-field-ref variable 4) value))
(for-each
(lambda (monitor)
(when (eq? (car monitor) 'after)
((cdr monitor) variable value)))
(variable-set-monitors variable))
(void))
(define variable-time-last-synchronized
(make-struct-field-accessor variable-field-ref 2 'time-last-synchronized))
(define set-variable-time-last-synchronized!
(make-struct-field-mutator set-variable-field! 2 'time-last-synchronized))
(define (variable-statistics variable)
(variable-synchronize! variable)
(variable-field-ref variable 3))
(define set-variable-statistics!
(make-struct-field-mutator set-variable-field! 3 'statistics))
(define (variable-history variable)
(variable-synchronize! variable)
(variable-field-ref variable 4))
(define set-variable-history!
(make-struct-field-mutator set-variable-field! 4 'history))
(define variable-continuous?
(make-struct-field-accessor variable-field-ref 5 'continuous?))
(define set-variable-continuous?!
(make-struct-field-mutator set-variable-field! 5 'continuous?))
(define variable-state-index
(make-struct-field-accessor variable-field-ref 6 'state-index))
(define set-variable-state-index!
(make-struct-field-mutator set-variable-field! 6 'state-index))
(define variable-get-monitors
(make-struct-field-accessor variable-field-ref 7 'get-monitors))
(define set-variable-get-monitors!
(make-struct-field-mutator set-variable-field! 7 'get-monitors))
(define variable-set-monitors
(make-struct-field-accessor variable-field-ref 8 'set-monitors))
(define set-variable-set-monitors!
(make-struct-field-mutator set-variable-field! 8 'set-monitors))
(define variable-vector-length
(make-struct-field-accessor variable-field-ref 9 'vector-length))
(define set-variable-vector-length!
(make-struct-field-mutator set-variable-field! 9 'vector-length))
(define (variable-dt variable)
(if (and (not (= (variable-state-index variable) -1))
(current-simulation-dydt))
(vector-ref
(current-simulation-dydt)
(variable-state-index variable))
(error 'variable-dt
"There is no active work/continuously using the variable")))
(define (set-variable-dt! variable value)
(if (and (not (= (variable-state-index variable) -1))
(current-simulation-dydt))
(vector-set!
(current-simulation-dydt)
(variable-state-index variable)
value)
(error 'set-variable-dt!
"There is no active work/continuously using the variable")))
(define (variable-initialized? variable)
(not (eq? (variable-field-ref variable 1) 'uninitialized)))
(define (variable-synchronize! variable)
(let ((duration (- (current-simulation-time)
(variable-time-last-synchronized variable))))
(when (and (> duration 0.0)
(not (eq? (variable-field-ref variable 1) 'uninitialized)))
(when (and (variable-field-ref variable 3)
(statistics-time-dependant?
(variable-field-ref variable 3)))
(statistics-accumulate!
(variable-field-ref variable 3)
(variable-value variable) duration))
(when (and (variable-field-ref variable 4)
(history-time-dependant?
(variable-field-ref variable 4)))
(history-accumulate!
(variable-field-ref variable 4)
(variable-value variable) duration))
(set-variable-time-last-synchronized!
variable (current-simulation-time)))))
(define (variable-minimum variable)
(statistics-minimum (variable-statistics variable)))
(define (variable-maximum variable)
(statistics-maximum (variable-statistics variable)))
(define (variable-n variable)
(statistics-n (variable-statistics variable)))
(define (variable-sum variable)
(statistics-sum (variable-statistics variable)))
(define (variable-mean variable)
(statistics-mean (variable-statistics variable)))
(define (variable-variance variable)
(statistics-variance (variable-statistics variable)))
(define (variable-standard-deviation variable)
(statistics-standard-deviation (variable-statistics variable)))
(define-syntax accumulate
(syntax-rules (variable-statistics variable-history)
((accumulate (variable-statistics variable))
(let ((statistics (make-statistics #t (current-simulation-time))))
(set-variable-statistics! variable statistics)))
((accumulate (variable-history variable))
(let ((history (make-history #t (current-simulation-time))))
(set-variable-history! variable history)))))
(define-syntax tally
(syntax-rules (variable-statistics variable-history)
((tally (variable-statistics variable))
(let ((statistics (make-statistics #f (current-simulation-time))))
(when (not (eq? (variable-field-ref variable 1) 'uninitialized))
(statistics-tally! statistics (variable-field-ref variable 1)))
(set-variable-statistics! variable statistics)))
((tally (variable-history variable))
(let ((history (make-history #f (current-simulation-time))))
(when (not (eq? (variable-field-ref variable 1) 'uninitialized))
(history-tally! history (variable-field-ref variable 1)))
(set-variable-history! variable history)))))
(define (variable-add-get-monitor! variable when proc)
(let ((mon (cons when proc)))
(set-variable-get-monitors!
variable
(cons mon (variable-get-monitors variable)))
mon))
(define (variable-remove-get-monitor! variable mon)
(set-variable-get-monitors!
variable
(remq mon (variable-get-monitors variable))))
(define (variable-add-set-monitor! variable when proc)
(let ((mon (cons when proc)))
(set-variable-set-monitors!
variable
(cons mon (variable-set-monitors variable)))
mon))
(define (variable-remove-set-monitor! variable mon)
(set-variable-set-monitors!
variable
(remq mon (variable-set-monitors variable))))
(define-syntax monitor
(syntax-rules (before after variable-value set-variable-value!)
((monitor before (variable-value variable)
body ...)
(let ((mon (cons
'before
(lambda (variable)
body ...))))
(set-variable-get-monitors!
variable
(cons mon (variable-get-monitors variable)))))
((monitor after (variable-value variable)
body ...)
(let ((mon (cons
'after
(lambda (variable)
body ...))))
(set-variable-get-monitors!
variable
(cons mon (variable-get-monitors variable)))))
((monitor before (set-variable-value! variable value)
body ...)
(let ((mon (cons
'before
(lambda (variable value)
body ...))))
(set-variable-set-monitors!
variable
(cons mon (variable-set-monitors variable)))))
((monitor after (set-variable-value! variable value)
body ...)
(let ((mon (cons
'after
(lambda (variable value)
body ...))))
(set-variable-set-monitors!
variable
(cons mon (variable-set-monitors variable)))))))