sc_neurocore_engine/neurons/biophysical/
destexhe_thalamic.rs1#[derive(Clone, Debug)]
13pub struct DestexheThalamicNeuron {
14 pub v: f64,
15 pub h_na: f64,
16 pub n_k: f64,
17 pub m_t: f64,
18 pub h_t: f64,
19 pub g_na: f64,
20 pub g_k: f64,
21 pub g_t: f64,
22 pub g_l: f64,
23 pub e_na: f64,
24 pub e_k: f64,
25 pub e_ca: f64,
26 pub e_l: f64,
27 pub dt: f64,
28 pub v_threshold: f64,
29}
30
31impl DestexheThalamicNeuron {
32 pub fn new() -> Self {
33 Self {
34 v: -65.0,
35 h_na: 0.6,
36 n_k: 0.3,
37 m_t: 0.0,
38 h_t: 1.0,
39 g_na: 100.0,
40 g_k: 10.0,
41 g_t: 2.0,
42 g_l: 0.05,
43 e_na: 50.0,
44 e_k: -90.0,
45 e_ca: 120.0,
46 e_l: -70.0,
47 dt: 0.02,
48 v_threshold: -20.0,
49 }
50 }
51 pub fn step(&mut self, current: f64) -> i32 {
52 let v_prev = self.v;
53 for _ in 0..5 {
54 let m_na = 1.0 / (1.0 + (-(self.v + 37.0) / 7.0).exp());
55 let h_na_inf = 1.0 / (1.0 + ((self.v + 41.0) / 4.0).exp());
56 let n_inf = 1.0 / (1.0 + (-(self.v + 25.0) / 12.0).exp());
57 let m_t_inf = 1.0 / (1.0 + (-(self.v + 57.0) / 6.5).exp());
58 let h_t_inf = 1.0 / (1.0 + ((self.v + 81.0) / 4.0).exp());
59 let tau_h_na = (1.0
61 / (0.128 * (-(self.v + 46.0) / 18.0).exp()
62 + 4.0 / (1.0 + (-(self.v + 23.0) / 5.0).exp())))
63 .max(0.1);
64 let tau_n_k = (1.0 / (0.032 * 5.0 + 0.5 * (-(self.v + 40.0) / 40.0).exp())).max(0.1);
65 let tau_h_t = if self.v < -81.0 {
66 (30.8
67 + 211.4 * ((self.v + 115.2) / 5.0).exp()
68 / (1.0 + ((self.v + 86.0) / 3.2).exp()))
69 .max(0.1)
70 } else {
71 10.0
72 };
73 self.h_na += (h_na_inf - self.h_na) / tau_h_na * self.dt;
74 self.n_k += (n_inf - self.n_k) / tau_n_k * self.dt;
75 self.m_t = m_t_inf; self.h_t += (h_t_inf - self.h_t) / tau_h_t * self.dt;
77 let i_na = self.g_na * m_na.powi(3) * self.h_na * (self.v - self.e_na);
78 let i_k = self.g_k * self.n_k.powi(4) * (self.v - self.e_k);
79 let i_t = self.g_t * self.m_t.powi(2) * self.h_t * (self.v - self.e_ca);
80 let i_l = self.g_l * (self.v - self.e_l);
81 self.v += (-i_na - i_k - i_t - i_l + current) * self.dt;
82 }
83 if self.v >= self.v_threshold && v_prev < self.v_threshold {
84 1
85 } else {
86 0
87 }
88 }
89 pub fn reset(&mut self) {
90 self.v = -65.0;
91 self.h_na = 0.6;
92 self.n_k = 0.3;
93 self.m_t = 0.0;
94 self.h_t = 1.0;
95 }
96}
97impl Default for DestexheThalamicNeuron {
98 fn default() -> Self {
99 Self::new()
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn default_matches_constructor_state() {
109 let default = DestexheThalamicNeuron::default();
110 let constructed = DestexheThalamicNeuron::new();
111 assert_eq!(default.v, constructed.v);
112 }
113
114 #[test]
115 fn destexhe_fires() {
116 let mut n = DestexheThalamicNeuron::new();
117 let t: i32 = (0..500).map(|_| n.step(5.0)).sum();
118 assert!(t > 0);
119 }
120
121 #[test]
123 fn destexhe_no_crash_zero_input() {
124 let mut n = DestexheThalamicNeuron::new();
125 let _t: i32 = (0..500).map(|_| n.step(0.0)).sum();
126 assert!(n.v.is_finite());
128 }
129 #[test]
130 fn destexhe_reset_clears_state() {
131 let mut n = DestexheThalamicNeuron::new();
132 for _ in 0..200 {
133 n.step(5.0);
134 }
135 n.reset();
136 assert!((n.v - (-65.0)).abs() < 1e-10);
137 }
138 #[test]
139 fn destexhe_extreme_bounded() {
140 let mut n = DestexheThalamicNeuron::new();
141 for _ in 0..200 {
142 n.step(1e4);
143 }
144 assert!(n.v.is_finite());
145 }
146 #[test]
147 fn destexhe_t_current_rebound() {
148 let v_hyp = -90.0_f64;
152 let h_t_inf = 1.0 / (1.0 + ((v_hyp + 81.0) / 4.0).exp());
153 assert!(h_t_inf > 0.9, "h_t_inf should be ~1 at V=-90: {}", h_t_inf);
154
155 let mut n = DestexheThalamicNeuron::new();
157 for _ in 0..500 {
158 n.step(-5.0);
159 }
160 let v_before_release = n.v;
161 for _ in 0..500 {
162 n.step(0.0);
163 }
164 assert!(n.v.is_finite());
165 assert!(
166 n.v > v_before_release,
167 "V should increase after release (rebound)"
168 );
169 }
170 #[test]
171 fn destexhe_negative_no_crash() {
172 let mut n = DestexheThalamicNeuron::new();
173 for _ in 0..200 {
174 n.step(-20.0);
175 }
176 assert!(n.v.is_finite());
177 }
178 #[test]
179 fn destexhe_nan_no_panic() {
180 let mut n = DestexheThalamicNeuron::new();
181 n.step(f64::NAN);
182 }
183}