--- Raymond Toy <[EMAIL PROTECTED]> wrote: > If it's not too large, could you just send the Lisp callback routines? > That should give some hints on what's happening even if we don't have > the foreign libraries.
I'll send what's manageable. I forgot one level of callback. It's actually: Lisp -> C -> Lisp -> C if you can believe it. Here are the relevant alien definitions. ;; These are C functions called from the Lisp system of equations function. (def-alien-routine get_sysvar_n int) (def-alien-routine get_sysvar_val double (i int)) (def-alien-routine get_sysvar_dotval double (i int)) (def-alien-routine set_sysvar_val void (i int) (x double)) (def-alien-routine set_sysvar_dotval void (i int) (x double)) ;; these C functions are called once per complete simulation (def-alien-routine init_dims void (nsys_var int) (nparam int) ;; this registers the Lisp callback for the system of equations (model (* (function void (double-float))))) (def-alien-routine mem_alloc int) (def-alien-routine mem_free void) (def-alien-routine fill_in int (start_time double) (init_vals (* double-float)) (sa int)) (def-alien-routine init_cvode void (init_vals (* double-float)) (start_time double)) (def-alien-routine sim_model_cvode int (sample_time double)) The system of equations is built dynamically. Slightly edited code for this is included below and an example function is given at the end of the email: (defun cvode-make-MS-model (system sa?) `(progn ,(append '(def-callback MS_model (void (time c-call:double)) (declare (optimize (speed 3) (safety 0)))) ;; this adds some general Lisp code (assign-exo-vars (getv-exogenous-variables) 'time) ;; this adds Lisp code that calls C functions (see below) (cvode-assign-sys-vars) ;; this adds more Lisp code that calls some C functions (cvode-generate-f-equations system sa? t)))) ;; this builds a part of the equations that calls C from ;; Lisp: get_sysvar_val(i), is a simple function that lets ;; Lisp access an array stored in C. (defun cvode-assign-sys-vars () (let ((syslst)) (dotimes (i (length *system-variables*) syslst) (push `(setf (aref *system-variables* ,i) (get_sysvar_val ,i)) syslst)))) ;; here's the declaration of get_sysvar_val from above double get_sysvar_val(int i) {return sys_var.vals[i];} ;; i call this function once for each of n variables for each ;; explicit time step passed to the solver. so, for one full ;; simulation, this function could be called hundreds of ;; times. ;; here's a note that I wrote myself regarding Clisp that might ;; be helpful when thinking about CMUCL: ;;; when clisp calls the function get_sysvar_val, it allocates 16 ;;; bytes of memory in which it stores the return value. each call to ;;; get_sysvar_val grabs 16 more bytes, which can add up to a ;;; substantial amount of memory (and GC calls) during simulation. ;;; so, we duplicate the values of the system variables locally (i.e., in ;;; Lisp) to speed up access time and to avoid unnecessary garbage. Finally, here is an example system of equations generated during runtime. (DEF-CALLBACK MS_MODEL (VOID (TIME DOUBLE)) (DECLARE (OPTIMIZE (SPEED 3) (SAFETY 0))) (SETF (AREF *SYSTEM-VARIABLES* 1) (GET_SYSVAR_VAL 1)) (SETF (AREF *SYSTEM-VARIABLES* 0) (GET_SYSVAR_VAL 0)) (SET_SYSVAR_DOTVAL 1 (EQUATION-AGGREGATOR #<Function + {101AEC21}> (* -1.0d0 (THE DOUBLE-FLOAT (AREF *MODEL-CONSTANTS* 3)) (THE DOUBLE-FLOAT (AREF *SYSTEM-VARIABLES* 1)) (THE DOUBLE-FLOAT (AREF *SYSTEM-VARIABLES* 0))) (* (THE DOUBLE-FLOAT (AREF *MODEL-CONSTANTS* 1)) (THE DOUBLE-FLOAT (AREF *SYSTEM-VARIABLES* 1)) (- 1 (* (THE DOUBLE-FLOAT (AREF *MODEL-CONSTANTS* 0)) (THE DOUBLE-FLOAT (AREF *SYSTEM-VARIABLES* 1))))))) (SET_SYSVAR_DOTVAL 0 (EQUATION-AGGREGATOR #<Function + {101AEC21}> (* (THE DOUBLE-FLOAT (AREF *MODEL-CONSTANTS* 4)) (THE DOUBLE-FLOAT (AREF *MODEL-CONSTANTS* 3)) (THE DOUBLE-FLOAT (AREF *SYSTEM-VARIABLES* 1)) (THE DOUBLE-FLOAT (AREF *SYSTEM-VARIABLES* 0))) (* -1.0d0 (THE DOUBLE-FLOAT (AREF *MODEL-CONSTANTS* 2)) (THE DOUBLE-FLOAT (AREF *SYSTEM-VARIABLES* 0))))))