source: project/release/4/nemo/tags/5.1/nemo-nmodl.scm @ 25871

Last change on this file since 25871 was 25871, checked in by Ivan Raikov, 9 years ago

nemo release 5.1

File size: 36.8 KB
Line 
1;;       
2;;
3;; TODO: consider an option for using tau/inf model descriptions directly
4;;
5;; An extension for translating NEMO models to NMODL descriptions.
6;;
7;; Copyright 2008-2012 Ivan Raikov and the Okinawa Institute of Science and Technology
8;;
9;; This program is free software: you can redistribute it and/or
10;; modify it under the terms of the GNU General Public License as
11;; published by the Free Software Foundation, either version 3 of the
12;; License, or (at your option) any later version.
13;;
14;; This program is distributed in the hope that it will be useful, but
15;; WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17;; General Public License for more details.
18;;
19;; A full copy of the GPL license can be found at
20;; <http://www.gnu.org/licenses/>.
21;;
22
23(module nemo-nmodl
24
25        (nemo:nmodl-translator)
26
27        (import scheme chicken utils data-structures lolevel srfi-1 srfi-13 )
28
29        (require-extension lolevel datatype matchable strictly-pretty 
30                           environments varsubst datatype 
31                           nemo-core nemo-utils nemo-gate-complex)
32
33(define nmodl-builtin-consts
34  `(celsius diam))
35
36(define nmodl-ops
37  `(+ - * / > < <= >= = ^))
38
39(define builtin-fns
40  `(+ - * / pow neg abs atan asin acos sin cos exp ln
41      sqrt tan cosh sinh tanh hypot gamma lgamma log10 log2 log1p ldexp cube
42      > < <= >= = and or round ceiling floor max min
43      fpvector-ref))
44
45
46(define (nmodl-name s)
47  (let ((cs (string->list (->string s))))
48    (let loop ((lst (list)) (cs cs))
49      (if (null? cs) (string->symbol (list->string (reverse lst)))
50          (let* ((c (car cs))
51                 (c1 (cond ((or (char-alphabetic? c) (char-numeric? c) (char=? c #\_)) c)
52                           (else #\_))))
53            (loop (cons c1 lst) (cdr cs)))))))
54                           
55
56(define (nmodl-state-name n s)
57  (nmodl-name (if n (s+ n s) s)))
58
59(define (rhsvars rhs)
60  (enum-freevars rhs (list) (list)))
61
62(define (rhsexpr/NMODL expr)
63  (match expr 
64         (('if . es)  `(if . ,(map (lambda (x) (rhsexpr/NMODL x)) es)))
65         (('let bnds body) `(let ,(map (lambda (x) (list (car x) (rhsexpr/NMODL (cadr x)))) bnds) ,(rhsexpr/NMODL body)))
66         (('pow x y)  (if (and (integer? y)  (positive? y))
67                          (if (> y 1)  (let ((tmp (gensym "x")))
68                                         `(let ((,tmp ,x)) (* . ,(list-tabulate (inexact->exact y) (lambda (i) tmp)))))
69                              x)
70                            expr))
71         ((s . es)    (if (symbol? s)   (cons (if (member s builtin-fns) s (nmodl-name s)) (map (lambda (x) (rhsexpr/NMODL x)) es)) expr))
72         (id          (if (symbol? id) (nmodl-name id) id))))
73
74
75(define-syntax pp
76  (syntax-rules ()
77    ((pp indent val ...) (ppf indent (quasiquote val) ...))))
78
79
80(define (letblk/NMODL e1 e2)
81  (cond ((equal? e1 (doc:empty)) (doc:group (doc:nest 2 e2)))
82        ((equal? e2 (doc:empty)) (doc:group (doc:nest 2 e1)))
83        (else (doc:connect (doc:group (doc:nest 2 e1))
84                           (doc:group (doc:nest 2 e2))))))
85       
86(define ifthen/NMODL  (doc:ifthen 0 (doc:text "if") (doc:text "") (doc:text "else")))
87(define group/NMODL   (doc:block 2 (doc:text "(") (doc:text ")")))
88(define block/NMODL   (doc:block 2 (doc:text "{") (doc:text "}")))
89(define binop/NMODL   (doc:binop 2))
90
91(define (format-op/NMODL indent op args)
92  (let ((op1 (doc:text (->string op))))
93    (let ((res
94           (if (null? args) op1
95               (match args
96                      ((x)           (doc:connect op1 x))
97                      ((x y)         (binop/NMODL x op1 y))
98                      ((x y z)       (binop/NMODL x op1 (binop/NMODL y op1 z)))
99                      (lst           (let* ((n   (length lst))
100                                            (n/2 (inexact->exact (round (/ n 2)))))
101                                       (binop/NMODL (format-op/NMODL indent op (take lst n/2 )) op1 
102                                                    (format-op/NMODL indent op (drop lst n/2 )))))))))
103      res)))
104
105
106(define (format-conseq-op/NMODL indent op args)
107  (let ((op1 (doc:text (->string op))))
108    (if (null? args) op1
109        (match args
110               ((x)      (doc:concat (list op1 x)))
111               ((x y)    (doc:concat (intersperse (list x op1 y) (doc:space))))
112               ((x y z)  (doc:concat (intersperse (list x op1 y op1 z) (doc:space))))
113               (lst      (let* ((n   (length lst))
114                                (n/2 (inexact->exact (round (/ n 2)))))
115                           (doc:concat 
116                            (intersperse 
117                             (list (format-conseq-op/NMODL indent op (take lst n/2 )) op1 
118                                   (format-conseq-op/NMODL indent op (drop lst n/2 )))
119                             (doc:space)))))))))
120
121(define (format-fncall/NMODL indent op args)
122  (let ((op1 (doc:text (->string op))))
123    (doc:cons op1 (group/NMODL ((doc:list indent identity (lambda () (doc:text ", "))) args)))))
124
125(define (name-normalize expr)
126  (match expr 
127         (('if c t e)  `(if ,(name-normalize c) ,(name-normalize t) ,(name-normalize e)))
128         (('let bs e)
129          `(let ,(map (lambda (b) `(,(car b) ,(name-normalize (cadr b)))) bs) ,(name-normalize e)))
130         ((f . es) 
131          (cons f (map name-normalize es)))
132         ((? symbol? ) (nmodl-name expr))
133         ((? atom? ) expr)))
134
135
136(define (canonicalize-expr/NMODL expr)
137  (let ((subst-convert  (subst-driver (lambda (x) (and (symbol? x) x)) 
138                                      nemo:binding? identity nemo:bind 
139                                      nemo:subst-term)))
140    (let* ((expr1 (if-convert expr))
141           (expr2 (subst-convert expr1 subst-empty))
142           (expr3 (let-lift expr2))
143           (expr4 (name-normalize expr3)))
144      expr4)))
145
146
147(define (format-expr/NMODL indent expr . rest) 
148  (let-optionals rest ((rv #f))
149   (let ((indent+ (+ 2 indent)))
150    (match expr
151       (('let bindings body)
152        (letblk/NMODL
153         (fold-right 
154           (lambda (x ax)
155             (let ((res
156                    (letblk/NMODL
157                     (match (second x)
158                            (('if c t e)
159                             (ifthen/NMODL
160                              (group/NMODL (format-expr/NMODL indent c))
161                              (block/NMODL (format-expr/NMODL indent t (first x)))
162                              (block/NMODL (format-expr/NMODL indent e (first x)))))
163                            (else
164                             (format-op/NMODL indent+ " = "
165                                              (list (format-expr/NMODL indent (first x) )
166                                                    (format-expr/NMODL indent (second x))))))
167                     ax)))
168               res
169               ))
170           (doc:empty) bindings)
171         (match body
172                (('let _ _) (format-expr/NMODL indent body rv))
173                (else
174                 (let ((body1 (doc:nest indent (format-expr/NMODL indent body))))
175                   (if rv  (format-op/NMODL indent " = " (list (format-expr/NMODL indent+ rv ) body1))
176                       body1))))))
177       
178       (('if . rest) (error 'format-expr/NMODL "invalid if statement " expr))
179
180       ((op . rest) 
181       (let ((op (case op ((pow)  '^) ((abs) 'fabs) ((ln) 'log) (else op))))
182         (let ((fe
183                (if (member op nmodl-ops)
184                    (let ((mdiv?  (any (lambda (x) (match x (('* . _) #t) (('/ . _) #t) (else #f))) rest))
185                          (mul?   (any (lambda (x) (match x (('* . _) #t) (else #f))) rest))
186                          (plmin? (any (lambda (x) (match x (('+ . _) #t) (('- . _) #t) (else #f))) rest)))
187                      (case op
188                        ((/) 
189                         (format-op/NMODL indent op 
190                                          (map (lambda (x) 
191                                                 (let ((fx (format-expr/NMODL indent+ x)))
192                                                   (if (or (symbol? x) (number? x)) fx
193                                                       (if (or mul? plmin?) (group/NMODL fx) fx)))) rest)))
194                        ((*) 
195                         (format-op/NMODL indent op 
196                                          (map (lambda (x) 
197                                                 (let ((fx (format-expr/NMODL indent+ x)))
198                                                   (if (or (symbol? x) (number? x)) fx
199                                                       (if plmin? (group/NMODL fx) fx)))) rest)))
200                       
201                        ((^) 
202                         (format-op/NMODL indent op 
203                                          (map (lambda (x) 
204                                                 (let ((fx (format-expr/NMODL indent+ x)))
205                                                   (if (or (symbol? x)  (number? x)) fx
206                                                       (if (or mdiv? plmin?) (group/NMODL fx) fx)))) rest)))
207                       
208                        (else
209                         (format-op/NMODL indent op 
210                                          (map (lambda (x) 
211                                                 (let ((fx (format-expr/NMODL indent+ x))) fx)) rest)))))
212                   
213                    (let ((op (case op ((neg) '-) (else op))))
214                      (format-fncall/NMODL indent op (map (lambda (x) (format-expr/NMODL indent+ x)) rest))))))
215           (if rv 
216               (format-op/NMODL indent " = " (list (format-expr/NMODL indent+ rv ) fe))
217               fe))))
218     
219      (else  (let ((fe (doc:text (->string expr))))
220               (if rv 
221                   (format-op/NMODL indent " = " (list (format-expr/NMODL indent+ rv ) fe))
222                   fe)))))))
223               
224
225         
226(define (expr->string/NMODL x . rest)
227  (let-optionals rest ((rv #f) (width 72))
228    (sdoc->string (doc:format width (format-expr/NMODL 2 x rv)))))
229 
230
231(define (format-conseq/NMODL indent expr . rest) 
232  (let-optionals rest ((rv #f))
233   (let ((indent+ (+ 2 indent)))
234    (match expr
235       (('let bindings body)
236        (letblk/NMODL
237         (fold-right 
238           (lambda (x ax)
239             (letblk/NMODL
240              (match (second x)
241                     (('if c t e)
242                      (ifthen/NMODL
243                       (group/NMODL (format-conseq/NMODL indent c))
244                       (block/NMODL (format-conseq/NMODL indent t (first x)))
245                       (block/NMODL (format-conseq/NMODL indent e (first x)))))
246                     (else
247                      (format-conseq-op/NMODL indent+ " = "
248                                       (list (format-conseq/NMODL indent (first x) )
249                                             (format-conseq/NMODL indent (second x))))))
250              ax))
251           (doc:empty) bindings)
252         (let ((body1 (doc:nest indent (format-conseq/NMODL indent body))))
253           (if rv  (format-conseq-op/NMODL indent " = " (list (format-conseq/NMODL indent+ rv ) body1))
254               body1))))
255       
256       (('if . rest) (error 'format-conseq/NMODL "invalid if statement " expr))
257
258       ((op . rest) 
259        (let ((op (case op ((pow)  '^) ((abs) 'fabs) (else op))))
260          (let ((fe
261                (if (member op nmodl-ops)
262                    (let ((mdiv?  (any (lambda (x) (match x (('* . _) #t) (('/ . _) #t) (else #f))) rest))
263                          (mul?   (any (lambda (x) (match x (('* . _) #t) (else #f))) rest))
264                          (plmin? (any (lambda (x) (match x (('+ . _) #t) (('- . _) #t) (else #f))) rest)))
265                      (case op
266                        ((/) 
267                         (format-conseq-op/NMODL indent op 
268                                          (map (lambda (x) 
269                                                 (let ((fx (format-conseq/NMODL indent+ x)))
270                                                   (if (or (symbol? x) (number? x)) fx
271                                                       (if (or mul? plmin?) (group/NMODL fx) fx)))) rest)))
272                        ((*) 
273                         (format-conseq-op/NMODL indent op 
274                                          (map (lambda (x) 
275                                                 (let ((fx (format-conseq/NMODL indent+ x)))
276                                                   (if (or (symbol? x) (number? x)) fx
277                                                       (if plmin? (group/NMODL fx) fx)))) rest)))
278                       
279                        ((^) 
280                         (format-conseq-op/NMODL indent op 
281                                          (map (lambda (x) 
282                                                 (let ((fx (format-conseq/NMODL indent+ x)))
283                                                   (if (or (symbol? x)  (number? x)) fx
284                                                       (if (or mdiv? plmin?) (group/NMODL fx) fx)))) rest)))
285                       
286                        (else
287                         (format-conseq-op/NMODL indent op 
288                                          (map (lambda (x) 
289                                                 (let ((fx (format-conseq/NMODL indent+ x))) fx)) rest)))))
290                   
291                    (case op
292                      ((neg) (format-conseq-op/NMODL indent '* (map (lambda (x) (format-conseq/NMODL indent+ x)) 
293                                                             (cons "(-1)" rest))))
294                      (else  (format-fncall/NMODL indent op (map (lambda (x) (format-conseq/NMODL indent+ x)) 
295                                                                 rest)))))))
296
297           (if rv (format-conseq-op/NMODL indent " = " (list (format-conseq/NMODL indent+ rv ) fe)) fe))))
298     
299      (else  (let ((fe (doc:text (->string expr))))
300               (if rv 
301                   (format-conseq-op/NMODL indent " = " (list (format-conseq/NMODL indent+ rv ) fe))
302                   fe)))))))
303               
304
305(define (conserve-conseq->string/NMODL x val . rest)
306  (let-optionals rest ((width 72))
307    (s+ "CONSERVE " (sdoc->string (doc:format width (format-conseq/NMODL 2 x #f))) 
308        " = " (number->string val))))
309 
310
311(define (make-define-fn table? min-v max-v with depend)
312  (lambda (indent n proc)
313    (let ((lst (procedure-data proc))
314          (indent+ (+ 2 indent)))
315      (let ((rt       (lookup-def 'rt lst))
316            (formals  (lookup-def 'formals lst))
317            (vars     (lookup-def 'vars lst))
318            (body     (lookup-def 'body lst)))
319        (pp indent ,nl (FUNCTION ,(nmodl-name n) (,(slp ", " vars)) "{" ))
320        (let* ((body0 (rhsexpr/NMODL body))
321               (body1 (canonicalize-expr/NMODL body0))
322               (lbs   (enum-bnds body1 (list))))
323          (if (not (null? lbs)) (pp indent+ (LOCAL ,(slp ", " lbs))))
324          (if (and table? min-v max-v with)
325              (match vars
326                     (('v)  (pp indent+ (TABLE ,@(if depend `(DEPEND ,depend) `(""))
327                                               FROM ,min-v TO ,max-v WITH ,with)))
328                     (else  (void))))
329          (pp indent+ ,(expr->string/NMODL body1 (nmodl-name n))))
330        (pp indent "}"))) 
331    ))
332
333(define (expeuler dt name rhs)
334  (define (isname? x) (equal? x name))
335  (let ((res 
336         (match rhs
337                ((or ('- A ('* B (and x (? isname?))))
338                     ('+ ('neg ('* B (and x (? isname?)))) A))
339                 (let ((xexp (string->symbol (s+ x 'exp))))
340                   `(let ((,xexp (exp (* (neg ,B) ,dt))))
341                      (+ (* ,x ,xexp)  (* (- 1 ,xexp) (/ ,A ,B))))))
342
343                ((or ('- A ('* (and x (? isname?)) . B))
344                     ('+ ('neg ('* (and x (? isname?)) . B)) A))
345                 (let ((xexp (string->symbol (s+ x 'exp)))
346                       (B1   (if (null? (cdr B)) (car B) `(* ,@B))))
347                   `(let ((,xexp (exp (* (neg ,B1) ,dt))))
348                      (+ (* ,x ,xexp)  (* (- 1 ,xexp) (/ ,A ,B1))))))
349               
350                (('+ ('neg ('* (and x1 (? isname?)) Alpha))
351                     ('* ('- 1 (and x2 (? isname?))) Beta))
352                 (let ((A  Alpha)
353                       (B  `(+ ,Alpha ,Beta)))
354                   (let ((xexp (string->symbol (s+ x1 'exp))))
355                     `(let ((,xexp (exp (* (neg ,B) ,dt))))
356                        (+ (* ,x1 ,xexp) (* (- 1 ,xexp) (/ ,A ,B)))))))
357               
358                (('let bnds body)
359                 `(let ,bnds ,(expeuler dt name body)))
360               
361                (else (nemo:error 'nemo:expeuler ": unable to rewrite equation " rhs 
362                                  "in exponential Euler form")))))
363
364    res))
365 
366
367(define (reaction-transition-eqs n initial open transitions conserve power method)
368  (match-let (((g cnode node-subs)  (transitions-graph n open transitions conserve nmodl-state-name)))
369     (let* ((out-edges  (g 'out-edges))
370            (in-edges   (g 'in-edges))
371            (nodes      ((g 'nodes))))
372       ;; generate differential equations for each state in the transitions system
373      (let ((eqs    (fold (lambda (s ax) 
374                            (if (and cnode (= (first cnode) (first s) )) ax
375                                (let* ((out   (out-edges (first s)))
376                                       (in    (in-edges (first s)))
377                                       (open? (eq? (second s) open))
378                                       (name  (nmodl-name (lookup-def (second s) node-subs))))
379                                  (let* ((rhs1  (cond ((and (not (null? out)) (not (null? in)))
380                                                       `(+ (neg ,(sum (map third out)))
381                                                           ,(sum (map third in))))
382                                                      ((and (not (null? out)) (null? in))
383                                                       `(neg ,(sum (map third out))))
384                                                      ((and (null? out) (not (null? in)))
385                                                       (sum (map third in)))))
386                                         (fbody0 (rhsexpr/NMODL rhs1))
387                                         (fbody1 (case method
388                                                   ((expeuler) (canonicalize-expr/NMODL (expeuler 'dt name fbody0)))
389                                                   (else       (canonicalize-expr/NMODL fbody0)))))
390                                    (cons (list name fbody1) ax))
391                                  )))
392                          (list) nodes)))
393        eqs))))
394
395
396           
397       
398
399(define (reaction-keqs n initial open transitions power)
400  (let* ((subst-convert  (subst-driver (lambda (x) (and (symbol? x) x)) 
401                                       nemo:binding? identity nemo:bind nemo:subst-term))
402         (state-list     (let loop ((lst (list)) (tlst transitions))
403                           (if (null? tlst)  (delete-duplicates lst eq?)
404                               (match (car tlst) 
405                                      (('-> (and (? symbol?) s0) (and (? symbol?) s1) rate-expr)
406                                       (loop (cons* s0 s1 lst) (cdr tlst)))
407                                      (((and (? symbol?) s0) '-> (and (? symbol? s1)) rate-expr)
408                                       (loop (cons* s0 s1 lst) (cdr tlst)))
409                                      (('<-> (and (? symbol?) s0) (and (? symbol?) s1) rate-expr1 rate-expr2)
410                                       (loop (cons* s0 s1 lst) (cdr tlst)))
411                                      (((and (? symbol?) s0) 'M-> (and (? symbol? s1)) rate-expr1 rate-expr2)
412                                       (loop (cons* s0 s1 lst) (cdr tlst)))
413                                      (else
414                                       (nemo:error 'nemo:nmodl-reaction-keqs ": invalid transition equation " 
415                                                   (car tlst) " in state complex " n))
416                                      (else (loop lst (cdr tlst)))))))
417         (state-subs     (fold (lambda (s ax) (subst-extend s (nmodl-state-name n s) ax)) subst-empty state-list)))
418    ;; generate kinetic equations for each edge in the transitions system
419    (list n 
420          (map
421           (lambda (e) 
422             (match e
423                    (('-> s0 s1 rexpr)
424                     (let ((i  (lookup-def s0 state-subs))
425                           (j  (lookup-def s1 state-subs)))
426                       `(-> ,i ,j ,(canonicalize-expr/NMODL 
427                                    (subst-convert rexpr state-subs)))))
428                   
429                    ((s0 '-> s1 rexpr)
430                     (let ((i  (lookup-def s0 state-subs))
431                           (j  (lookup-def s1 state-subs)))
432                       `(-> ,i ,j ,(canonicalize-expr/NMODL 
433                                    (subst-convert rexpr state-subs)))))
434                   
435                    (('<-> s0 s1 rexpr1 rexpr2)
436                     (let ((i  (lookup-def s0 state-subs))
437                           (j  (lookup-def s1 state-subs)))
438                       `(<-> ,i ,j 
439                             ,(canonicalize-expr/NMODL (subst-convert rexpr1 state-subs))
440                             ,(canonicalize-expr/NMODL (subst-convert rexpr2 state-subs)))))
441                   
442                    ((s0 '<-> s1 rexpr1 rexpr2)
443                     (let ((i  (lookup-def s0 state-subs))
444                           (j  (lookup-def s1 state-subs)))
445                       `(<-> ,i ,j 
446                             ,(canonicalize-expr/NMODL (subst-convert rexpr1 state-subs))
447                             ,(canonicalize-expr/NMODL (subst-convert rexpr2 state-subs)))))
448                   
449                   
450                    (else (nemo:error 'nemo:nmodl-reaction-keqs ": invalid transition equation " 
451                                      e " in state complex " n))))
452           transitions))))
453       
454
455
456(define (state-init n init)
457  (let* ((init  (rhsexpr/NMODL init))
458         (init1 (canonicalize-expr/NMODL init)))
459    (list (nmodl-name n) init1)))
460
461
462(define (asgn-eq n rhs)
463  (let* ((fbody   (rhsexpr/NMODL rhs))
464         (fbody1  (canonicalize-expr/NMODL fbody)))
465    (list (nmodl-name n) fbody1)))
466
467
468(define (reaction-eq n open transitions conserve)
469  (list (nmodl-name n) (nmodl-state-name n open)))
470
471(define (poset->reaction-eq-defs poset sys kinetic)
472  (fold-right
473   (lambda (lst ax)
474     (fold  (lambda (x ax) 
475              (match-let (((i . n)  x))
476                         (let ((en (environment-ref sys n)))
477                           (if (nemo:quantity? en)
478                               (cases nemo:quantity en
479                                      (REACTION  (name initial open transitions conserve power) 
480                                                 (cons (reaction-eq name open transitions conserve) ax))
481
482                                      (else  ax))
483                               ax))))
484            ax lst))
485   (list) poset))
486
487
488(define (poset->asgn-eq-defs poset sys)
489  (fold-right
490   (lambda (lst ax)
491     (fold  (lambda (x ax) 
492              (match-let (((i . n)  x))
493                         (let ((en (environment-ref sys n)))
494                           (if (nemo:quantity? en)
495                               (cases nemo:quantity en
496                                      (ASGN  (name value rhs) (cons (asgn-eq name rhs) ax))
497                                      (else  ax))
498                               ax))))
499            ax lst))
500   (list) poset))
501
502
503(define (poset->rate-eq-defs poset sys kinetic method)
504  (fold-right
505   (lambda (lst ax)
506     (fold  (lambda (x ax) 
507              (match-let (((i . n)  x))
508                         (let ((en (environment-ref sys n)))
509                           (if (and (not (member n kinetic)) (nemo:quantity? en))
510                               (cases nemo:quantity en
511                                      (REACTION  (name initial open transitions conserve power) 
512                                                 (append (reaction-transition-eqs name initial open transitions 
513                                                                                  conserve power method) ax))
514                                     
515                                      (RATE (name initial rhs power)
516                                            (let ((fbody0  (rhsexpr/NMODL rhs))
517                                                  (dy      (nmodl-name name )))
518                                              (case method
519                                                ((expeuler) 
520                                                 (cons (list dy (canonicalize-expr/NMODL (expeuler 'dt name fbody0))) 
521                                                       ax))
522                                                (else
523                                                 (cons (list dy (canonicalize-expr/NMODL fbody0)) ax)))))
524
525                                      (else  ax))
526                               ax))))
527            ax lst))
528   (list) poset))
529
530
531(define (poset->kinetic-eq-defs poset sys kinetic)
532  (fold-right
533   (lambda (lst ax)
534     (fold  (lambda (x ax) 
535              (match-let (((i . n)  x))
536                         (let ((en (environment-ref sys n)))
537                           (if (and (member n kinetic) (nemo:quantity? en))
538                               (cases nemo:quantity en
539                                      (REACTION  (name initial open transitions conserve power) 
540                                                 (cons (reaction-keqs name initial open transitions power) ax))
541                                      (else  ax))
542                               ax))))
543            ax lst))
544   (list) poset))
545
546
547(define (poset->state-init-defs poset sys)
548  (fold-right
549   (lambda (lst ax)
550     (fold  (lambda (x ax) 
551              (match-let (((i . n)  x))
552                         (let ((en (environment-ref sys n)))
553                           (if (nemo:quantity? en)
554                               (cases nemo:quantity en
555                                      (REACTION  (name initial open transitions conserve power)
556                                                 (if (nemo:rhs? initial)
557                                                     (cons* (state-init name initial) 
558                                                            (state-init (nmodl-state-name name open) name) ax) 
559                                                     ax))
560                                      (RATE  (name initial rhs power)
561                                             (if (nemo:rhs? initial)
562                                                 (cons (state-init name initial) ax) 
563                                                 ax))
564                                      (else  ax))
565                               ax))))
566            ax lst))
567   (list) poset))
568
569(define (poset->state-conserve-eq-defs poset sys)
570  (fold-right
571   (lambda (lst ax)
572     (fold  (lambda (x ax) 
573              (match-let (((i . n)  x))
574                         (let ((en (environment-ref sys n)))
575                           (if (nemo:quantity? en)
576                               (cases nemo:quantity en
577                                      (REACTION (name initial open transitions conserve power)
578                                                (if (and (list? conserve) (every nemo:conseq? conserve))
579                                                    (cons (state-conseqs (nmodl-name name) transitions conserve
580                                                                        nmodl-state-name) ax) 
581                                                    ax))
582                                      (else  ax))
583                               ax))))
584            ax lst))
585   (list) poset))
586
587
588(define (find-locals defs)
589  (concatenate (map (lambda (def) 
590                      (match def 
591                             (('let bnds body) 
592                              (let ((bexprs (map second bnds)))
593                                (concatenate (list (map first bnds) 
594                                                   (find-locals bexprs )
595                                                   (find-locals (list body))))))
596                             (('if c t e)      (append (find-locals (list t)) (find-locals (list e))))
597                             ((s . rest)       (find-locals rest))
598                             (else (list)))) 
599                    defs)))
600
601
602(define (rate/reaction-power sys n)
603  (let ((en (environment-ref sys n)))
604    (if (nemo:quantity? en)
605        (cases nemo:quantity en
606               (REACTION  (name initial open transitions conserve power) 
607                          power)
608               (RATE    (name initial rhs power)
609                        power)
610               (else  #f)) 
611        #f)))
612
613
614(define (bucket-partition p lst)
615  (let loop ((lst lst) (ax (list)))
616    (if (null? lst) ax
617        (let ((x (car lst)))
618          (let bkt-loop ((old-bkts ax) (new-bkts (list)))
619            (if (null? old-bkts) (loop (cdr lst) (cons (list x) new-bkts))
620                (if (p x (caar old-bkts ))
621                    (loop (cdr lst) (append (cdr old-bkts) (cons (cons x (car old-bkts)) new-bkts)))
622                    (bkt-loop (cdr old-bkts) (cons (car old-bkts) new-bkts)))))))))
623
624
625
626(define (nemo:nmodl-translator sys . rest)
627  (define (cid x)  (second x))
628  (define (cn x)   (first x))
629  (let-optionals rest ((method 'cnexp) (table? #f) (min-v -100) (max-v 100) (step 0.5) 
630                       (depend #f)  (kinetic (list)) (linear? #f))
631  (match-let ((($ nemo:quantity 'DISPATCH  dis) (environment-ref sys (nemo-intern 'dispatch))))
632    (let ((imports  ((dis 'imports)  sys))
633          (exports  ((dis 'exports)  sys)))
634      (let* ((indent        0)
635             (indent+       (+ 2 indent ))
636             (table-with    (and table? (inexact->exact (round (/ (abs (- max-v min-v)) step)))))
637             (sysname       (nmodl-name ((dis 'sysname) sys)))
638             (consts        ((dis 'consts)  sys))
639             (asgns         ((dis 'asgns)   sys))
640             (states        ((dis 'states)  sys))
641             (kinetic       (or kinetic '()))
642             (kinetic       (delete-duplicates
643                             (cond ((eq? kinetic 'all) (filter-map first states))
644                                   ((symbol? kinetic) 
645                                    (let ((sk (->string kinetic)))
646                                      (filter-map (lambda (s) (and s (and (string-suffix? sk (->string s)) s)) )
647                                                  (map first states))))
648                                   (else
649                                    (let ((kinetic (map ->string kinetic))
650                                          (ss      (map (compose ->string first) states)))
651                                      (concatenate
652                                       (map (lambda (sk)
653                                              (filter-map (lambda (s) (and (string-suffix? sk s) s))
654                                                          ss))
655                                            kinetic)))))))
656             (reactions     ((dis 'reactions) sys))
657             (rates         ((dis 'rates) sys))
658             (defuns        ((dis 'defuns)  sys))
659             (components    ((dis 'components) sys))
660             (g             (match-let (((state-list asgn-list g) ((dis 'depgraph*) sys))) g))
661             (poset         (vector->list ((dis 'depgraph->bfs-dist-poset) g)))
662             
663             (gate-complex-info    (nemo:gate-complex-query sys))
664             (gate-complexes       (lookup-def 'gate-complexes gate-complex-info))
665             (perm-ions     (map (match-lambda ((comp i e erev) `(,comp ,(nmodl-name i) ,(nmodl-name e) ,erev)))
666                                 (lookup-def 'perm-ions gate-complex-info)))
667             (acc-ions      (map (match-lambda ((comp i in out) `(,comp ,@(map nmodl-name (list i in out)))))
668                                 (lookup-def 'acc-ions gate-complex-info)))
669             (epools        (lookup-def 'pool-ions gate-complex-info))
670             (pool-ions     (map (lambda (lst) (map nmodl-name lst)) epools))
671
672             (i-gates       (lookup-def 'i-gates gate-complex-info))
673
674             (has-kinetic?  (or (not (null? (filter (lambda (x) (member (car x) kinetic)) states)))))
675             (has-ode?      (or (not (null? (filter (lambda (x) (not (member (car x) kinetic))) states)))
676                                (not (null? pool-ions))))
677
678             (asgn-eq-defs       (poset->asgn-eq-defs poset sys))
679             (reaction-eq-defs   (poset->reaction-eq-defs poset sys kinetic)) 
680             (rate-eq-defs       (reverse (poset->rate-eq-defs poset sys kinetic method)))
681             (kstate-eq-defs     (poset->kinetic-eq-defs poset sys kinetic))
682             (conserve-eq-defs   (poset->state-conserve-eq-defs poset sys))
683             (state-init-defs    (poset->state-init-defs poset sys))
684
685             )
686
687           (pp indent ,nl (TITLE ,sysname))
688           
689           (pp indent ,nl (NEURON "{"))
690           (let recur ((exports exports))
691             (if (not (null? exports)) 
692                 (begin
693                   (pp indent+ (RANGE ,(slp ", " (map nmodl-name (take exports (min 10 (length exports)))))))
694                   (recur (drop exports (min 10 (length exports)))))))
695
696           (let ((currents (append (map (lambda (gate-complex) (nmodl-name (s+ 'i_ (first gate-complex)))) gate-complexes )
697                                   (map (lambda (i-gate) (nmodl-name (s+ 'i_ (second i-gate)))) i-gates ))))
698             (if (not (null? currents)) (pp indent+ (RANGE ,(slp ", " currents)))))
699
700           (for-each (lambda (x)
701                       (case (first x)
702                         ((non-specific) 
703                          (pp indent+ (RANGE ,(third x))
704                              (NONSPECIFIC_CURRENT ,(second x))))
705                         (else
706                          (cond ((fourth x)
707                                 (pp indent+ (RANGE ,(second x))
708                                     (USEION ,(first x) READ ,(third x) WRITE ,(second x))))
709                                (else (pp indent+ (RANGE ,(second x))))))))
710                     (delete-duplicates perm-ions (lambda (x y) (eq? (car x) (car y)))))
711
712           
713           (if (null? acc-ions)
714               (for-each (lambda (pool-ion)
715                           (pp indent+ (RANGE ,(slp ", " (list (second pool-ion) (third pool-ion))))
716                               (USEION ,(fourth pool-ion) 
717                                       READ  ,(slp ", " (list (second pool-ion)))
718                                       WRITE ,(slp ", " (list (third pool-ion ))))))
719                         pool-ions)
720               (for-each (lambda (acc-ion)
721                           (let ((pool-ion (assoc (first acc-ion) pool-ions)))
722                             (if pool-ion
723                                 (pp indent+ (RANGE ,(second acc-ion))
724                                     (USEION ,(first acc-ion) 
725                                             READ  ,(slp ", " (list (third acc-ion) (fourth acc-ion) (second pool-ion)))
726                                             WRITE ,(slp ", " (list (second acc-ion) (third pool-ion )))))
727                                 (pp indent+ (RANGE ,(second acc-ion))
728                                     (USEION ,(first acc-ion) 
729                                             READ ,(slp ", "  (list (third acc-ion) (fourth acc-ion) ))
730                                             WRITE ,(second acc-ion))))))
731                         (delete-duplicates acc-ions (lambda (x y) (eq? (car x) (car y))))))
732
733           (let* ((const-names   (map first consts))
734                  (is-const?     (lambda (x) (member x const-names)))
735                  (range-consts  (delete-duplicates 
736                                  (fold (lambda (def ax) 
737                                          (let* ((rhs   (second def))
738                                                 (vars  (rhsvars rhs)))
739                                            (append (filter is-const? vars) ax)))
740                                        (list) asgn-eq-defs ))))
741             (if (not (null? range-consts)) (pp indent+ (RANGE ,(slp ", " range-consts)))))
742           
743           
744           (pp indent "}")
745           
746           (let* ((define-fn (make-define-fn table? min-v max-v table-with depend)))
747             (for-each (lambda (fndef) 
748                         (if (not (member (car fndef) builtin-fns))
749                             (apply define-fn (cons indent fndef)))) 
750                       defuns))
751
752           (let* ((parameter-defs 
753                   (filter-map
754                    (lambda (nv)
755                      (and (not (member (first nv) nmodl-builtin-consts))
756                           (let ((v1 (canonicalize-expr/NMODL (second nv))))
757                             (list (first nv) v1))))
758                    consts))
759                  (parameter-locals  (find-locals (map second parameter-defs)))
760                  (state-defs 
761                   (append
762                    (map (lambda (st)
763                           (if (pair? st) (nmodl-state-name (first st) (second st)) 
764                               (nmodl-name st)))
765                         states)
766                    (map nmodl-name reactions)))
767                  (assigned-defs
768                   (filter-map
769                    (lambda (x) 
770                      (let ((x1 (nmodl-name x)))
771                        (and (not (or (member x1 state-defs) (assoc x1 parameter-defs)))
772                             x1)))
773                    (delete-duplicates
774                     (append asgns
775                             (map first imports) 
776                             (map second perm-ions) (map third perm-ions)
777                             (map second acc-ions)  (map fourth acc-ions)
778                             (map second pool-ions) (map third pool-ions)
779                             (map (lambda (gate-complex) (nmodl-name (s+ 'i_ (first gate-complex)))) gate-complexes )
780                             (map (lambda (i-gate) (nmodl-name (s+ 'i_ (second i-gate)))) i-gates )
781                             )))))
782             
783             (pp indent ,nl (PARAMETER "{"))
784             (if (not (null? parameter-locals)) (pp indent+ (LOCAL ,(slp ", " parameter-locals))))
785             (for-each (lambda (def)
786                         (let ((n (nmodl-name (first def))) (b (second def)))
787                           (pp indent+ ,(expr->string/NMODL b n)))) parameter-defs)
788             (case method  ((expeuler)  (pp indent+ dt)))
789             (pp indent "}")
790             (pp indent ,nl (STATE "{"))
791             (for-each (lambda (x) (pp indent+ ,x)) state-defs)
792             (pp indent "}")
793             (pp indent ,nl (ASSIGNED "{"))
794             (for-each (lambda (x) (pp indent+ ,x)) assigned-defs)
795             (pp indent "}"))
796
797           (if (not (null? asgns))
798               (begin
799                 (pp indent ,nl (PROCEDURE asgns () "{"))
800                 (let ((locals    (find-locals (map second asgn-eq-defs))) )
801                   (if (not (null? locals)) (pp indent+ (LOCAL ,(slp ", " locals)))))
802#|
803                 This seems to cause a segmentation fault in nrnoc:
804
805                 (if (and table? min-v max-v table-with)
806                     (pp indent+ (TABLE ,(slp ", " (map first asgn-eq-defs))
807                                  ,@(if depend `(DEPEND ,depend) `(""))
808                                  FROM ,min-v TO ,max-v WITH ,table-with)))
809|#
810
811                 (for-each (lambda (def)
812                             (let ((n (nmodl-name (first def)) )
813                                   (b (second def)))
814                               (pp indent+ ,(expr->string/NMODL b n)))) asgn-eq-defs)
815                 (pp indent "}")))
816             
817           (if (not (null? reactions))
818               (begin
819                 (pp indent ,nl (PROCEDURE reactions () "{"))
820                 (let ((locals    (find-locals (map second reaction-eq-defs))) )
821                   (if (not (null? locals)) (pp indent+ (LOCAL ,(slp ", " locals))))
822                   (for-each (lambda (def)
823                               (let ((n (nmodl-name (first def))) (b (second def)))
824                                 (pp indent+ ,(expr->string/NMODL b n)))) 
825                             reaction-eq-defs))
826                 (pp indent "}")))
827
828           (if (not (null? pool-ions))
829               (begin
830                 (pp indent ,nl (PROCEDURE pools () "{"))
831                 (for-each (lambda (pool-ion)
832                             (pp indent+ (,(third pool-ion) = ,(first pool-ion))))
833                           pool-ions)
834                 (pp indent "}")))
835
836           (pp indent ,nl (BREAKPOINT "{"))
837           (let* ((i-eqs (filter-map
838                          (lambda (gate-complex) 
839
840                            (let* ((label             (first gate-complex))
841                                   (n                 (second gate-complex))
842                                   (subcomps          ((dis 'component-subcomps) sys n))
843                                   (acc               (lookup-def 'accumulating-substance subcomps))
844                                   (perm              (lookup-def 'permeating-ion subcomps))
845                                   (permqs            (and perm ((dis 'component-exports) sys (cid perm))))
846                                   (pore              (lookup-def 'pore subcomps))
847                                   (permeability      (lookup-def 'permeability subcomps))
848                                   (gate              (lookup-def 'gate subcomps))
849                                   (sts               (and gate ((dis 'component-exports) sys (cid gate)))))
850
851
852                              (if (not (or pore permeability))
853                                  (nemo:error 'nemo:nmodl-translator ": ion channel definition " label
854                                              "lacks any pore or permeability components"))
855 
856                              (cond ((and perm permeability gate)
857                                     (let* ((i     (nmodl-name (s+ 'i (cn perm))))
858                                            (pmax  (car ((dis 'component-exports) sys (cid permeability))))
859                                            (pwrs  (map (lambda (n) (rate/reaction-power sys n)) sts))
860                                            (sptms (map (lambda (st pwr) (if pwr `(pow ,st ,pwr) st)) sts pwrs))
861                                            (gion  `(* ,pmax ,@sptms)))
862                                         (list i #f gion (nmodl-name (s+ 'i_ label) ))))
863
864                                    ((and perm pore gate)
865                                     (case (cn perm)
866                                       ((non-specific)
867                                        (let* ((i     (nmodl-name 'i))
868                                               (e     (car permqs))
869                                               (gmax  (car ((dis 'component-exports) sys (cid pore))))
870                                               (pwrs  (map (lambda (n) (rate/reaction-power sys n)) sts))
871                                               (sptms (map (lambda (st pwr) (if pwr `(pow ,st ,pwr) st)) sts pwrs))
872                                               (gion  `(* ,gmax ,@sptms)))
873                                          (list i e gion (nmodl-name (s+ 'i_ label) ))))
874
875                                       (else
876                                        (let* ((i     (nmodl-name (s+ 'i (cn perm))))
877                                               (e     (nmodl-name (s+ 'e (cn perm))))
878                                               (gmax  (car ((dis 'component-exports) sys (cid pore))))
879                                               (pwrs  (map (lambda (n) (rate/reaction-power sys n)) sts))
880                                               (sptms (map (lambda (st pwr) (if pwr `(pow ,st ,pwr) st)) sts pwrs))
881                                               (gion  `(* ,gmax ,@sptms)))
882                                          (list i e gion (nmodl-name (s+ 'i_ label)))))))
883
884                                    ((and perm pore)
885                                     (case (cn perm)
886                                       ((non-specific)
887                                        (let* ((i     (nmodl-name 'i))
888                                               (e     (car permqs))
889                                               (gmax  (car ((dis 'component-exports) sys (cid pore)))))
890                                          (list i e gmax (nmodl-name (s+ 'i_ label)))))
891                                       (else
892                                        (nemo:error 'nemo:nmodl-translator ": ion channel definition " label
893                                                    (s+ "(" n ")")
894                                                    "lacks gate component"))))
895                                   
896                                    ((and acc pore gate)
897                                     (let* ((i     (nmodl-name (s+ 'i (cn acc))))
898                                            (gmax  (car ((dis 'component-exports) sys (cid pore))))
899                                            (pwrs  (map (lambda (n) (rate/reaction-power sys n)) sts))
900                                            (sptms (map (lambda (st pwr) (if pwr `(pow ,st ,pwr) st)) sts pwrs))
901                                            (gion  `(* ,gmax ,@sptms)))
902                                       (list i #f gion (nmodl-name (s+ 'i_ label) ))))
903                                   
904                                    (else (nemo:error 'nemo:nmodl-translator ": invalid ion channel definition " 
905                                                      label))
906                                    )))
907                          gate-complexes))
908
909                  (i-eqs  (fold  (lambda (i-gate ax) 
910                                   (let ((i-gate-var (first i-gate)))
911                                     (cons (list (nmodl-name 'i) #f i-gate-var (s+ 'i_ (second i-gate)) ) ax)))
912                                 i-eqs i-gates))
913
914                  (i-bkts (bucket-partition (lambda (x y) (eq? (car x) (car y))) i-eqs))
915
916                  (i-eqs  (fold (lambda (b ax) 
917                                  (match b 
918                                         ((and ps ((i e gion ii) . rst))
919                                          (let loop ((ps ps) (summands (list)) (eqs (list)))
920                                            (if (null? ps)
921
922                                                (let* ((sum0  (sum summands))
923                                                       (sum1  (rhsexpr/NMODL sum0))
924                                                       (sum2  (canonicalize-expr/NMODL sum1)))
925                                                  (append eqs (list (list i sum2)) ax))
926
927                                                (match-let (((i e gion ii) (car ps)))
928                                                  (loop (cdr ps) 
929                                                        (cons ii summands) 
930                                                        (let* ((expr0 (rhsexpr/NMODL (if e `(* ,gion (- v ,e)) gion)))
931                                                               (expr1 (canonicalize-expr/NMODL expr0)))
932                                                          (cons (list ii expr1) eqs)))))))
933                                           
934                                         ((i e gion ii)
935                                          (let* ((expr0  (rhsexpr/NMODL (if e `(* ,gion (- v ,e)) gion)))
936                                                 (expr1  (canonicalize-expr/NMODL expr0)))
937                                            (cons (list i expr1) ax)))
938                                         
939                                         (else ax)))
940                                (list) i-bkts))
941                 
942                  (locals (find-locals (map second i-eqs))))
943
944             (if (not (null? locals))    (pp indent+ (LOCAL ,(slp ", " locals))))
945             (if has-ode?
946                 (case method
947                   ((#f expeuler)  (pp indent+ (SOLVE states)))
948                   (else           (pp indent+ (SOLVE states METHOD ,method)))))
949             (if has-kinetic?   (pp indent+  (SOLVE kstates METHOD sparse)))
950             (if (not (null? reactions))   (pp indent+ (reactions ())))
951             (if (not (null? pool-ions)) (pp indent+ (pools ())))
952             (for-each (lambda (p) (pp indent+ ,(expr->string/NMODL (second p) (first p)))) i-eqs)
953             (pp indent "}"))
954           
955           (if has-ode?
956               (let ((locals   (find-locals (map second rate-eq-defs))))
957                 (case method
958                   ((expeuler) (pp indent ,nl (PROCEDURE states () "{")))
959                   (else       (pp indent ,nl (DERIVATIVE states "{"))))
960                 (if (not (null? locals)) (pp indent+ (LOCAL ,(slp ", " locals))))
961                 (if (not (null? asgns))     (pp indent+ (asgns ())))
962                 (let ((prime (case method 
963                                ((expeuler) identity)
964                                (else  (lambda (x) (s+ x "'"))))))
965                   (for-each (lambda (def)
966                               (let ((n (prime (first def)))
967                                     (b (second def)))
968                                 (pp indent+ ,(expr->string/NMODL b n))))
969                             rate-eq-defs))
970                 (pp indent "}")))
971
972           (if has-kinetic?
973               (begin
974                 (pp indent ,nl (KINETIC kstates "{"))
975                 (let* ((exprs             (map second kstate-eq-defs))
976                        (locals            (concatenate 
977                                            (find-locals
978                                             (append (map (lambda (x) (map fourth x)) exprs)
979                                                     (map (lambda (x) (map fifth x)) exprs))))))
980                   (if (not (null? locals)) (pp indent+ (LOCAL ,(slp ", " locals))))
981                   (if (not (null? asgns))     (pp indent+ (asgns ())))
982                   (for-each
983                    (lambda (def)
984                      (let* ((n             (first def))
985                             (eqs           (second def))
986                             (conserve-eqs  (lookup-def (nmodl-name n) conserve-eq-defs)))
987                        (for-each
988                         (lambda (eq)
989                           (match eq
990                                  (('-> s0 s1 rexpr) 
991                                   (pp indent+ (~ ,s0 -> ,s1 (,(expr->string/NMODL rexpr)))))
992                                  (('<-> s0 s1 rexpr1 rexpr2) 
993                                   (pp indent+ (~ ,s0 <-> ,s1 (,(expr->string/NMODL rexpr1) #\,
994                                                               ,(expr->string/NMODL rexpr2) 
995                                                               ))))
996                                  ))
997                           eqs)
998                        (if conserve-eqs
999                            (for-each (lambda (eq) 
1000                                        (let ((val  (first eq))
1001                                              (expr (third eq)))
1002                                          (pp indent+ ,(conserve-conseq->string/NMODL expr val))))
1003                                    conserve-eqs))
1004                        ))
1005                    kstate-eq-defs))
1006                 (pp indent "}")))
1007           
1008           
1009           (let ((locals (concatenate (find-locals (map second state-init-defs)))) )
1010               (pp indent ,nl (INITIAL "{"))
1011               (if (not (null? locals)) (pp indent+ (LOCAL ,(slp ", " locals))))
1012               (if (not (null? asgns))  (pp indent+ (asgns ())))
1013               (for-each (lambda (def)
1014                           (let ((n (first def)) (b (second def)))
1015                             (pp indent+ ,(expr->string/NMODL b n)))) state-init-defs)
1016
1017               (if has-kinetic?
1018                   (pp indent+ (SOLVE kstates STEADYSTATE sparse)))
1019               
1020               (pp indent "}")
1021
1022               (pp indent ,nl (PROCEDURE print_state () "{"))
1023
1024               (let ((lst (sort (map (compose ->string first) rate-eq-defs) string<?)))
1025                 (for-each (lambda (x)
1026                             (pp indent+ (printf (,(s+ #\" x " = %g\\n"  #\") ", " ,x ))))
1027                           lst))
1028
1029               (pp indent "}")
1030
1031               ))))))
1032)
Note: See TracBrowser for help on using the repository browser.