source: project/release/3/oru/nmodl.scm @ 11694

Last change on this file since 11694 was 11694, checked in by Ivan Raikov, 13 years ago

More updates to the NMODL backend.

File size: 22.6 KB
Line 
1
2;; TODO: * uniquify state names in state complexes
3;;       * check that open states are valid
4;;
5;;
6;; An extension for translating NeuroML models to NMODL descriptions.
7;;
8;; Copyright 2008 Ivan Raikov and the Okinawa Institute of Science and Technology
9;;
10;; This program is free software: you can redistribute it and/or
11;; modify it under the terms of the GNU General Public License as
12;; published by the Free Software Foundation, either version 3 of the
13;; License, or (at your option) any later version.
14;;
15;; This program is distributed in the hope that it will be useful, but
16;; WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18;; General Public License for more details.
19;;
20;; A full copy of the GPL license can be found at
21;; <http://www.gnu.org/licenses/>.
22;;
23
24(require-extension syntax-case)
25(require-extension matchable)
26(require-extension strictly-pretty)
27(require-extension environments)
28(require-extension oru-core)
29(require-extension srfi-1)
30(require-extension srfi-4)
31(require-extension srfi-13)
32(require-extension srfi-14)
33(require-extension runcmd)
34(require-extension utils)
35(require-extension lolevel)
36(require-extension varsubst)
37(require-extension digraph)
38(require-extension datatype)
39
40(define (lookup-def k lst . rest)
41  (let-optionals rest ((default #f))
42      (let ((kv (assoc k lst)))
43        (if (not kv) default
44            (match kv ((k v) v) (else (cdr kv)))))))
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
57(define (enumprocs expr ax)
58  (match expr 
59         (('if . es)  (fold enumprocs ax es))
60         (('let bnds body)  (fold enumprocs (fold enumprocs ax (map cadr bnds)) body))
61         ((s . es)    (if (symbol? s)  (cons s (fold enumprocs ax es)) ax))
62         (else ax)))
63
64(define (enumvars expr ax)
65  (match expr 
66         (('if . es)  (fold enumvars ax es))
67         (('let bnds body)  (fold enumprocs (fold enumvars ax (map cadr bnds)) body))
68         ((s . es)    (if (symbol? s)  (fold enumvars ax es) ax))
69         (id          (if (symbol? id) (cons id ax) ax))))
70
71(define (enumbnds expr ax)
72  (match expr 
73         (('if . es)        (fold enumbnds ax es))
74         (('let bnds body)  (enumbnds body (append  (map car bnds) ax)))
75         ((s . es)          (if (symbol? s)  (fold enumbnds ax es) ax))
76         (else ax)))
77
78(define (rhsvars rhs)
79  (enumvars rhs (list)))
80
81(define (rhsexpr expr)
82  (match expr 
83         (('if . es)  `(if . ,(map (lambda (x) (rhsexpr x)) es)))
84         (('pow x y)  (if (and (integer? y)  (positive? y))
85                          (if (> y 1)  (let ((tmp (gensym "x")))
86                                         `(let ((,tmp ,x)) (* . ,(list-tabulate (inexact->exact y) (lambda (i) tmp)))))
87                              x)
88                            expr))
89         ((s . es)    (if (symbol? s)  (cons s (map (lambda (x) (rhsexpr x)) es)) expr))
90         (id          id)))
91
92
93;;; Procedures for string concatenation and pretty-printing
94
95(define (s+ . lst)    (string-concatenate (map ->string lst)))
96(define (sw+ lst)     (string-intersperse (filter-map (lambda (x) (and x (->string x))) lst) " "))
97(define (s\ p . lst)  (string-intersperse (map ->string lst) p))
98(define (sl\ p lst)   (string-intersperse (map ->string lst) p))
99(define nl "\n")
100
101(define (spaces n)  (list->string (list-tabulate n (lambda (x) #\space))))
102
103(define (ppf indent . lst)
104  (let ((sp (spaces indent)))
105    (for-each (lambda (x)
106                (and x (match x 
107                              ((i . x1) (if (and (number? i) (positive? i))
108                                            (for-each (lambda (x) (ppf (+ indent i) x)) x1)
109                                            (print sp (sw+ x))))
110                              (else   (print sp (if (list? x) (sw+ x) x))))))
111              lst)))
112
113
114(define-syntax pp
115  (syntax-rules ()
116    ((pp indent val ...) (ppf indent (quasiquote val) ...))))
117
118(define ifthen/NMODL  (doc:ifthen 2 (doc:text "if") (doc:text "") (doc:text "else")))
119(define letblk/NMODL  (doc:letblk 2 (doc:empty) (doc:break) (doc:empty)))
120(define group/NMODL   (doc:block 2 (doc:text "(") (doc:text ")")))
121(define block/NMODL   (doc:block 2 (doc:text "{") (doc:text "}")))
122(define binop/NMODL   (doc:binop 2))
123
124(define (format-op/NMODL indent op args)
125  (let ((op1 (doc:text (->string op))))
126    (if (null? args) op1
127        (match args
128               ((x)           (doc:connect op1 x))
129               ((x y)         (binop/NMODL x op1 y))
130               ((x y z)       (binop/NMODL x op1 (binop/NMODL y op1 z)))
131               (lst           (let* ((n   (length lst))
132                                     (n/2 (inexact->exact (round (/ n 2)))))
133                                (binop/NMODL (format-op/NMODL indent op (take lst n/2 )) op1 
134                                         (format-op/NMODL indent op (drop lst n/2 )))))))))
135
136(define (format-fncall/NMODL indent op args)
137  (let ((op1 (doc:text (->string op))))
138    (doc:cons op1 (group/NMODL ((doc:list indent identity (lambda () (doc:text ", "))) args)))))
139
140
141(define nmodl-ops
142  `(+ - * / > < <= >= = ^))
143
144(define builtin-fns
145  `(+ - * / pow neg abs atan asin acos sin cos exp ln
146      sqrt tan cosh sinh tanh hypot gamma lgamma log10 log2 log1p ldexp cube
147      > < <= >= = and or round ceiling floor max min
148      fpvector-ref))
149
150(define (sum lst)
151  (if (null? lst) lst
152      (match lst
153             ((x)   x)
154             ((x y) `(+ ,x ,y))
155             ((x y . rest) `(+ (+ ,x ,y) ,(sum rest)))
156             ((x . rest) `(+ ,x ,(sum rest))))))
157
158
159(define (subst-term t subst k)
160  (match t
161         (('if c t e)
162          `(if ,(k c subst) ,(k t subst) ,(k e subst)))
163         (('let bs e)
164          (k `(let ,(map (lambda (b) `(,(car b) ,(k (cadr b) subst))) bs) ,(k e subst)) subst))
165         ((f . es)
166          (cons (k f subst) (map (lambda (e) (k e subst)) es)))
167         ((? symbol? )  (lookup-def t subst t))
168         ((? atom? ) t)))
169
170(define (binding? t) (and (list? t) (eq? 'let (car t)) (cdr t)))
171
172(define (bind ks vs e) `(let ,(zip ks vs) ,e))
173
174
175(define (if-convert expr)
176  (match expr 
177         (('if c t e) 
178          (let ((r (gensym "if")))
179            `(let ((,r (if ,(if-convert c) ,(if-convert t) ,(if-convert e)))) 
180               ,r)))
181         (('let bs e)
182          `(let ,(map (lambda (b) `(,(car b) ,(if-convert (cadr b)))) bs) ,(if-convert e)))
183         ((f . es)
184          (cons f (map if-convert es)))
185         ((? atom? ) expr)))
186
187         
188(define (let-enum expr ax)
189  (match expr
190         (('let ((x ('if c t e))) y)
191          (let ((ax (fold let-enum ax (list c t e))))
192            (if (eq? x y)  (append ax (list (list x `(if ,c ,t ,e)))) ax)))
193
194         (('let bnds body)  (let-enum body (append ax bnds)))
195
196         (('if c t e)  (fold let-enum ax (list c t e)))
197
198         ((f . es)  (fold let-enum ax es))
199
200         (else ax)))
201
202
203(define (let-elim expr)
204  (match expr
205         (('let ((x ('if c t e))) y)
206          (if (eq? x y)  y expr))
207
208         (('let bnds body) (let-elim body))
209
210         (('if c t e)  `(if . ,(map let-elim (list c t e))))
211
212         ((f . es)  `(,f . ,(map let-elim es)))
213
214         (else expr)))
215 
216
217(define (let-lift expr)
218  (let ((bnds (let-enum expr (list))))
219    (if (null? bnds) expr
220        `(let ,(map (lambda (b) (list (car b) (let-elim (cadr b)))) bnds) ,(let-elim expr)))))
221
222(define (canonicalize-expr/NMODL expr)
223  (let ((subst-convert  (subst-driver (lambda (x) (and (symbol? x) x)) binding? identity bind subst-term)))
224    (let* ((expr1 (if-convert expr))
225           (expr2 (subst-convert expr1 subst-empty))
226           (expr3 (let-lift expr2)))
227      expr3)))
228
229(define (format-expr/NMODL indent expr . rest) 
230  (let-optionals rest ((rv #f))
231   (let ((indent+ (+ 2 indent)))
232    (match expr
233       (('let bindings body)
234        (letblk/NMODL
235         (fold-right 
236           (lambda (x ax)
237             (letblk/NMODL
238              (match (second x)
239                     (('if c t e)
240                      (ifthen/NMODL
241                       (group/NMODL (format-expr/NMODL indent c))
242                       (block/NMODL 
243                        (binop/NMODL (doc:text (->string (first x))) (doc:text " = ")
244                                     (format-expr/NMODL indent+ t)))
245                       (block/NMODL
246                        (binop/NMODL (doc:text (->string (first x))) (doc:text " = ")
247                                     (format-expr/NMODL indent+ e) ))))
248                     
249                     (else
250                      (format-op/NMODL indent+ " = "
251                                       (list (format-expr/NMODL indent+ (first x) )
252                                             (format-expr/NMODL indent+ (second x))))))
253              ax))
254           (doc:empty) bindings)
255         (let ((body1 (doc:nest indent (format-expr/NMODL indent body))))
256           (if rv  (format-op/NMODL indent " = " (list (format-expr/NMODL indent+ rv ) body1))
257               body1))))
258       
259       (('if . rest) (error 'format-expr/NMODL "invalid if statement " expr))
260
261       ((op . rest) 
262       (let ((op (case op ((pow)  '^) ((abs) 'fabs) (else op))))
263         (let ((fe
264                (if (member op nmodl-ops)
265                    (let ((mdiv?  (any (lambda (x) (match x (('* . _) #t) (('/ . _) #t) (else #f))) rest))
266                          (mul?   (any (lambda (x) (match x (('* . _) #t) (else #f))) rest))
267                          (plmin? (any (lambda (x) (match x (('+ . _) #t) (('- . _) #t) (else #f))) rest)))
268                      (case op
269                        ((/) 
270                         (format-op/NMODL indent op 
271                                          (map (lambda (x) 
272                                                 (let ((fx (format-expr/NMODL indent+ x)))
273                                                   (if (or (symbol? x) (number? x)) fx
274                                                       (if (or mul? plmin?) (group/NMODL fx) fx)))) rest)))
275                        ((*) 
276                         (format-op/NMODL indent op 
277                                          (map (lambda (x) 
278                                                 (let ((fx (format-expr/NMODL indent+ x)))
279                                                   (if (or (symbol? x) (number? x)) fx
280                                                       (if plmin? (group/NMODL fx) fx)))) rest)))
281                       
282                        ((^) 
283                         (format-op/NMODL indent op 
284                                          (map (lambda (x) 
285                                                 (let ((fx (format-expr/NMODL indent+ x)))
286                                                   (if (or (symbol? x)  (number? x)) fx
287                                                       (if (or mdiv? plmin?) (group/NMODL fx) fx)))) rest)))
288                       
289                        (else
290                         (format-op/NMODL indent op 
291                                          (map (lambda (x) 
292                                                 (let ((fx (format-expr/NMODL indent+ x))) fx)) rest)))))
293                   
294                    (let ((op (case op ((neg) '-) (else op))))
295                      (format-fncall/NMODL indent op (map (lambda (x) (format-expr/NMODL indent+ x)) rest))))))
296           (if rv 
297               (format-op/NMODL indent " = " (list (format-expr/NMODL indent+ rv ) fe))
298               fe))))
299     
300      (else  (let ((fe (doc:text (->string expr))))
301               (if rv 
302                   (format-op/NMODL indent " = " (list (format-expr/NMODL indent+ rv ) fe))
303                   fe)))))))
304               
305
306         
307(define (expr->string/NMODL x . rest)
308  (let-optionals rest ((rv #f) (width 64))
309    (sdoc->string (doc:format width (format-expr/NMODL 2 x rv)))))
310 
311
312(define (define-fn 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 ,n (,(sl\ ", " vars)) "{" ))
320      (let* ((body1 (canonicalize-expr/NMODL body))
321             (lbs (enumbnds body1 (list))))
322        (if (not (null? lbs)) (pp indent (LOCAL ,(sl\ ", " lbs))))
323        (pp indent+ ,(expr->string/NMODL body1 n)))
324      (pp indent "}")))  )
325
326
327(define (define-state indent n)
328  (pp indent (,n)))
329
330
331(define (state-eqs n initial open transitions power)
332  (let* ((g (make-digraph n (string-append (->string n) " transitions graph")))
333         (add-node!  (g 'add-node!))
334         (add-edge!  (g 'add-edge!))
335         (out-edges  (g 'out-edges))
336         (in-edges   (g 'in-edges))
337         (node-info  (g 'node-info))
338         (node-list  (let loop ((lst (list)) (tlst transitions))
339                       (if (null? tlst)  (delete-duplicates lst eq?)
340                           (match (car tlst) 
341                                  (('-> s0 s1 rate-expr)
342                                   (loop (cons s0 (cons s1 lst)) (cdr tlst)))
343                                  (('-> _)
344                                   (oru:error 'oru:nmodl-state-eqs ": invalid transition equation " 
345                                                  (car tlst) " in state complex " n))
346                                  (else (loop lst (cdr tlst)))))))
347         (node-ids      (list-tabulate (length node-list) identity))
348         (name->id-map  (zip node-list node-ids)))
349    ;; insert state nodes in the dependency graph
350    (for-each (lambda (i n) (add-node! i n)) node-ids node-list)
351    (let* ((nodes  ((g 'nodes)))
352           (snode   (find (lambda (s) (not (eq? (second s) open))) nodes))
353           (snex   `(- 1 ,(sum (filter-map (lambda (s) (and (not (= (first s) (first snode))) (second s))) nodes)))))
354      ;; create rate edges in the graph
355      (for-each (lambda (e) 
356                  (match e (('-> s0 s1 rate-expr)
357                            (let ((i  (car (alist-ref s0 name->id-map)))
358                                  (j  (car (alist-ref s1 name->id-map)))
359                                  (x  (if (eq? s0 (second snode)) snex s0)))
360                            (add-edge! (list i j `(* ,x ,rate-expr)))))
361                         (else (void))))
362                transitions)
363      ;; generate differential equations for each state in the transitions system
364      (let ((eqs    (fold (lambda (s ax) 
365                            (if (= (first snode) (first s) ) ax
366                                (let* ((out   (out-edges (first s)))
367                                       (in    (in-edges (first s)))
368                                       (open? (eq? (second s) open))
369                                       (name  (second s)))
370                                  (let* ((rhs1  (cond ((and (not (null? out)) (not (null? in)))
371                                                       `(+ (neg ,(sum (map third out)))
372                                                           ,(sum (map third in))))
373                                                      ((and (not (null? out)) (null? in))
374                                                       `(neg ,(sum (map third out))))
375                                                      ((and (null? out) (not (null? in)))
376                                                       (sum (map third in)))))
377                                         (fbody  (rhsexpr rhs1))
378                                         (fbody1 (canonicalize-expr/NMODL fbody)))
379                                    (cons (list (s+ name "'") fbody1) ax)))))
380                          (list) nodes)))
381        eqs))))
382           
383       
384
385
386(define (state-init n init)
387  (let* ((init  (rhsexpr init))
388         (init1 (canonicalize-expr/NMODL init)))
389    (list  n init1)))
390
391(define (asgn-eq n rhs)
392  (let* ((fbody   (rhsexpr rhs))
393         (fbody1  (canonicalize-expr/NMODL fbody)))
394    (list n fbody1)))
395
396
397(define (stcomp-eq n open transitions)
398  (list n open))
399
400
401(define (poset->asgn-eq-defs poset sys)
402  (fold-right
403   (lambda (lst ax)
404     (fold  (lambda (x ax) 
405              (match-let (((i . n)  x))
406                         (let ((en (environment-ref sys n)))
407                           (if (oru:quantity? en)
408                               (cases oru:quantity en
409                                      (ASGN  (name value rhs) (cons (asgn-eq name rhs) ax))
410                                      (else  ax))
411                               ax))))
412            ax lst))
413   (list) poset))
414
415
416(define (poset->state-eq-defs poset sys)
417  (fold-right
418   (lambda (lst ax)
419     (fold  (lambda (x ax) 
420              (match-let (((i . n)  x))
421                         (let ((en (environment-ref sys n)))
422                           (if (oru:quantity? en)
423                               (cases oru:quantity en
424                                      (TSCOMP  (name initial open transitions power) 
425                                               (append (state-eqs name initial open transitions power) ax))
426                                      (else  ax))
427                               ax))))
428            ax lst))
429   (list) poset))
430
431
432(define (poset->stcomp-eq-defs poset sys)
433  (fold-right
434   (lambda (lst ax)
435     (fold  (lambda (x ax) 
436              (match-let (((i . n)  x))
437                         (let ((en (environment-ref sys n)))
438                           (if (oru:quantity? en)
439                               (cases oru:quantity en
440                                      (TSCOMP  (name initial open transitions power) 
441                                               (cons (stcomp-eq name open transitions) ax))
442                                      (else  ax))
443                               ax))))
444            ax lst))
445   (list) poset))
446
447(define (poset->state-init-defs poset sys)
448  (fold-right
449   (lambda (lst ax)
450     (fold  (lambda (x ax) 
451              (match-let (((i . n)  x))
452                         (let ((en (environment-ref sys n)))
453                           (if (oru:quantity? en)
454                               (cases oru:quantity en
455                                      (TSCOMP  (name initial open transitions power) 
456                                               (cons* (state-init name initial) (state-init open name) ax))
457                                      (else  ax))
458                               ax))))
459            ax lst))
460   (list) poset))
461
462(define (find-locals defs)
463  (concatenate 
464   (map (lambda (def) (match (second def) (('let bnds _) (map first bnds)) (else (list))))
465        defs)))
466
467
468(define (state-power sys n)
469  (let ((en (environment-ref sys n)))
470    (if (oru:quantity? en)
471        (cases oru:quantity en
472               (TSCOMP  (name initial open transitions power)  power)
473               (else  #f))  #f)))
474
475(define (bucket-partition p lst)
476  (let loop ((lst lst) (ax (list)))
477    (if (null? lst) ax
478        (let ((x (car lst)))
479          (let bkt-loop ((old-bkts ax) (new-bkts (list)))
480            (if (null? old-bkts) (loop (cdr lst) (cons (list x) new-bkts))
481                (if (p x (caar old-bkts ))
482                    (loop (cdr lst) (append (cdr old-bkts) (cons (cons x (car old-bkts)) new-bkts)))
483                    (bkt-loop (cdr old-bkts) (cons (car old-bkts) new-bkts)))))))))
484
485
486(define (oru:nmodl-translator sys)
487  (match-let ((($ oru:quantity 'DISPATCH  dis) (environment-ref sys (oru-intern 'dispatch))))
488    (let ((imports  ((dis 'imports)  sys))
489          (exports  ((dis 'exports)  sys)))
490      (let* ((indent  0)
491             (indent+ (+ 2 indent ))
492             (sysname (nmodl-name ((dis 'sysname) sys)))
493             (sfname  (string-append (->string sysname) ".mod"))
494             (deps*   ((dis 'depgraph*) sys))
495             (asgns   ((dis 'asgns) sys))
496             (states  ((dis 'states) sys))
497             (stcomps ((dis 'stcomps) sys))
498             (components ((dis 'components) sys))
499             (ionchs  (filter-map (match-lambda (('ion-channel name) name) (else #f)) components))) 
500
501        (match-let (((state-list asgn-list g) deps*))
502         (let ((poset     (vector->list ((dis 'depgraph->bfs-dist-poset) g)))
503               (perm-ions (delete-duplicates
504                           (fold (lambda (n ax) 
505                                  (let* ((subcomps ((dis 'component-subcomps) sys n))
506                                         (perm (lookup-def 'permeating-substance subcomps))
507                                         (erev (and perm (car ((dis 'component-exports) sys perm))))
508                                         (i    (and perm (nmodl-name (s+ 'i perm))))
509                                         (e    (and perm (nmodl-name (s+ 'e perm)))))
510                                    (if perm  (cons `(,perm ,i ,e ,erev) ax) ax)))
511                                (list) ionchs)
512                           (lambda (x y) (eq? (car x) (car y)))))
513               (acc-ions (delete-duplicates
514                           (fold (lambda (n ax) 
515                                  (let* ((subcomps ((dis 'component-subcomps) sys n))
516                                         (acc   (lookup-def 'accumulating-substance subcomps))
517                                         (i     (and acc (nmodl-name (s+ 'i acc))))
518                                         (in    (and acc (nmodl-name (s+ acc 'i))))
519                                         (out   (and acc (nmodl-name (s+ acc 'o)))))
520                                    (if acc  (cons `(,acc ,i ,in ,out) ax) ax)))
521                                (list) ionchs)
522                           (lambda (x y) (eq? (car x) (car y)))))
523               )
524               
525           (with-output-to-file sfname
526             (lambda ()
527               (pp indent ,nl (TITLE ,sysname))
528
529               (pp indent ,nl (NEURON "{"))
530               (if (not (null? exports)) (pp indent+ (RANGE ,(sl\ ", " exports))))
531               (for-each (lambda (x)
532                           (pp indent+ (RANGE ,(second x))
533                               (USEION ,(first x) READ ,(third x) WRITE ,(second x))))
534                         perm-ions)
535               (for-each (lambda (x)
536                           (pp indent+ (RANGE ,(second x))
537                               (USEION ,(first x) READ ,(third x) ", " ,(fourth x) WRITE ,(second x))))
538                         acc-ions)
539               
540               (pp indent "}")
541
542
543               (pp indent ,nl (PARAMETER "{"))
544               (let* ((const-defs (map (lambda (nv)
545                                         (let ((v1 (canonicalize-expr/NMODL (second nv))))
546                                           (list (first nv) v1)))
547                                       ((dis 'consts) sys)))
548                      (locals  (find-locals const-defs)))
549                 (if (not (null? locals)) (pp indent+ (LOCAL ,(sl\ ", " locals))))
550                 (for-each (lambda (def)
551                             (let ((n (first def)) (b (second def)))
552                               (pp indent+ ,(expr->string/NMODL b n)))) const-defs))
553               (pp indent "}")
554
555               (for-each (lambda (fndef) 
556                           (if (not (member (car fndef) builtin-fns))
557                               (apply define-fn (cons indent fndef)))) 
558                         ((dis 'defuns) sys))
559
560               (pp indent ,nl (STATE "{"))
561               (for-each (lambda (st) (apply define-state (list indent+ st)))
562                         states)
563               (for-each (lambda (st) (apply define-state (list indent+ st)))
564                         stcomps)
565               (pp indent "}")
566
567               (pp indent ,nl (ASSIGNED "{"))
568               (let* ((asgns0 (append asgns (map first imports) 
569                                      (map second perm-ions) (map third perm-ions)
570                                      (map second acc-ions) (map fourth acc-ions)))
571                      (asgns1 (delete-duplicates asgns0)))
572                 (for-each (lambda (x) (pp indent+ ,x)) asgns1))
573               (pp indent "}")
574
575               (if (not (null? asgns))
576                   (begin
577                     (pp indent ,nl (PROCEDURE rates () "{"))
578                     (let* ((eq-defs   (poset->asgn-eq-defs poset sys)) 
579                            (locals    (find-locals eq-defs))) 
580                       (if (not (null? locals)) (pp indent+ (LOCAL ,(sl\ ", " locals))))
581                       (for-each (lambda (def)
582                             (let ((n (first def)) (b (second def)))
583                               (pp indent+ ,(expr->string/NMODL b n)))) eq-defs))
584
585                     (pp indent "}")))
586
587               (if (not (null? stcomps))
588                   (begin
589                     (pp indent ,nl (PROCEDURE stcomps () "{"))
590                     (let* ((eq-defs   (poset->stcomp-eq-defs poset sys)) 
591                            (locals    (find-locals eq-defs))) 
592                       (if (not (null? locals)) (pp indent+ (LOCAL ,(sl\ ", " locals))))
593                       (for-each (lambda (def)
594                             (let ((n (first def)) (b (second def)))
595                               (pp indent+ ,(expr->string/NMODL b n)))) eq-defs))
596
597                     (pp indent "}")))
598               
599               (pp indent ,nl (BREAKPOINT "{"))
600               (let* ((i-eqs (filter-map
601                              (lambda (n) 
602                                (let* ((subcomps ((dis 'component-subcomps) sys n))
603                                       (acc   (lookup-def 'accumulating-substance subcomps))
604                                       (perm  (lookup-def 'permeating-substance subcomps))
605                                       (pore  (lookup-def 'pore subcomps))
606                                       (gate  (lookup-def 'gate subcomps))
607                                       (sts   (and gate ((dis 'component-exports) sys gate))))
608                                  (cond ((and perm pore gate)
609                                         (let* ((i     (nmodl-name (s+ 'i perm)))
610                                                (e     (nmodl-name (s+ 'e perm)))
611                                                (gmax  (car ((dis 'component-exports) sys pore)))
612                                                (pwrs  (map (lambda (n) (state-power sys n)) sts))
613                                                (gion  `(* ,gmax . ,(map (lambda (st pwr) `(pow ,st ,pwr)) sts pwrs))))
614                                           (list i e gion)))
615                                         ((and acc pore gate)
616                                          (let* ((i     (nmodl-name (s+ 'i acc)))
617                                                 (gmax  (car ((dis 'component-exports) sys pore)))
618                                                 (pwrs  (map (lambda (n) (state-power sys n)) sts))
619                                                 (gion  `(* ,gmax . ,(map (lambda (st pwr) `(pow ,st ,pwr)) sts pwrs))))
620                                           (list i #f gion)))
621                                         (else (oru:error 'oru:nmodl-translator ": invalid ion channel definition " n))
622                                        )))
623                                 ionchs))
624                      (i-bkts (bucket-partition (lambda (x y) (eq? (car x) (car y))) i-eqs))
625                      (i-eqs  (fold (lambda (b ax) 
626                                      (match b 
627                                             ((and ps ((i e gion) . rst)) 
628                                              (let* ((sum   (if e `(* ,(sum (map third ps)) (- v ,e))
629                                                                (sum (map third ps))))
630                                                     (sum0  (rhsexpr sum))
631                                                     (sum1  (canonicalize-expr/NMODL sum0)))
632                                                (cons (list i sum1) ax)))
633
634                                             ((i e gion)
635                                              (let* ((expr0  (rhsexpr (if e `(* ,gion (- v ,e)) gion)))
636                                                     (expr1  (canonicalize-expr/NMODL expr0)))
637                                                (cons (list i expr1) ax)))
638                                                     
639
640                                             (else ax)))
641                                    (list) i-bkts))
642                      (locals (find-locals i-eqs)))
643                 (if (not (null? locals))   (pp indent+ (LOCAL ,(sl\ ", " locals))))
644                 (if (not (null? asgns))    (pp indent+ (rates ())))
645                 (pp indent+ (SOLVE states))
646                 (if (not (null? stcomps))  (pp indent+ (stcomps ())))
647                 (for-each (lambda (p) (pp indent+ ,(expr->string/NMODL (second p) (first p)))) i-eqs)
648                 (pp indent "}"))
649
650               (if (not (null? states))
651                   (begin
652                     (pp indent ,nl (DERIVATIVE states "{"))
653                     (let* ((eq-defs (reverse (poset->state-eq-defs poset sys)))
654                            (locals (find-locals eq-defs))) 
655                       (if (not (null? locals)) (pp indent+ (LOCAL ,(sl\ ", " locals))))
656                       (for-each (lambda (def)
657                             (let ((n (first def)) (b (second def)))
658                               (pp indent+ ,(expr->string/NMODL b n)))) eq-defs))
659                     (pp indent "}")))
660
661               (pp indent ,nl (INITIAL "{"))
662               (let* ((init-defs  (poset->state-init-defs poset sys))
663                      (locals     (concatenate (find-locals init-defs)))) 
664                 (if (not (null? locals)) (pp indent+ (LOCAL ,(sl\ ", " locals))))
665                 (for-each (lambda (def)
666                             (let ((n (first def)) (b (second def)))
667                               (pp indent+ ,(expr->string/NMODL b n)))) init-defs)
668                 (for-each (lambda (x)  (pp indent+ (,(third x) = ,(fourth x))))
669                           perm-ions))
670               (pp indent "}")
671
672               )))
673         )))))
Note: See TracBrowser for help on using the repository browser.