1#[allow(clippy::too_many_arguments)]
34pub fn step_kernel(
35 v_e: &mut [f64],
37 g_ampa_e: &mut [f64],
38 g_gaba_e: &mut [f64],
39 refrac_e: &mut [f64],
40 i_drive_e: &[f64],
41 xi_e: &[f64],
42 spikes_e_out: &mut [u8],
43 v_i: &mut [f64],
45 g_ampa_i: &mut [f64],
46 g_gaba_i: &mut [f64],
47 refrac_i: &mut [f64],
48 i_drive_i: &[f64],
49 xi_i: &[f64],
50 spikes_i_out: &mut [u8],
51 e_l: f64,
53 e_ampa: f64,
54 e_gaba: f64,
55 g_l: f64,
56 c_m: f64,
57 v_threshold: f64,
58 v_reset: f64,
59 t_refrac: f64,
60 tau_ampa: f64,
62 tau_gaba: f64,
63 sigma_e: f64,
65 sigma_i: f64,
66 dt: f64,
68) -> (u32, u32) {
69 let decay_ampa = (-dt / tau_ampa).exp();
70 let decay_gaba = (-dt / tau_gaba).exp();
71 let dt_over_cm = dt / c_m;
72 let sqrt_dt = dt.sqrt();
73
74 for g in g_ampa_e.iter_mut() {
76 *g *= decay_ampa;
77 }
78 for g in g_ampa_i.iter_mut() {
79 *g *= decay_ampa;
80 }
81 for g in g_gaba_e.iter_mut() {
82 *g *= decay_gaba;
83 }
84 for g in g_gaba_i.iter_mut() {
85 *g *= decay_gaba;
86 }
87
88 let mut n_e: u32 = 0;
99 let n_excit = v_e.len();
100 for k in 0..n_excit {
101 let in_refrac = refrac_e[k] > 0.0;
102 let v_old = v_e[k];
103 let i_leak = -g_l * (v_old - e_l);
104 let i_ampa = -g_ampa_e[k] * (v_old - e_ampa);
105 let i_gaba = -g_gaba_e[k] * (v_old - e_gaba);
106 let i_total = i_leak + i_ampa + i_gaba + i_drive_e[k];
107 let noise = sqrt_dt * sigma_e * xi_e[k];
108 let v_new = if in_refrac {
109 v_reset
110 } else {
111 v_old + i_total * dt_over_cm + noise
112 };
113 let spk = v_new >= v_threshold && !in_refrac;
114 v_e[k] = if spk { v_reset } else { v_new };
115 let new_refrac = if spk { t_refrac } else { refrac_e[k] - dt };
116 refrac_e[k] = if new_refrac > 0.0 { new_refrac } else { 0.0 };
117 spikes_e_out[k] = u8::from(spk);
118 if spk {
119 n_e += 1;
120 }
121 }
122
123 let mut n_i: u32 = 0;
125 let n_inh = v_i.len();
126 for k in 0..n_inh {
127 let in_refrac = refrac_i[k] > 0.0;
128 let v_old = v_i[k];
129 let i_leak = -g_l * (v_old - e_l);
130 let i_ampa = -g_ampa_i[k] * (v_old - e_ampa);
131 let i_gaba = -g_gaba_i[k] * (v_old - e_gaba);
132 let i_total = i_leak + i_ampa + i_gaba + i_drive_i[k];
133 let noise = sqrt_dt * sigma_i * xi_i[k];
134 let v_new = if in_refrac {
135 v_reset
136 } else {
137 v_old + i_total * dt_over_cm + noise
138 };
139 let spk = v_new >= v_threshold && !in_refrac;
140 v_i[k] = if spk { v_reset } else { v_new };
141 let new_refrac = if spk { t_refrac } else { refrac_i[k] - dt };
142 refrac_i[k] = if new_refrac > 0.0 { new_refrac } else { 0.0 };
143 spikes_i_out[k] = u8::from(spk);
144 if spk {
145 n_i += 1;
146 }
147 }
148
149 (n_e, n_i)
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 #[test]
158 fn test_no_drive_no_spikes() {
159 let n_e = 4;
160 let n_i = 2;
161 let mut v_e = vec![-67.0_f64; n_e];
162 let mut v_i = vec![-67.0_f64; n_i];
163 let mut g_ampa_e = vec![0.0; n_e];
164 let mut g_ampa_i = vec![0.0; n_i];
165 let mut g_gaba_e = vec![0.0; n_e];
166 let mut g_gaba_i = vec![0.0; n_i];
167 let mut refrac_e = vec![0.0; n_e];
168 let mut refrac_i = vec![0.0; n_i];
169 let i_drive_e = vec![0.0; n_e];
170 let i_drive_i = vec![0.0; n_i];
171 let xi_e = vec![0.0; n_e];
172 let xi_i = vec![0.0; n_i];
173 let mut spk_e = vec![0_u8; n_e];
174 let mut spk_i = vec![0_u8; n_i];
175
176 let (ne, ni) = step_kernel(
177 &mut v_e,
178 &mut g_ampa_e,
179 &mut g_gaba_e,
180 &mut refrac_e,
181 &i_drive_e,
182 &xi_e,
183 &mut spk_e,
184 &mut v_i,
185 &mut g_ampa_i,
186 &mut g_gaba_i,
187 &mut refrac_i,
188 &i_drive_i,
189 &xi_i,
190 &mut spk_i,
191 -67.0,
192 0.0,
193 -80.0,
194 0.05,
195 1.0,
196 -52.0,
197 -67.0,
198 2.0,
199 5.0,
200 5.0,
201 0.0,
202 0.0,
203 0.1,
204 );
205 assert_eq!(ne, 0);
206 assert_eq!(ni, 0);
207 for v in &v_e {
208 assert!((v - (-67.0)).abs() < 1e-9);
210 }
211 }
212
213 #[test]
216 fn test_drive_produces_spikes_and_refractory_holds() {
217 let n_e = 1;
218 let n_i = 1;
219 let mut v_e = vec![-67.0_f64; n_e];
220 let mut v_i = vec![-67.0_f64; n_i];
221 let mut g_ampa_e = vec![0.0; n_e];
222 let mut g_ampa_i = vec![0.0; n_i];
223 let mut g_gaba_e = vec![0.0; n_e];
224 let mut g_gaba_i = vec![0.0; n_i];
225 let mut refrac_e = vec![0.0; n_e];
226 let mut refrac_i = vec![0.0; n_i];
227 let i_drive_e = vec![5.0; n_e]; let i_drive_i = vec![0.0; n_i];
229 let xi_e = vec![0.0; n_e];
230 let xi_i = vec![0.0; n_i];
231 let mut total_spikes_e = 0_u32;
232 let mut last_spike_step = -1_i32;
233
234 for step in 0..400_i32 {
235 let mut spk_e = vec![0_u8; n_e];
236 let mut spk_i = vec![0_u8; n_i];
237 let (ne, _ni) = step_kernel(
238 &mut v_e,
239 &mut g_ampa_e,
240 &mut g_gaba_e,
241 &mut refrac_e,
242 &i_drive_e,
243 &xi_e,
244 &mut spk_e,
245 &mut v_i,
246 &mut g_ampa_i,
247 &mut g_gaba_i,
248 &mut refrac_i,
249 &i_drive_i,
250 &xi_i,
251 &mut spk_i,
252 -67.0,
253 0.0,
254 -80.0,
255 0.05,
256 1.0,
257 -52.0,
258 -67.0,
259 2.0,
260 5.0,
261 5.0,
262 0.0,
263 0.0,
264 0.1,
265 );
266 if ne > 0 {
267 if last_spike_step >= 0 {
268 assert!(step - last_spike_step >= 20);
271 }
272 last_spike_step = step;
273 }
274 total_spikes_e += ne;
275 }
276 assert!(total_spikes_e > 0);
277 }
278
279 #[test]
281 fn test_deterministic_for_same_inputs() {
282 let n_e = 8;
283 let n_i = 4;
284 let mk = || {
285 (
286 vec![-65.0_f64; n_e],
287 vec![-65.0_f64; n_i],
288 vec![0.5_f64; n_e],
289 vec![0.5_f64; n_i],
290 vec![0.3_f64; n_e],
291 vec![0.3_f64; n_i],
292 vec![0.0_f64; n_e],
293 vec![0.0_f64; n_i],
294 )
295 };
296 let xi_e = vec![0.1_f64; n_e];
297 let xi_i = vec![-0.1_f64; n_i];
298 let i_drive_e = vec![1.0; n_e];
299 let i_drive_i = vec![0.5; n_i];
300
301 let (
302 mut v_e_a,
303 mut v_i_a,
304 mut ga_e_a,
305 mut ga_i_a,
306 mut gg_e_a,
307 mut gg_i_a,
308 mut rf_e_a,
309 mut rf_i_a,
310 ) = mk();
311 let (
312 mut v_e_b,
313 mut v_i_b,
314 mut ga_e_b,
315 mut ga_i_b,
316 mut gg_e_b,
317 mut gg_i_b,
318 mut rf_e_b,
319 mut rf_i_b,
320 ) = mk();
321 let mut spk_e_a = vec![0_u8; n_e];
322 let mut spk_i_a = vec![0_u8; n_i];
323 let mut spk_e_b = vec![0_u8; n_e];
324 let mut spk_i_b = vec![0_u8; n_i];
325
326 let _ = step_kernel(
327 &mut v_e_a,
328 &mut ga_e_a,
329 &mut gg_e_a,
330 &mut rf_e_a,
331 &i_drive_e,
332 &xi_e,
333 &mut spk_e_a,
334 &mut v_i_a,
335 &mut ga_i_a,
336 &mut gg_i_a,
337 &mut rf_i_a,
338 &i_drive_i,
339 &xi_i,
340 &mut spk_i_a,
341 -67.0,
342 0.0,
343 -80.0,
344 0.05,
345 1.0,
346 -52.0,
347 -67.0,
348 2.0,
349 5.0,
350 5.0,
351 0.1,
352 0.05,
353 0.1,
354 );
355 let _ = step_kernel(
356 &mut v_e_b,
357 &mut ga_e_b,
358 &mut gg_e_b,
359 &mut rf_e_b,
360 &i_drive_e,
361 &xi_e,
362 &mut spk_e_b,
363 &mut v_i_b,
364 &mut ga_i_b,
365 &mut gg_i_b,
366 &mut rf_i_b,
367 &i_drive_i,
368 &xi_i,
369 &mut spk_i_b,
370 -67.0,
371 0.0,
372 -80.0,
373 0.05,
374 1.0,
375 -52.0,
376 -67.0,
377 2.0,
378 5.0,
379 5.0,
380 0.1,
381 0.05,
382 0.1,
383 );
384
385 assert_eq!(v_e_a, v_e_b);
386 assert_eq!(v_i_a, v_i_b);
387 assert_eq!(spk_e_a, spk_e_b);
388 assert_eq!(spk_i_a, spk_i_b);
389 }
390}