HodgkinHuxleyTutorial / Tutorial /Source /HodgkinHuxley.py
pgleeson's picture
Adding files from github
0558c72
Raw
History Blame Contribute Delete
14.3 kB
import scipy as sp
import numpy as np
import pylab as plt
from scipy.integrate import odeint
import sys
class HodgkinHuxley():
"""Full Hodgkin-Huxley Model implemented in Python"""
""" __init__ uses optional arguments """
""" when no argument is passed default values are used """
def __init__(self, C_m=1, gmax_Na=120, gmax_K=36, gmax_L=0.3, E_Na=50,
E_K=-77, E_L=-54.387, t_n=450, delta_t=0.01,
I_inj_amplitude=0, I_inj_duration=0, I_inj_delay=0,
vc_delay=10, vc_duration=30, vc_condVoltage=-65,
vc_testVoltage=10, vc_returnVoltage=-65, runMode='iclamp',
injected_current_plot=True, gating_plot=True, cond_scaling_plot=False,
cond_dens_plot=True, driving_force_plot=False,
current_plot=True, memb_pot_plot=True):
self.C_m = C_m
""" membrane capacitance, in uF/cm^2 """
self.gmax_Na = gmax_Na
""" Sodium (Na) maximum conductances, in mS/cm^2 """
self.gmax_K = gmax_K
""" Postassium (K) maximum conductances, in mS/cm^2 """
self.gmax_L = gmax_L
""" Leak maximum conductances, in mS/cm^2 """
self.E_Na = E_Na
""" Sodium (Na) Nernst reversal potentials, in mV """
self.E_K = E_K
""" Postassium (K) Nernst reversal potentials, in mV """
self.E_L = E_L
""" Leak Nernst reversal potentials, in mV """
self.t = np.arange(0, t_n, delta_t)
""" The time to integrate over """
""" Advanced input - injection current (single rectangular pulse only) """
self.I_inj_amplitude = I_inj_amplitude
""" maximum value or amplitude of injection pulse """
self.I_inj_duration = I_inj_duration
""" duration or width of injection pulse """
self.I_inj_delay = I_inj_delay
""" start time of injection pulse """
#vclamp parameters
self.run_mode = runMode
"""default is current clamp"""
self.delay = vc_delay
"""Delay before switching from conditioningVoltage to testingVoltage, in ms"""
self.duration = vc_duration
"""Duration to hold at testingVoltage, in ms"""
self.conditioningVoltage = vc_condVoltage
"""Target voltage before time delay, in mV"""
self.testingVoltage = vc_testVoltage
"""Target voltage between times delay and delay + duration, in mV"""
self.returnVoltage = vc_returnVoltage
"""Target voltage after time duration, in mV"""
self.simpleSeriesResistance = 1e7
"""Current will be calculated by the difference in voltage between the target and parent, divided by this value, in mOhm"""
# plotting conditionals
self.injected_current_plot = injected_current_plot
self.gating_plot = gating_plot
self.cond_scaling_plot = cond_scaling_plot
self.cond_dens_plot = cond_dens_plot
self.driving_force_plot = driving_force_plot
self.current_plot = current_plot
self.memb_pot_plot = memb_pot_plot
self.num_plots = (int(self.injected_current_plot) +
int(self.gating_plot)+ int(self.cond_scaling_plot) +
int(self.cond_dens_plot) + int(self.driving_force_plot) +
int(self.current_plot) + int(self.memb_pot_plot))
self.plot_count = 0
def alpha_m(self, V):
"""Channel gating kinetics. Functions of membrane voltage"""
return 0.1*(V+40.0)/(1.0 - np.exp(-(V+40.0) / 10.0))
def beta_m(self, V):
"""Channel gating kinetics. Functions of membrane voltage"""
return 4.0*np.exp(-(V+65.0) / 18.0)
def alpha_h(self, V):
"""Channel gating kinetics. Functions of membrane voltage"""
return 0.07*np.exp(-(V+65.0) / 20.0)
def beta_h(self, V):
"""Channel gating kinetics. Functions of membrane voltage"""
return 1.0/(1.0 + np.exp(-(V+35.0) / 10.0))
def alpha_n(self, V):
"""Channel gating kinetics. Functions of membrane voltage"""
return 0.01*(V+55.0)/(1.0 - np.exp(-(V+55.0) / 10.0))
def beta_n(self, V):
"""Channel gating kinetics. Functions of membrane voltage"""
return 0.125*np.exp(-(V+65) / 80.0)
def g_Na(self, m, h):
"""
Conductance density (in mS/cm^2)
Sodium (Na = element name)
| :param m:
| :param h:
| :return:
"""
return self.gmax_Na * m**3 * h
def I_Na(self, V, m, h):
"""
Membrane current (in uA/cm^2)
Sodium (Na = element name)
| :param V:
| :param m:
| :param h:
| :return:
"""
return self.g_Na(m, h) * (V - self.E_Na)
def g_K(self, n):
"""
Conductance density (in mS/cm^2)
Potassium (K = element name)
| :param n:
| :return:
"""
return self.gmax_K * n**4
def I_K(self, V, n):
"""
Membrane current (in uA/cm^2)
Potassium (K = element name)
| :param V:
| :param n:
| :return:
"""
return self.g_K(n) * (V - self.E_K)
# Leak
def I_L(self, V):
"""
Membrane current (in uA/cm^2)
Leak
| :param V:
| :param h:
| :return:
"""
return self.gmax_L * (V - self.E_L)
def I_inj(self, t):
"""
External Current
| :param t: time
| :return: step up to 10 uA/cm^2 at t>100
| step down to 0 uA/cm^2 at t>200
| step up to 35 uA/cm^2 at t>300
| step down to 0 uA/cm^2 at t>400
"""
""" running standalone python script """
if __name__ == '__main__':
return 10*(t>100) - 10*(t>200) + 35*(t>300) - 35*(t>400)
#""" running jupyterLab notebook """
else:
return self.I_inj_amplitude*(t>self.I_inj_delay) - self.I_inj_amplitude*(t>self.I_inj_delay+self.I_inj_duration)
def I_inj_vclamp(self,t,v):
"""
External Current (vclamp)
| :param t: time
| :return: injector current for voltage clamp
|
"""
if t > (self.delay + self.duration):
current_A = (self.returnVoltage - v) / self.simpleSeriesResistance
elif t >= self.delay:
current_A = (self.testingVoltage - v) / self.simpleSeriesResistance
elif t < self.delay:
current_A = (self.conditioningVoltage - v) / self.simpleSeriesResistance
else:
print('Problem in injection current calculation for voltage clamp...')
return 0
#convert current to current density (uA/cm^2)
current_uA = current_A*10**6 #convert ampere to micro ampere
surface_area = 1000*10**-8 #surface area of 1000 um^2 converted to cm^2
current_density = current_uA/surface_area
return current_density
@staticmethod
def dALLdt(X, t, self):
"""
Integrate
| :param X:
| :param t:
| :return: calculate membrane potential & activation variables
"""
V, m, h, n = X
if self.is_vclamp():
dVdt = (self.I_inj_vclamp(t,V) - self.I_Na(V, m, h) - self.I_K(V, n) - self.I_L(V)) / self.C_m
else:
dVdt = (self.I_inj(t) - self.I_Na(V, m, h) - self.I_K(V, n) - self.I_L(V)) / self.C_m
dmdt = self.alpha_m(V)*(1.0-m) - self.beta_m(V)*m
dhdt = self.alpha_h(V)*(1.0-h) - self.beta_h(V)*h
dndt = self.alpha_n(V)*(1.0-n) - self.beta_n(V)*n
return dVdt, dmdt, dhdt, dndt
def is_vclamp(self):
return self.run_mode=='vclamp' or self.run_mode=='Voltage Clamp'
def simulate(self, init_values=[-64.99584, 0.05296, 0.59590, 0.31773]):
"""
Main simulate method for the Hodgkin Huxley neuron model
"""
# init_values are the steady state values for v,m,h,n at zero current injection
X = odeint(self.dALLdt, init_values, self.t, args=(self,))
V = X[:,0]
m = X[:,1]
h = X[:,2]
n = X[:,3]
ina = self.I_Na(V, m, h)
ik = self.I_K(V, n)
il = self.I_L(V)
gna = self.g_Na(m, h)
gk = self.g_K(n)
# Save some of the data to file
with open('hh_py_v.dat','w') as f:
for ti in range(len(self.t)):
f.write('%s\t%s\n'%(self.t[ti],V[ti]))
if not '-nogui' in sys.argv:
#increase figure and font size for display in jupyter notebook
if __name__ != '__main__':
plt.rcParams['figure.figsize'] = [7, 7]
#plt.rcParams['font.size'] = 15
#plt.rcParams['legend.fontsize'] = 12
plt.rcParams['legend.loc'] = "upper right"
#
else:
plt.rcParams['figure.figsize'] = [10, 7]
plt.close()
fig=plt.figure(figsize=(7, self.num_plots * 2))
fig.canvas.header_visible = False
# plt.xlim([np.min(self.t),np.max(self.t)]) #for all subplots
if self.injected_current_plot:
ax1 = plt.subplot(self.num_plots,1,self.plot_count + 1)
plt.title('Simulation of Hodgkin Huxley model neuron')
if self.is_vclamp():
i_inj_values = [self.I_inj_vclamp(t,v) for t,v in zip(self.t,V)]
else:
i_inj_values = [self.I_inj(t) for t in self.t]
if self.is_vclamp(): plt.ylim(-2000,3000)
plt.plot(self.t, i_inj_values, 'k')
plt.ylabel('$I_{inj}$ ($\\mu{A}/cm^2$)')
self.plot_count += 1
if self.gating_plot:
try:
plt.subplot(self.num_plots,1,self.plot_count+1, sharex = ax1)
except NameError:
ax1 = plt.subplot(self.num_plots,1,self.plot_count + 1)
plt.title('Simulation of Hodgkin Huxley model neuron')
plt.plot(self.t, m, 'r', label='$m$')
plt.plot(self.t, h, 'g', label='$h$')
plt.plot(self.t, n, 'b', label='$n$')
plt.ylabel('Gating variable')
plt.legend()
self.plot_count += 1
if self.cond_scaling_plot:
try:
plt.subplot(self.num_plots,1,self.plot_count+1, sharex = ax1)
except NameError:
ax1 = plt.subplot(self.num_plots,1,self.plot_count + 1)
plt.title('Simulation of Hodgkin Huxley model neuron')
scale_na = m*m*m*h
scale_k = n*n*n*n
plt.plot(self.t, scale_na, 'c', label='$m^{3}h$')
plt.plot(self.t, scale_k, 'y', label='$n^{4}$')
plt.ylabel('Cond scaling')
plt.legend()
self.plot_count += 1
if self.cond_dens_plot:
try:
plt.subplot(self.num_plots,1,self.plot_count+1, sharex = ax1)
except NameError:
ax1 = plt.subplot(self.num_plots,1,self.plot_count + 1)
plt.title('Simulation of Hodgkin Huxley model neuron')
plt.plot(self.t, gna, 'c', label='$g_{Na}$')
plt.plot(self.t, gk, 'y', label='$g_{K}$')
plt.ylabel('Cond dens ($mS/cm^2$)')
plt.legend()
self.plot_count += 1
if self.driving_force_plot:
try:
ax_here = plt.subplot(self.num_plots,1,self.plot_count+1, sharex = ax1)
except NameError:
ax1 = plt.subplot(self.num_plots,1,self.plot_count + 1)
plt.title('Simulation of Hodgkin Huxley model neuron')
ax_here = ax1
dna = V - self.E_Na
dk = V - self.E_K
zero = [0 for v in V]
#plt.plot(self.t, dna, 'c', label='$V - E_{Na}$')
ax_here.fill_between(self.t, dna, color='c', alpha=0.5)
ax_here.fill_between(self.t, dk, color='y', alpha=0.5)
plt.plot(self.t, dna, 'c', label='$V_{m} - E_{Na}$', linewidth=0.8)
plt.plot(self.t, dk, 'y', label='$V_{m} - E_{K}$', linewidth=0.8)
plt.plot(self.t, zero, 'k', linestyle='dashed', linewidth=0.5)
plt.ylabel('Driving force (mV)')
plt.legend()
#if not self.is_vclamp(): plt.ylim(-85,60)
#plt.ylim(-1, 40)
self.plot_count += 1
if self.current_plot:
try:
plt.subplot(self.num_plots,1,self.plot_count+1, sharex = ax1)
except NameError:
ax1 = plt.subplot(self.num_plots,1,self.plot_count + 1)
plt.title('Simulation of Hodgkin Huxley model neuron')
plt.plot(self.t, ina, 'c', label='$I_{Na}$')
plt.plot(self.t, ik, 'y', label='$I_{K}$')
plt.plot(self.t, il, 'm', label='$I_{L}$')
plt.ylabel('Curr dens ($\\mu{A}/cm^2$)')
plt.legend()
self.plot_count += 1
if self.memb_pot_plot:
try:
plt.subplot(self.num_plots,1,self.plot_count+1, sharex = ax1)
except NameError:
ax1 = plt.subplot(self.num_plots,1,self.plot_count + 1)
plt.title('Simulation of Hodgkin Huxley model neuron')
plt.plot(self.t, V, 'k')
plt.ylabel('$V_{m}$ (mV)')
plt.xlabel('Time (ms)')
if not self.is_vclamp(): plt.ylim(-85,60)
#plt.ylim(-1, 40)
self.plot_count += 1
plt.tight_layout()
plt.show()
if __name__ == '__main__':
if '-vclamp' in sys.argv:
runner = HodgkinHuxley(runMode='vclamp', t_n=50, delta_t=0.0005)
else: #default mode
runner = HodgkinHuxley(runMode='iclamp', t_n=450, delta_t=0.01)
runner.simulate()