|
14 | 14 | 'HH', |
15 | 15 | 'MorrisLecar', |
16 | 16 | 'PinskyRinzelModel', |
| 17 | + 'WangBuzsakiModel', |
17 | 18 | ] |
18 | 19 |
|
19 | 20 |
|
@@ -204,6 +205,7 @@ def __init__( |
204 | 205 | h_initializer: Union[Initializer, Callable, Tensor] = OneInit(0.6), |
205 | 206 | n_initializer: Union[Initializer, Callable, Tensor] = OneInit(0.32), |
206 | 207 | method: str = 'exp_auto', |
| 208 | + keep_size: bool = False, |
207 | 209 | name: str = None |
208 | 210 | ): |
209 | 211 | # initialization |
@@ -287,6 +289,7 @@ def update(self, t, dt): |
287 | 289 | self.input[:] = 0. |
288 | 290 |
|
289 | 291 |
|
| 292 | + |
290 | 293 | class MorrisLecar(NeuGroup): |
291 | 294 | r"""The Morris-Lecar neuron model. |
292 | 295 |
|
@@ -383,6 +386,7 @@ def __init__( |
383 | 386 | W_initializer: Union[Callable, Initializer, Tensor] = OneInit(0.02), |
384 | 387 | V_initializer: Union[Callable, Initializer, Tensor] = Uniform(-70., -60.), |
385 | 388 | method: str = 'exp_auto', |
| 389 | + keep_size: bool = False, |
386 | 390 | name: str = None |
387 | 391 | ): |
388 | 392 | # initialization |
@@ -626,6 +630,7 @@ def __init__( |
626 | 630 | Ca_initializer: Union[Initializer, Callable, Tensor] = OneInit(0.2), |
627 | 631 | # others |
628 | 632 | method: str = 'exp_auto', |
| 633 | + keep_size: bool = False, |
629 | 634 | name: str = None, |
630 | 635 | ): |
631 | 636 | # initialization |
@@ -805,3 +810,185 @@ def inf_q(self, Ca): |
805 | 810 | alpha = self.alpha_q(Ca) |
806 | 811 | beta = self.beta_q(Ca) |
807 | 812 | return alpha / (alpha + beta) |
| 813 | + |
| 814 | + |
| 815 | +class WangBuzsakiModel(NeuGroup): |
| 816 | + r"""Wang-Buzsaki model [9]_, an implementation of a modified Hodgkin-Huxley model. |
| 817 | +
|
| 818 | + Each model is described by a single compartment and obeys the current balance equation: |
| 819 | +
|
| 820 | + .. math:: |
| 821 | +
|
| 822 | + C_{m} \frac{d V}{d t}=-I_{\mathrm{Na}}-I_{\mathrm{K}}-I_{\mathrm{L}}-I_{\mathrm{syn}}+I_{\mathrm{app}} |
| 823 | +
|
| 824 | + where :math:`C_{m}=1 \mu \mathrm{F} / \mathrm{cm}^{2}` and :math:`I_{\mathrm{app}}` is the |
| 825 | + injected current (in :math:`\mu \mathrm{A} / \mathrm{cm}^{2}` ). The leak current |
| 826 | + :math:`I_{\mathrm{L}}=g_{\mathrm{L}}\left(V-E_{\mathrm{L}}\right)` has a conductance |
| 827 | + :math:`g_{\mathrm{L}}=0.1 \mathrm{mS} / \mathrm{cm}^{2}`, so that the passive time constant |
| 828 | + :math:`\tau_{0}=C_{m} / g_{\mathrm{L}}=10 \mathrm{msec} ; E_{\mathrm{L}}=-65 \mathrm{mV}`. |
| 829 | +
|
| 830 | + The spike-generating :math:`\mathrm{Na}^{+}` and :math:`\mathrm{K}^{+}` voltage-dependent ion |
| 831 | + currents :math:`\left(I_{\mathrm{Na}}\right.` and :math:`I_{\mathrm{K}}` ) are of the |
| 832 | + Hodgkin-Huxley type (Hodgkin and Huxley, 1952). The transient sodium current |
| 833 | + :math:`I_{\mathrm{Na}}=g_{\mathrm{Na}} m_{\infty}^{3} h\left(V-E_{\mathrm{Na}}\right)`, |
| 834 | + where the activation variable :math:`m` is assumed fast and substituted by its steady-state |
| 835 | + function :math:`m_{\infty}=\alpha_{m} /\left(\alpha_{m}+\beta_{m}\right)` ; |
| 836 | + :math:`\alpha_{m}(V)=-0.1(V+35) /(\exp (-0.1(V+35))-1), \beta_{m}(V)=4 \exp (-(V+60) / 18)`. |
| 837 | + The inactivation variable :math:`h` obeys a first-order kinetics: |
| 838 | +
|
| 839 | + .. math:: |
| 840 | +
|
| 841 | + \frac{d h}{d t}=\phi\left(\alpha_{h}(1-h)-\beta_{h} h\right) |
| 842 | +
|
| 843 | + where :math:`\alpha_{h}(V)=0.07 \exp (-(V+58) / 20)` and |
| 844 | + :math:`\beta_{h}(V)=1 /(\exp (-0.1(V+28)) +1) \cdot g_{\mathrm{Na}}=35 \mathrm{mS} / \mathrm{cm}^{2}` ; |
| 845 | + :math:`E_{\mathrm{Na}}=55 \mathrm{mV}, \phi=5 .` |
| 846 | +
|
| 847 | + The delayed rectifier :math:`I_{\mathrm{K}}=g_{\mathrm{K}} n^{4}\left(V-E_{\mathrm{K}}\right)`, |
| 848 | + where the activation variable :math:`n` obeys the following equation: |
| 849 | +
|
| 850 | + .. math:: |
| 851 | +
|
| 852 | + \frac{d n}{d t}=\phi\left(\alpha_{n}(1-n)-\beta_{n} n\right) |
| 853 | +
|
| 854 | + with :math:`\alpha_{n}(V)=-0.01(V+34) /(\exp (-0.1(V+34))-1)` and |
| 855 | + :math:`\beta_{n}(V)=0.125\exp (-(V+44) / 80)` ; :math:`g_{\mathrm{K}}=9 \mathrm{mS} / \mathrm{cm}^{2}`, and |
| 856 | + :math:`E_{\mathrm{K}}=-90 \mathrm{mV}`. |
| 857 | +
|
| 858 | +
|
| 859 | + Parameters |
| 860 | + ---------- |
| 861 | + size: sequence of int, int |
| 862 | + The size of the neuron group. |
| 863 | + ENa: float, JaxArray, ndarray, Initializer, callable |
| 864 | + The reversal potential of sodium. Default is 50 mV. |
| 865 | + gNa: float, JaxArray, ndarray, Initializer, callable |
| 866 | + The maximum conductance of sodium channel. Default is 120 msiemens. |
| 867 | + EK: float, JaxArray, ndarray, Initializer, callable |
| 868 | + The reversal potential of potassium. Default is -77 mV. |
| 869 | + gK: float, JaxArray, ndarray, Initializer, callable |
| 870 | + The maximum conductance of potassium channel. Default is 36 msiemens. |
| 871 | + EL: float, JaxArray, ndarray, Initializer, callable |
| 872 | + The reversal potential of learky channel. Default is -54.387 mV. |
| 873 | + gL: float, JaxArray, ndarray, Initializer, callable |
| 874 | + The conductance of learky channel. Default is 0.03 msiemens. |
| 875 | + V_th: float, JaxArray, ndarray, Initializer, callable |
| 876 | + The threshold of the membrane spike. Default is 20 mV. |
| 877 | + C: float, JaxArray, ndarray, Initializer, callable |
| 878 | + The membrane capacitance. Default is 1 ufarad. |
| 879 | + phi: float, JaxArray, ndarray, Initializer, callable |
| 880 | + The temperature regulator constant. |
| 881 | + V_initializer: JaxArray, ndarray, Initializer, callable |
| 882 | + The initializer of membrane potential. |
| 883 | + h_initializer: JaxArray, ndarray, Initializer, callable |
| 884 | + The initializer of h channel. |
| 885 | + n_initializer: JaxArray, ndarray, Initializer, callable |
| 886 | + The initializer of n channel. |
| 887 | + method: str |
| 888 | + The numerical integration method. |
| 889 | + name: str |
| 890 | + The group name. |
| 891 | +
|
| 892 | + References |
| 893 | + ---------- |
| 894 | + .. [9] Wang, X.J. and Buzsaki, G., (1996) Gamma oscillation by synaptic |
| 895 | + inhibition in a hippocampal interneuronal network model. Journal of |
| 896 | + neuroscience, 16(20), pp.6402-6413. |
| 897 | +
|
| 898 | + """ |
| 899 | + |
| 900 | + def __init__( |
| 901 | + self, |
| 902 | + size: Shape, |
| 903 | + ENa: Union[float, Tensor, Initializer, Callable] = 55., |
| 904 | + gNa: Union[float, Tensor, Initializer, Callable] = 35., |
| 905 | + EK: Union[float, Tensor, Initializer, Callable] = -90., |
| 906 | + gK: Union[float, Tensor, Initializer, Callable] = 9., |
| 907 | + EL: Union[float, Tensor, Initializer, Callable] = -65, |
| 908 | + gL: Union[float, Tensor, Initializer, Callable] = 0.1, |
| 909 | + V_th: Union[float, Tensor, Initializer, Callable] = 20., |
| 910 | + phi: Union[float, Tensor, Initializer, Callable] = 5.0, |
| 911 | + C: Union[float, Tensor, Initializer, Callable] = 1.0, |
| 912 | + V_initializer: Union[Initializer, Callable, Tensor] = OneInit(-65.), |
| 913 | + h_initializer: Union[Initializer, Callable, Tensor] = OneInit(0.6), |
| 914 | + n_initializer: Union[Initializer, Callable, Tensor] = OneInit(0.32), |
| 915 | + method: str = 'exp_auto', |
| 916 | + keep_size: bool = False, |
| 917 | + name: str = None |
| 918 | + ): |
| 919 | + # initialization |
| 920 | + super(WangBuzsakiModel, self).__init__(size=size, name=name) |
| 921 | + |
| 922 | + # parameters |
| 923 | + self.ENa = init_param(ENa, self.num, allow_none=False) |
| 924 | + self.EK = init_param(EK, self.num, allow_none=False) |
| 925 | + self.EL = init_param(EL, self.num, allow_none=False) |
| 926 | + self.gNa = init_param(gNa, self.num, allow_none=False) |
| 927 | + self.gK = init_param(gK, self.num, allow_none=False) |
| 928 | + self.gL = init_param(gL, self.num, allow_none=False) |
| 929 | + self.C = init_param(C, self.num, allow_none=False) |
| 930 | + self.phi = init_param(phi, self.num, allow_none=False) |
| 931 | + self.V_th = init_param(V_th, self.num, allow_none=False) |
| 932 | + |
| 933 | + # initializers |
| 934 | + check_initializer(h_initializer, 'h_initializer', allow_none=False) |
| 935 | + check_initializer(n_initializer, 'n_initializer', allow_none=False) |
| 936 | + check_initializer(V_initializer, 'V_initializer', allow_none=False) |
| 937 | + self._h_initializer = h_initializer |
| 938 | + self._n_initializer = n_initializer |
| 939 | + self._V_initializer = V_initializer |
| 940 | + |
| 941 | + # variables |
| 942 | + self.h = bm.Variable(init_param(self._h_initializer, (self.num,))) |
| 943 | + self.n = bm.Variable(init_param(self._n_initializer, (self.num,))) |
| 944 | + self.V = bm.Variable(init_param(self._V_initializer, (self.num,))) |
| 945 | + self.input = bm.Variable(bm.zeros(self.num)) |
| 946 | + self.spike = bm.Variable(bm.zeros(self.num, dtype=bool)) |
| 947 | + |
| 948 | + # integral |
| 949 | + self.integral = odeint(method=method, f=self.derivative) |
| 950 | + |
| 951 | + def reset(self): |
| 952 | + self.h.value = init_param(self._h_initializer, (self.num,)) |
| 953 | + self.n.value = init_param(self._n_initializer, (self.num,)) |
| 954 | + self.V.value = init_param(self._V_initializer, (self.num,)) |
| 955 | + self.input[:] = 0 |
| 956 | + self.spike[:] = False |
| 957 | + |
| 958 | + def m_inf(self, V): |
| 959 | + alpha = -0.1 * (V + 35) / (bm.exp(-0.1 * (V + 35)) - 1) |
| 960 | + beta = 4. * bm.exp(-(V + 60.) / 18.) |
| 961 | + return alpha / (alpha + beta) |
| 962 | + |
| 963 | + def dh(self, h, t, V): |
| 964 | + alpha = 0.07 * bm.exp(-(V + 58) / 20) |
| 965 | + beta = 1 / (bm.exp(-0.1 * (V + 28)) + 1) |
| 966 | + dhdt = alpha * (1 - h) - beta * h |
| 967 | + return self.phi * dhdt |
| 968 | + |
| 969 | + def dn(self, n, t, V): |
| 970 | + alpha = -0.01 * (V + 34) / (bm.exp(-0.1 * (V + 34)) - 1) |
| 971 | + beta = 0.125 * bm.exp(-(V + 44) / 80) |
| 972 | + dndt = alpha * (1 - n) - beta * n |
| 973 | + return self.phi * dndt |
| 974 | + |
| 975 | + def dV(self, V, t, h, n, I_ext): |
| 976 | + INa = self.gNa * self.m_inf(V) ** 3 * h * (V - self.ENa) |
| 977 | + IK = self.gK * n ** 4 * (V - self.EK) |
| 978 | + IL = self.gL * (V - self.EL) |
| 979 | + dVdt = (- INa - IK - IL + I_ext) / self.C |
| 980 | + return dVdt |
| 981 | + |
| 982 | + @property |
| 983 | + def derivative(self): |
| 984 | + return JointEq([self.dV, self.dh, self.dn]) |
| 985 | + |
| 986 | + def update(self, t, dt): |
| 987 | + V, h, n = self.integral(self.V, self.h, self.n, t, self.input, dt=dt) |
| 988 | + self.spike.value = bm.logical_and(self.V < self.V_th, V >= self.V_th) |
| 989 | + self.V.value = V |
| 990 | + self.h.value = h |
| 991 | + self.n.value = n |
| 992 | + self.input[:] = 0. |
| 993 | + |
| 994 | + |
0 commit comments