You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: NeuroML2/compare_MC/RE/REASON.md
+293Lines changed: 293 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -239,3 +239,296 @@ For `t_n → t_{n+1}`:
239
239
240
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
241
242
+
---
243
+
244
+
# Difference Between cadad and cadad_RE_soma_nml
245
+
246
+
This note compares the classic Destexhe-style Ca pump `cadad` (`mod/cadad.mod`) with the NeuroML-exported Ca concentration mechanism `cadad_RE_soma_nml` (`mod/cadad_RE_soma_nml.mod`), focusing on why the **NML-fix vs NRN native** runs diverged once `cadad` was included, and how we made the two behaviors match.
247
+
248
+
We use the following notation:
249
+
250
+
- Ionic Ca concentration used by NEURON: `cai(t)` (the `ca_ion` concentration)
251
+
- NML-exported internal state: `concentration(t)` (in `cadad_RE_soma_nml`)
Key question: **for the same `ica(t)` and parameters, and with fixed time step / `cnexp`, do `cadad` and `cadad_RE_soma_nml` integrate `cai(t)` in exactly the same way, including how `cai` is initialised at `t = 0`?**
Here the true ODE state is `concentration`; `cai` is an alias that is updated each step from `concentration`. The NeuroML exporter also uses explicit `area` and a different choice of units for `depth` and `Faraday`.
370
+
371
+
---
372
+
373
+
## 2. Are the ODEs Numerically Equivalent?
374
+
375
+
Ignoring initialisation for the moment, and substituting the definitions in `rates()`:
So up to floating-point rounding, **both mechanisms implement the same continuous-time ODE for Ca concentration**, provided the parameters are set as in:
415
+
416
+
-`run_neuron_full.py` for `cadad` (depth = 1.0 (µm)),
417
+
-`run_neuron_full_nml_fix.py` for `cadad_RE_soma_nml` (depth = 1e-4 (cm), Faraday as above).
418
+
419
+
This means the source of the discrepancy is **not** a missing / extra factor of 10 or 10000 in the ODE itself.
420
+
421
+
---
422
+
423
+
## 3. The Real Difference: Initialisation of `cai` at t = 0
424
+
425
+
### 3.1 `cadad.mod` initialisation
426
+
427
+
For `cadad.mod` (see `x86_64/cadad.cpp`), the generated `nrn_init` does roughly:
428
+
429
+
1. Read the existing ionic Ca concentration into the mechanism:
430
+
-`cai = _ion_cai`
431
+
2. Call `initmodel()` (which implements the `INITIAL` block):
432
+
-`cai = cainf`
433
+
3. Write back to the ion:
434
+
-`_ion_cai = cai`
435
+
436
+
Thus, **at `t = 0`, the pump forces `ca_ion.cai` to `cainf`**, regardless of what Python set `seg.cai` to before `finitialize`. In `run_neuron_full.py`:
437
+
438
+
```python
439
+
for seg in soma:
440
+
seg.cai =5.0e-5
441
+
seg.cao =2.0
442
+
...
443
+
soma.insert("cadad")
444
+
soma.depth_cadad =1.0
445
+
soma.taur_cadad =5.0
446
+
soma.cainf_cadad =2.4e-4
447
+
...
448
+
h.finitialize(h.v_init)
449
+
```
450
+
451
+
the `seg.cai = 5e-5` assignment is **overridden at initialisation**; the simulation actually starts from `cai = 2.4e-4` due to the `INITIAL { cai = cainf }` in `cadad.mod`.
452
+
453
+
### 3.2 Original `cadad_RE_soma_nml.mod` initialisation
454
+
455
+
Before our change, the NML-exported `INITIAL` block was:
456
+
457
+
```nmodl
458
+
INITIAL {
459
+
initialConcentration = cai
460
+
initialExtConcentration = cao
461
+
rates()
462
+
rates() ? To ensure correct initialisation.
463
+
464
+
concentration = initialConcentration
465
+
extConcentration = initialExtConcentration
466
+
}
467
+
```
468
+
469
+
The generated C++ `nrn_init` for `cadad_RE_soma_nml` (`x86_64/cadad_RE_soma_nml.cpp`) did:
470
+
471
+
1. Read the ionic concentrations:
472
+
-`cai = _ion_cai`
473
+
-`cao = _ion_cao`
474
+
2. Call `initmodel()`:
475
+
-`initialConcentration` and `concentration` are set based on the existing `cai` / `cao`,
476
+
-**but `cai` itself is not modified** in the `INITIAL` block.
477
+
3. Write back:
478
+
-`_ion_cai = cai`
479
+
480
+
Therefore, unlike `cadad.mod`, the NML mechanism **did not override `cai` at `t = 0`**. It started with the Python-assigned value (`5e-5`), even though its internal state `concentration` was set consistently.
481
+
482
+
Combined with the fact that `run_neuron_full_nml_fix.py` explicitly sets:
-**NML-fix + `cadad_RE_soma_nml` (original)**: starts from `cai = 5e-5`, only later relaxing towards `cainf`.
499
+
500
+
Given the strong nonlinearity of T-type Ca currents and Ca-dependent dynamics, this different initial `cai` is enough to produce the observed divergence in the voltage traces when `cadad` is present, while the `noCadad` runs match almost exactly.
501
+
502
+
---
503
+
504
+
## 4. Fix: Make `cadad_RE_soma_nml` Initialise `cai` Like `cadad`
505
+
506
+
To align the behavior of the NML-exported mechanism with the original `cadad.mod`, we changed the `INITIAL` block in `mod/cadad_RE_soma_nml.mod` to explicitly set `cai` to `cainf` before setting up the internal state:
507
+
508
+
```nmodl
509
+
INITIAL {
510
+
: Align with cadad.mod: force cai to start at cainf
511
+
cai = cainf
512
+
513
+
initialConcentration = cai
514
+
initialExtConcentration = cao
515
+
rates()
516
+
rates() ? To ensure correct initialisation.
517
+
518
+
concentration = initialConcentration
519
+
extConcentration = initialExtConcentration
520
+
}
521
+
```
522
+
523
+
Conceptually, this makes the two mechanisms agree on:
524
+
525
+
- The continuous-time ODE for Ca concentration (`dcai/dt`),
526
+
- The effective scaling from `ica` to `dcai/dt` (via `depth`, `Faraday`, and unit conversions),
527
+
-**And crucially, the initial condition `cai(t=0) = cainf`**, matching what `cadad.mod` has always done.
528
+
529
+
After recompiling the mechanisms (e.g. `nrnivmodl mod`) and rerunning:
0 commit comments