1 | ;; |
---|
2 | ;; |
---|
3 | ;; An extension for specifying Hodgkin-Huxley type dynamics in NEMO |
---|
4 | ;; systems. |
---|
5 | ;; |
---|
6 | ;; Copyright 2008-2011 Ivan Raikov and the Okinawa Institute of Science and Technology |
---|
7 | ;; |
---|
8 | ;; This program is free software: you can redistribute it and/or |
---|
9 | ;; modify it under the terms of the GNU General Public License as |
---|
10 | ;; published by the Free Software Foundation, either version 3 of the |
---|
11 | ;; License, or (at your option) any later version. |
---|
12 | ;; |
---|
13 | ;; This program is distributed in the hope that it will be useful, but |
---|
14 | ;; WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
15 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
16 | ;; General Public License for more details. |
---|
17 | ;; |
---|
18 | ;; A full copy of the GPL license can be found at |
---|
19 | ;; <http://www.gnu.org/licenses/>. |
---|
20 | ;; |
---|
21 | |
---|
22 | (module nemo-hh |
---|
23 | |
---|
24 | (nemo:hh-transformer) |
---|
25 | |
---|
26 | (import scheme chicken data-structures srfi-1 srfi-13) |
---|
27 | |
---|
28 | (require-extension matchable environments varsubst nemo-core) |
---|
29 | |
---|
30 | (define (s+ . lst) (string-concatenate (map ->string lst))) |
---|
31 | |
---|
32 | (define (p$ p n) (string->symbol (s+ (->string p) "_" (->string n)))) |
---|
33 | |
---|
34 | |
---|
35 | (define (lookup-field k lst . rest) |
---|
36 | (let-optionals rest ((default #f)) |
---|
37 | (let ((v (alist-ref k lst))) |
---|
38 | (if v (first v) default)))) |
---|
39 | |
---|
40 | |
---|
41 | (define (check-names ion env . names) |
---|
42 | (for-each (lambda (name) |
---|
43 | (if (environment-includes? env name) |
---|
44 | (nemo:error 'nemo:hh-transformer "quantity " name " in ionic conductance declaration " ion |
---|
45 | "is already declared elsewhere"))) |
---|
46 | names)) |
---|
47 | |
---|
48 | (define (check-decls ion names alst . rest) |
---|
49 | (let-optionals rest ((raise-exception? #t)) |
---|
50 | (if raise-exception? |
---|
51 | (for-each (lambda (name) |
---|
52 | (if (not (alist-ref name alst)) |
---|
53 | (nemo:error 'nemo:hh-transformer "required quantity " name |
---|
54 | " is not present in ionic conductance declaration " ion))) |
---|
55 | names) |
---|
56 | (every (lambda (name) (alist-ref name alst)) names)))) |
---|
57 | |
---|
58 | |
---|
59 | (define (handle thunk dflt) |
---|
60 | (condition-case (thunk) |
---|
61 | [(exn) dflt])) |
---|
62 | |
---|
63 | (define (hh-ionic-gate-transform sys parse-expr subst-expr scope-subst scope eval-const env-extend! add-external! component-extend! comp en markov?) |
---|
64 | (define (and-parse-expr scope-subst x . rest) |
---|
65 | (and x (subst-expr (apply parse-expr (cons x rest)) scope-subst))) |
---|
66 | (match en |
---|
67 | ((or (('hh 'ionic 'conductance) ('name (? symbol? ion)) . alst) |
---|
68 | (('hh-ionic-gate) ('name (? symbol? ion)) . alst)) |
---|
69 | |
---|
70 | (check-decls ion '(m-power h-power) alst) |
---|
71 | |
---|
72 | (let* ((suffix (->string ion)) |
---|
73 | |
---|
74 | (m-inf-sym (p$ ion 'm-inf)) |
---|
75 | (m-tau-sym (p$ ion 'm-tau)) |
---|
76 | |
---|
77 | (h-inf-sym (p$ ion 'h-inf)) |
---|
78 | (h-tau-sym (p$ ion 'h-tau)) |
---|
79 | (h-reaction-sym (p$ ion 'h)) |
---|
80 | |
---|
81 | ) |
---|
82 | |
---|
83 | (let ((m-power (eval-const sys (subst-expr |
---|
84 | (parse-expr (lookup-field 'm-power alst) |
---|
85 | `(hh-ionic-gate ,ion (m-power)) |
---|
86 | ) |
---|
87 | scope-subst))) |
---|
88 | (h-power (eval-const sys (subst-expr |
---|
89 | (parse-expr (lookup-field 'h-power alst 0) |
---|
90 | `(hh-ionic-gate ,ion (h-power)) |
---|
91 | ) |
---|
92 | scope-subst)))) |
---|
93 | |
---|
94 | (if (not (and (integer? m-power) (positive? m-power))) |
---|
95 | (nemo:error 'nemo:hh-transformer |
---|
96 | "m-power value in ionic conductance declaration " ion |
---|
97 | " must be a positive integer")) |
---|
98 | |
---|
99 | ;; check for required decls in m |
---|
100 | (check-decls ion '(initial-m) alst) |
---|
101 | (if (not (check-decls ion '(m-inf m-tau) alst #f)) |
---|
102 | (check-decls ion '(m-alpha m-beta) alst)) |
---|
103 | |
---|
104 | ;; check for required decls in h |
---|
105 | (if (positive? h-power) |
---|
106 | (begin (check-decls ion '(initial-h) alst) |
---|
107 | (if (not (check-decls ion '(h-inf h-tau) alst #f)) |
---|
108 | (check-decls ion '(h-alpha h-beta) alst)))) |
---|
109 | |
---|
110 | (if (not (and (integer? h-power) (or (zero? h-power) (positive? m-power)))) |
---|
111 | (nemo:error 'nemo:hh-transformer |
---|
112 | "h-power value in ionic conductance declaration " ion |
---|
113 | " must be a positive integer")) |
---|
114 | |
---|
115 | (let* ((initial-m ((lambda (x) |
---|
116 | (let ((expr (subst-expr |
---|
117 | (parse-expr x `(hh-ionic-gate ,ion (initial-m))) |
---|
118 | scope-subst))) |
---|
119 | (handle (lambda () (eval-const sys expr)) expr))) |
---|
120 | (lookup-field 'initial-m alst))) |
---|
121 | (m-inf (and-parse-expr scope-subst |
---|
122 | (lookup-field 'm-inf alst) |
---|
123 | `(hh-ionic-gate ,ion (m-inf)))) |
---|
124 | (m-tau (and-parse-expr scope-subst |
---|
125 | (lookup-field 'm-tau alst) |
---|
126 | `(hh-ionic-gate ,ion (m-tau)))) |
---|
127 | (m-alpha (and-parse-expr scope-subst |
---|
128 | (lookup-field 'm-alpha alst) |
---|
129 | `(hh-ionic-gate ,ion (m-alpha)))) |
---|
130 | (m-beta (and-parse-expr scope-subst |
---|
131 | (lookup-field 'm-beta alst) |
---|
132 | `(hh-ionic-gate ,ion (m-beta)))) |
---|
133 | (open 'O) |
---|
134 | (closed 'C) |
---|
135 | ) |
---|
136 | |
---|
137 | (if m-inf (env-extend! m-inf-sym '(asgn) 'none `(rhs ,m-inf))) |
---|
138 | (if m-tau (env-extend! m-tau-sym '(asgn) 'none `(rhs ,m-tau))) |
---|
139 | (if m-inf (component-extend! comp m-inf-sym)) |
---|
140 | (if m-tau (component-extend! comp m-tau-sym)) |
---|
141 | |
---|
142 | |
---|
143 | (cond ((or (and m-alpha m-beta) (and markov? m-tau m-inf)) |
---|
144 | (let* ((m-reaction-sym (p$ ion 'm)) |
---|
145 | (m-alpha (or m-alpha |
---|
146 | (subst-expr |
---|
147 | `(let ((x (/ ,m-inf-sym ,m-tau-sym))) x) |
---|
148 | scope-subst))) |
---|
149 | (m-beta (or m-beta |
---|
150 | (subst-expr |
---|
151 | `(let ((x (/ (- 1 ,m-inf-sym) ,m-tau-sym))) x) |
---|
152 | scope-subst))) |
---|
153 | (mst `((power ,m-power) (open ,open) |
---|
154 | (transitions (<-> ,closed ,open ,m-alpha ,m-beta)) |
---|
155 | (conserve (1 = (+ ,closed ,open)))))) |
---|
156 | (apply env-extend! (cons* m-reaction-sym '(reaction) initial-m mst)) |
---|
157 | (add-external! m-reaction-sym 'output) |
---|
158 | (component-extend! comp m-reaction-sym))) |
---|
159 | ((and m-tau m-inf) |
---|
160 | (let* ((m-rate-sym (p$ ion 'm)) |
---|
161 | (rate-rhs `((rhs (/ (- ,m-inf-sym ,m-rate-sym) ,m-tau-sym))))) |
---|
162 | (apply env-extend! (cons* m-rate-sym '(rate) initial-m rate-rhs)) |
---|
163 | (add-external! m-rate-sym 'output) |
---|
164 | (component-extend! comp m-rate-sym) |
---|
165 | )) |
---|
166 | (else |
---|
167 | (nemo:error 'nemo:hh-transformer |
---|
168 | "invalid activation and inactivation rate specification in ionic conductance declaration " |
---|
169 | ion))) |
---|
170 | ) |
---|
171 | |
---|
172 | (if (positive? h-power) |
---|
173 | (let* ((initial-h ((lambda (x) |
---|
174 | (let ((expr (subst-expr |
---|
175 | (parse-expr x `(hh-ionic-gate ,ion (initial-h))) |
---|
176 | scope-subst))) |
---|
177 | (handle (lambda () (eval-const sys expr)) expr))) |
---|
178 | (lookup-field 'initial-h alst))) |
---|
179 | (h-inf (and-parse-expr scope-subst |
---|
180 | (lookup-field 'h-inf alst) |
---|
181 | `(hh-ionic-gate ,ion (h-inf)))) |
---|
182 | (h-tau (and-parse-expr scope-subst |
---|
183 | (lookup-field 'h-tau alst) |
---|
184 | `(hh-ionic-gate ,ion (h-tau)))) |
---|
185 | (h-alpha (and-parse-expr scope-subst |
---|
186 | (lookup-field 'h-alpha alst) |
---|
187 | `(hh-ionic-gate ,ion (h-alpha)))) |
---|
188 | (h-beta (and-parse-expr scope-subst |
---|
189 | (lookup-field 'h-beta alst) |
---|
190 | `(hh-ionic-gate ,ion (h-beta)))) |
---|
191 | (open 'O) |
---|
192 | (closed 'C)) |
---|
193 | |
---|
194 | (if h-inf (env-extend! h-inf-sym '(asgn) 'none `(rhs ,h-inf))) |
---|
195 | (if h-tau (env-extend! h-tau-sym '(asgn) 'none `(rhs ,h-tau))) |
---|
196 | (if h-inf (component-extend! comp h-inf-sym)) |
---|
197 | (if h-tau (component-extend! comp h-tau-sym)) |
---|
198 | |
---|
199 | (cond ((or (and h-alpha h-beta) (and markov? h-tau h-inf)) |
---|
200 | (let* ((h-reaction-sym (p$ ion 'h)) |
---|
201 | (h-alpha (or h-alpha |
---|
202 | (subst-expr |
---|
203 | `(let ((x (/ ,h-inf-sym ,h-tau-sym))) x) |
---|
204 | scope-subst))) |
---|
205 | (h-beta (or h-beta |
---|
206 | (subst-expr |
---|
207 | `(let ((x (/ (- 1 ,h-inf-sym) ,h-tau-sym))) x) |
---|
208 | scope-subst))) |
---|
209 | (hst `((power ,h-power) (open ,open) |
---|
210 | (transitions (<-> ,closed ,open ,h-alpha ,h-beta)) |
---|
211 | (conserve (1 = (+ ,closed ,open)))))) |
---|
212 | (apply env-extend! (cons* h-reaction-sym '(reaction) initial-h hst)) |
---|
213 | (add-external! h-reaction-sym 'output) |
---|
214 | (component-extend! comp h-reaction-sym))) |
---|
215 | ((and h-tau h-inf) |
---|
216 | (let* ((h-rate-sym (p$ ion 'h)) |
---|
217 | (rate-rhs `((rhs (/ (- ,h-inf-sym ,h-rate-sym) ,h-tau-sym))))) |
---|
218 | (apply env-extend! (cons* h-rate-sym '(rate) initial-h rate-rhs)) |
---|
219 | (add-external! h-rate-sym 'output) |
---|
220 | (component-extend! comp h-rate-sym) |
---|
221 | )) |
---|
222 | (else |
---|
223 | (nemo:error 'nemo:hh-transformer |
---|
224 | "invalid activation and inactivation rate specification in ionic conductance declaration " |
---|
225 | ion))) |
---|
226 | |
---|
227 | ))))) |
---|
228 | |
---|
229 | (else (list)))) |
---|
230 | |
---|
231 | (define (nemo:hh-transformer sys markov? . rest) |
---|
232 | (let-optionals rest ((parse-expr (lambda (x . rest) (identity x)))) |
---|
233 | (let ((new-sys (nemo:env-copy sys))) |
---|
234 | (match-let ((($ nemo:quantity 'DISPATCH dis) (environment-ref new-sys (nemo-intern 'dispatch)))) |
---|
235 | (let* ((eval-const (dis 'eval-const)) |
---|
236 | (subst-expr (dis 'subst-expr)) |
---|
237 | (env-extend! ((dis 'env-extend!) new-sys)) |
---|
238 | (add-external! ((dis 'add-external!) new-sys)) |
---|
239 | (component-extend! ((dis 'component-extend!) new-sys)) |
---|
240 | (indent 0) |
---|
241 | (indent+ (+ 2 indent ))) |
---|
242 | (let recur ((comp-name (nemo-intern 'toplevel)) (scope #f)) |
---|
243 | (let* ((comp-symbols ((dis 'component-symbols) new-sys comp-name)) |
---|
244 | (subcomps ((dis 'component-subcomps) new-sys comp-name)) |
---|
245 | (scope-subst ((dis 'component-scope-subst) new-sys comp-name))) |
---|
246 | (for-each (lambda (sym) |
---|
247 | (hh-ionic-gate-transform |
---|
248 | new-sys parse-expr subst-expr scope-subst scope |
---|
249 | (dis 'eval-const) env-extend! add-external! component-extend! |
---|
250 | comp-name (environment-ref new-sys sym) markov?)) |
---|
251 | comp-symbols) |
---|
252 | (for-each (lambda (subcomp) (recur subcomp (or scope subcomp))) (map third subcomps)))) |
---|
253 | new-sys))))) |
---|
254 | ) |
---|