sc_neurocore_engine/bindings/stochastic/
benda_herz.rs1use numpy::{IntoPyArray, PyReadonlyArray1};
10use pyo3::exceptions::PyValueError;
11use pyo3::prelude::*;
12use pyo3::types::PyDict;
13
14use crate::neurons;
15
16#[pyclass(
17 name = "BendaHerzNeuron",
18 module = "sc_neurocore_engine.sc_neurocore_engine"
19)]
20#[derive(Clone)]
21pub struct PyBendaHerzNeuron {
22 inner: neurons::BendaHerzNeuron,
23}
24
25#[pymethods]
26impl PyBendaHerzNeuron {
27 #[new]
28 fn new() -> Self {
29 Self {
30 inner: neurons::BendaHerzNeuron::new(),
31 }
32 }
33
34 fn step(&mut self, current: f64) -> i32 {
35 self.inner.step(current)
36 }
37
38 fn reset(&mut self) {
39 self.inner.reset();
40 }
41
42 fn get_state(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
43 let d = PyDict::new(py);
44 d.set_item("a", self.inner.a)?;
45 d.set_item("phase", self.inner.phase)?;
46 Ok(d.into_any().unbind())
47 }
48}
49
50pub(super) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> {
51 module.add_class::<PyBendaHerzNeuron>()?;
52 module.add_function(wrap_pyfunction!(py_benda_herz_simulate, module)?)?;
53 Ok(())
54}
55
56#[pyfunction]
57#[pyo3(signature=(a,phase,onset_gain,rheobase,adaptation_slope,tau_a,dt,currents))]
58#[allow(clippy::too_many_arguments)]
59fn py_benda_herz_simulate<'py>(
60 py: Python<'py>,
61 a: f64,
62 phase: f64,
63 onset_gain: f64,
64 rheobase: f64,
65 adaptation_slope: f64,
66 tau_a: f64,
67 dt: f64,
68 currents: PyReadonlyArray1<'py, f64>,
69) -> PyResult<Py<PyAny>> {
70 let mut neuron = neurons::BendaHerzNeuron {
71 a,
72 phase,
73 onset_gain,
74 rheobase,
75 adaptation_slope,
76 tau_a,
77 dt,
78 };
79 if !neuron.valid() {
80 return Err(PyValueError::new_err("invalid Benda-Herz configuration"));
81 }
82 let mut adaptation = Vec::with_capacity(currents.len()?);
83 let mut phases = Vec::with_capacity(currents.len()?);
84 let mut events = Vec::with_capacity(currents.len()?);
85 for ¤t in currents.as_slice()? {
86 let event = neuron.step(current);
87 if event < 0 {
88 return Err(PyValueError::new_err("invalid Benda-Herz transition"));
89 }
90 adaptation.push(neuron.a);
91 phases.push(neuron.phase);
92 events.push(event);
93 }
94 let d = PyDict::new(py);
95 d.set_item("adaptation", adaptation.into_pyarray(py))?;
96 d.set_item("phases", phases.into_pyarray(py))?;
97 d.set_item("events", events.into_pyarray(py))?;
98 d.set_item("a_final", neuron.a)?;
99 d.set_item("phase_final", neuron.phase)?;
100 Ok(d.into_any().unbind())
101}