#lang scheme/base
(require "control.ss")
(provide (all-defined-out))
(define-values (struct:standard-control-state
standard-control-state-constructor
standard-control-state?
standard-control-state-field-ref
set-standard-control-state-field!)
(make-struct-type 'standard-control-state #f 4 0))
(define (make-standard-control-state)
(standard-control-state-constructor 0.0 0.0 0.0 0.0))
(define standard-control-state-eps-abs
(make-struct-field-accessor standard-control-state-field-ref 0 'eps-abs))
(define set-standard-control-state-eps-abs!
(make-struct-field-mutator set-standard-control-state-field! 0 'eps-abs))
(define standard-control-state-eps-rel
(make-struct-field-accessor standard-control-state-field-ref 1 'eps-rel))
(define set-standard-control-state-eps-rel!
(make-struct-field-mutator set-standard-control-state-field! 1 'eps-rel))
(define standard-control-state-a_y
(make-struct-field-accessor standard-control-state-field-ref 2 'a_y))
(define set-standard-control-state-a_y!
(make-struct-field-mutator set-standard-control-state-field! 2 'a_y))
(define standard-control-state-a_dydt
(make-struct-field-accessor standard-control-state-field-ref 3 'a_dydt))
(define set-standard-control-state-a_dydt!
(make-struct-field-mutator set-standard-control-state-field! 3 'a_dydt))
(define (standard-control-init standard-control-state
eps-abs eps-rel a_y a_dydt)
(when (< eps-abs 0.0)
(error 'standard-control-init "eps-abs is negative"))
(when (< eps-rel 0.0)
(error 'standard-control-init "eps-rel is negative"))
(when (< a_y 0.0)
(error 'standard-control-init "a_y is negative"))
(when (< a_dydt 0.0)
(error 'standard-control-init "a_dydt is negative"))
(set-standard-control-state-eps-abs! standard-control-state eps-abs)
(set-standard-control-state-eps-rel! standard-control-state eps-rel)
(set-standard-control-state-a_y! standard-control-state a_y)
(set-standard-control-state-a_dydt! standard-control-state a_dydt))
(define (standard-control-h-adjust state dim ord y y-err yp h)
(let ((eps-abs (standard-control-state-eps-abs state))
(eps-rel (standard-control-state-eps-rel state))
(a_y (standard-control-state-a_y state))
(a_dydt (standard-control-state-a_dydt state))
(s 0.9)
(h-old (unbox h))
(rmax -inf.0))
(do ((i 0 (+ i 1)))
((= i dim) (void))
(let* ((D0 (+ (* eps-rel
(+ (* a_y (abs (vector-ref y i)))
(* a_dydt (abs (* h-old (vector-ref yp i))))))
eps-abs))
(r (/ (abs (vector-ref y-err i)) (abs D0))))
(set! rmax (max r rmax))))
(let/ec exit
(cond ((> rmax 1.1)
(let ((r (/ s (expt rmax (/ 1.0 ord)))))
(when (< r 0.2)
(set! r 0.2))
(set-box! h (* r h-old))
(exit -1)))
((< rmax 0.5)
(let ((r (/ s (expt rmax (/ 1.0 (+ ord 1.0))))))
(when (> r 5.0)
(set! r 5.0))
(when (< r 1.0) (set! r 1.0))
(set-box! h (* r h-old))
(exit 1)))
(else
0)))))
(define standard-control-type
(make-ode-control-type
"standard"
make-standard-control-state
standard-control-init
standard-control-h-adjust))
(define (standard-control-new eps-abs eps-rel a_y a_dydt)
(let ((control (make-ode-control standard-control-type)))
(ode-control-init control eps-abs eps-rel a_y a_dydt)
control))
(define (control-y-new eps-abs eps-rel)
(standard-control-new eps-abs eps-rel 1.0 0.0))
(define (control-yp-new eps-abs eps-rel)
(standard-control-new eps-abs eps-rel 0.0 1.0))