Skip to content

Commit 43dcedf

Browse files
committed
reason for not match
1 parent 45a65ca commit 43dcedf

File tree

1 file changed

+241
-0
lines changed

1 file changed

+241
-0
lines changed

NeuroML2/compare_MC/RE/REASON.md

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
# Difference Between Gate Multipliers in HH2_magic and HH2_reason
2+
3+
This note compares `HH2_magic` and `HH2_reason` with respect to **when the gate multipliers `m_fcond / h_fcond / n_fcond` are updated**, and shows the corresponding auto-generated C++ code and the time-stepping order.
4+
5+
We use the following notation:
6+
7+
- Gating variables: `m(t), h(t), n(t)`
8+
- Gate multipliers:
9+
- `m_fcond(t) = m(t)^3`
10+
- `h_fcond(t) = h(t)`
11+
- `n_fcond(t) = n(t)^4`
12+
- Sodium and potassium currents:
13+
- `inahh2(t) = gnabar * m_fcond(t) * h_fcond(t) * (v(t) - ena)`
14+
- `ikhh2(t) = gkbar * n_fcond(t) * (v(t) - ek)`
15+
16+
Key question: in a discrete time step `t_n → t_{n+1}`, at which time point (`t_n` or `t_{n+1}`) are `m_fcond / h_fcond / n_fcond` computed from `m,h,n`?
17+
18+
---
19+
20+
## 1. MOD-Level Comparison
21+
22+
### 1.1 HH2_magic.mod (gate multipliers computed in BREAKPOINT)
23+
24+
Key fragment (simplified):
25+
26+
```nmodl
27+
BREAKPOINT {
28+
SOLVE state METHOD cnexp
29+
30+
: gate fcond factors (similar to HH2_nondiff style)
31+
m_fcond = m*m*m
32+
h_fcond = h
33+
n_fcond = n*n*n*n
34+
35+
: Use precomputed fcond factors (set in evaluate_fct)
36+
inahh2 = gnabar * m_fcond * h_fcond * (v - ena)
37+
ikhh2 = gkbar * n_fcond * (v - ek)
38+
ina = inahh2
39+
ik = ikhh2
40+
}
41+
42+
DERIVATIVE state {
43+
evaluate_fct(v)
44+
m' = (m_inf - m) / tau_m
45+
h' = (h_inf - h) / tau_h
46+
n' = (n_inf - n) / tau_n
47+
}
48+
49+
PROCEDURE evaluate_fct(v(mV)) {
50+
...
51+
tau_m, tau_h, tau_n, m_inf, h_inf, n_inf, m_exp, h_exp, n_exp
52+
are computed from v
53+
...
54+
}
55+
```
56+
57+
Properties:
58+
59+
- In `BREAKPOINT`, after `state` has updated `m,h,n`, the code **immediately recomputes `m_fcond, h_fcond, n_fcond` from the updated `m,h,n`**.
60+
- `evaluate_fct` only computes time constants and steady-state values from `v`, and does not touch `m_fcond / h_fcond / n_fcond`.
61+
62+
### 1.2 HH2_reason.mod (gate multipliers computed in evaluate_fct)
63+
64+
Key fragment:
65+
66+
```nmodl
67+
BREAKPOINT {
68+
SOLVE state METHOD cnexp
69+
70+
: Use precomputed fcond factors (set in evaluate_fct)
71+
inahh2 = gnabar * m_fcond * h_fcond * (v - ena)
72+
ikhh2 = gkbar * n_fcond * (v - ek)
73+
ina = inahh2
74+
ik = ikhh2
75+
}
76+
77+
DERIVATIVE state {
78+
evaluate_fct(v)
79+
m' = (m_inf - m) / tau_m
80+
h' = (h_inf - h) / tau_h
81+
n' = (n_inf - n) / tau_n
82+
}
83+
84+
PROCEDURE evaluate_fct(v(mV)) {
85+
...
86+
tau_m, tau_h, tau_n, m_inf, h_inf, n_inf, m_exp, h_exp, n_exp
87+
are computed from v
88+
...
89+
m_exp = 1 - Exp(-dt/tau_m)
90+
h_exp = 1 - Exp(-dt/tau_h)
91+
n_exp = 1 - Exp(-dt/tau_n)
92+
93+
: gate fcond factors (similar to HH2_nondiff style)
94+
m_fcond = m*m*m
95+
h_fcond = h
96+
n_fcond = n*n*n*n
97+
}
98+
```
99+
100+
Properties:
101+
102+
- `BREAKPOINT` no longer updates `m_fcond / h_fcond / n_fcond`; it only uses them.
103+
- `evaluate_fct(v)` computes `tau_*` and `*_inf` and then **updates the gate multipliers from the current `m,h,n`**.
104+
105+
---
106+
107+
## 2. Time Ordering in the Auto-Generated C++ Code
108+
109+
Assume fixed time step and `cnexp` method. For one step `t_n → t_{n+1}`:
110+
111+
- `m_n = m(t_n), m_{n+1} = m(t_{n+1})`
112+
- `v_n = v(t_n)` (voltage is determined by solving the cable equation; here we focus only on `m,h,n` vs gate multipliers).
113+
114+
### 2.1 Call Order in HH2_magic.cpp
115+
116+
Key functions (irrelevant parts omitted):
117+
118+
```cpp
119+
// state: call evaluate_fct(v) first, then update m,h,n with cnexp
120+
static int state (_internalthreadargsproto_) { {
121+
evaluate_fct ( _threadargscomma_ v ) ;
122+
m = m + (1. - exp(dt*(( ( ( - 1.0 ) ) ) / tau_m)))*(- ( ( ( m_inf ) ) / tau_m ) / ( ( ( ( - 1.0 ) ) ) / tau_m ) - m) ;
123+
h = h + (1. - exp(dt*(( ( ( - 1.0 ) ) ) / tau_h)))*(- ( ( ( h_inf ) ) / tau_h ) / ( ( ( ( - 1.0 ) ) ) / tau_h ) - h) ;
124+
n = n + (1. - exp(dt*(( ( ( - 1.0 ) ) ) / tau_n)))*(- ( ( ( n_inf ) ) / tau_n ) / ( ( ( ( - 1.0 ) ) ) / tau_n ) - n) ;
125+
}
126+
return 0;
127+
}
128+
129+
// evaluate_fct: updates *_inf, tau_*, *_exp, but NOT m_fcond/h_fcond/n_fcond
130+
static int evaluate_fct ( _internalthreadargsprotocomma_ double _lv ) {
131+
...
132+
tau_m = 1.0 / ( _la + _lb ) / tadj ;
133+
m_inf = _la / ( _la + _lb ) ;
134+
...
135+
tau_h = ...
136+
h_inf = ...
137+
...
138+
tau_n = ...
139+
n_inf = ...
140+
m_exp = 1.0 - Exp ( _threadargscomma_ - dt / tau_m ) ;
141+
h_exp = 1.0 - Exp ( _threadargscomma_ - dt / tau_h ) ;
142+
n_exp = 1.0 - Exp ( _threadargscomma_ - dt / tau_n ) ;
143+
return 0;
144+
}
145+
146+
// _nrn_current: recompute gate multipliers from CURRENT m,h,n
147+
static double _nrn_current(_internalthreadargsprotocomma_ double _v) {
148+
double _current=0.; v=_v;
149+
{ {
150+
m_fcond = m * m * m ;
151+
h_fcond = h ;
152+
n_fcond = n * n * n * n ;
153+
inahh2 = gnabar * m_fcond * h_fcond * ( v - ena ) ;
154+
ikhh2 = gkbar * n_fcond * ( v - ek ) ;
155+
ina = inahh2 ;
156+
ik = ikhh2 ;
157+
}
158+
_current += ina;
159+
_current += ik;
160+
161+
} return _current;
162+
}
163+
```
164+
165+
For `t_n → t_{n+1}`:
166+
167+
1. At the beginning of the step: `m = m_n`.
168+
2. Call `state()`:
169+
- `evaluate_fct(v_n)` computes `tau_m, tau_h, tau_n, m_inf, ...`; it does **not** touch `m_fcond / h_fcond / n_fcond`;
170+
- cnexp updates `m,h,n` to `m_{n+1}, h_{n+1}, n_{n+1}`.
171+
3. Call `_nrn_current()`:
172+
- recompute the gate multipliers from **updated** `m_{n+1}, h_{n+1}, n_{n+1}`;
173+
- compute `inahh2, ikhh2` from these multipliers.
174+
175+
Conclusion: **in `HH2_magic`, the gate multipliers used in the current are aligned with `m,h,n` at time `t_{n+1}`.**
176+
177+
### 2.2 Call Order in HH2_reason.cpp
178+
179+
Key functions:
180+
181+
```cpp
182+
// state: also calls evaluate_fct(v) first, then updates m,h,n
183+
static int state (_internalthreadargsproto_) { {
184+
evaluate_fct ( _threadargscomma_ v ) ;
185+
m = m + (1. - exp(dt*(( ( ( - 1.0 ) ) ) / tau_m)))*(- ( ( ( m_inf ) ) / tau_m ) / ( ( ( ( - 1.0 ) ) ) / tau_m ) - m) ;
186+
h = h + (1. - exp(dt*(( ( ( - 1.0 ) ) ) / tau_h)))*(- ( ( ( h_inf ) ) / tau_h ) / ( ( ( ( - 1.0 ) ) ) / tau_h ) - h) ;
187+
n = n + (1. - exp(dt*(( ( ( - 1.0 ) ) ) / tau_n)))*(- ( ( ( n_inf ) ) / tau_n ) / ( ( ( ( - 1.0 ) ) ) / tau_n ) - n) ;
188+
}
189+
return 0;
190+
}
191+
192+
// evaluate_fct: at the END, update gate multipliers from CURRENT m,h,n
193+
static int evaluate_fct ( _internalthreadargsprotocomma_ double _lv ) {
194+
...
195+
tau_m = ...
196+
m_inf = ...
197+
...
198+
tau_h = ...
199+
h_inf = ...
200+
...
201+
tau_n = ...
202+
n_inf = ...
203+
m_exp = 1.0 - Exp ( _threadargscomma_ - dt / tau_m ) ;
204+
h_exp = 1.0 - Exp ( _threadargscomma_ - dt / tau_h ) ;
205+
n_exp = 1.0 - Exp ( _threadargscomma_ - dt / tau_n ) ;
206+
m_fcond = m * m * m ;
207+
h_fcond = h ;
208+
n_fcond = n * n * n * n ;
209+
return 0;
210+
}
211+
212+
// _nrn_current: just uses the precomputed gate multipliers
213+
static double _nrn_current(_internalthreadargsprotocomma_ double _v) {
214+
double _current=0.; v=_v;
215+
{ {
216+
inahh2 = gnabar * m_fcond * h_fcond * ( v - ena ) ;
217+
ikhh2 = gkbar * n_fcond * ( v - ek ) ;
218+
ina = inahh2 ;
219+
ik = ikhh2 ;
220+
}
221+
_current += ina;
222+
_current += ik;
223+
224+
} return _current;
225+
}
226+
```
227+
228+
For `t_n → t_{n+1}`:
229+
230+
1. At the beginning of the step: `m = m_n`.
231+
2. Call `state()`:
232+
- `evaluate_fct(v_n)`:
233+
- computes `tau_m, tau_h, tau_n, m_inf, ...` from `v_n`;
234+
- uses the **current** `m_n, h_n, n_n` to write `m_fcond, h_fcond, n_fcond`;
235+
- cnexp then updates `m,h,n` to `m_{n+1}, h_{n+1}, n_{n+1}`.
236+
3. Call `_nrn_current()`:
237+
- uses the precomputed `m_fcond, h_fcond, n_fcond` from step 2;
238+
- at this moment `m,h,n` are already `m_{n+1}, h_{n+1}, n_{n+1}`, but the gate multipliers still correspond to `m_n, h_n, n_n`.
239+
240+
Conclusion: **in `HH2_reason`, the gate multipliers used in the current correspond to the gating state at time `t_n`, while `m,h,n` themselves have advanced to `t_{n+1}`. The gate multipliers lag one time step behind the gating variables.**
241+

0 commit comments

Comments
 (0)