m_generic_neuron_from_json.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. import pylab, os, json, sympy, scipy, sys
  2. from sympy import S, symbols, lambdify
  3. from scipy import integrate
  4. from scipy.integrate import odeint
  5. import numpy as np
  6. from copy import copy
  7. def load_mod(modfile,bp):
  8. ### Loads expressions from the json file
  9. nakdic = json.load(open(modfile))
  10. ### Auxiliary functions..
  11. fundic = dict([(j,k.split(":")[0]) for j,k in nakdic["functions"].items()])
  12. ### Definitions..
  13. defdic = dict([(j,k.split(":")[0]) for j,k in nakdic["definitions"].items()])
  14. ### Parameters
  15. pardic = dict([(j,k) for j,k in nakdic["parameters"].items()])
  16. ### Initial conditions
  17. icdic0 = [[j,k] for j,k in nakdic["init_states"].items()]
  18. icdic = [(i,str(S(str(S(str(S(str(S(j).subs(defdic))).subs(fundic))).subs(fundic))).subs(pardic))) for i,j in icdic0]
  19. ### parameters to be changed
  20. bifpar = [(k,pardic.pop(k)) for k in bp]
  21. ### Current expressions
  22. if 'currents' in nakdic.keys():
  23. currentlist1 = [[j,k] for j,k in nakdic['currents'].items()]
  24. currentlist = [(i,str(S(str(S(str(S(str(S(j).subs(defdic))).subs(fundic))).subs(fundic))).subs(pardic))) for i,j in currentlist1]
  25. if 'currents' not in nakdic.keys():
  26. currentlist={}
  27. ### SS Current expressions
  28. if 'ss_currents' in nakdic.keys():
  29. ss_currents1=[[j,k] for j,k in nakdic['ss_currents'].items()]
  30. ss_currents = [(i,str(S(str(S(str(S(str(S(j).subs(defdic))).subs(fundic))).subs(fundic))).subs(pardic))) for i,j in ss_currents1]
  31. if 'ss_currents' not in nakdic.keys():
  32. ss_currents={}
  33. ### Membrane potential expressions
  34. if 'resting_membrane_pot' in nakdic.keys():
  35. membpotlist1 = [[j,k] for j,k in nakdic['resting_membrane_pot'].items()]
  36. membpotlist = [(i,str(S(str(S(str(S(str(S(j).subs(defdic))).subs(fundic))).subs(fundic))).subs(pardic))) for i,j in membpotlist1]
  37. if 'resting_membrane_pot' not in nakdic.keys():
  38. membpotlist={}
  39. ### ODEs
  40. statevar_list = list(nakdic["init_states"].keys())
  41. time_derivative_list= ["d{}/dt".format(k) for k in statevar_list]
  42. sdelist=[]
  43. for ode in nakdic["ode"]:
  44. odestr= "({})-({})".format(*ode.split("="))
  45. odestr= odestr.replace(" ","")
  46. time_derivative= [k for k in time_derivative_list if k in odestr][0] # bad style
  47. state_variable= [k for k in statevar_list if k in time_derivative][0]
  48. ode_rhs= sympy.S(sympy.solve(odestr,time_derivative)[0]) # [0] is bad style
  49. sdelisti = [state_variable,str(S(str(S(str(S(str(S(ode_rhs).subs(defdic))).subs(fundic))).subs(fundic))).subs(pardic))]
  50. sdelist+=[sdelisti]
  51. ### Model Description
  52. if 'source' in nakdic.keys():
  53. s_description=nakdic['source']
  54. if 'source' not in nakdic.keys():
  55. s_description=''
  56. if "comments" in nakdic.keys():
  57. if "source" in nakdic['comments'].keys():
  58. s_description=nakdic['comments']['source']
  59. return sdelist, currentlist, membpotlist, s_description, icdic, pardic, ss_currents
  60. class generic_neuron_from_json():
  61. def __init__(self, s_name_model,dir_file=[],strIapp='I_app'):
  62. ### Creates a class generic_neuron_from_json() which contains all the expressions that describe the dynamics of [s_name_model]
  63. ## s_name_model= file name efample: 'MTM_W_PNAs_Temp_snapshot_constleak.json'
  64. ## dir_file= path of the file containning cfg/
  65. # For practival reasons I_app is always a parameter.. (to be used for stimulationg with time dependent function)
  66. bifpar={}
  67. if bifpar=={}:
  68. I_app=-5
  69. bifpar = {
  70. strIapp : [str(I_app)+"* uA/cm2"]
  71. }
  72. ## Definning location of file
  73. import os
  74. if dir_file==[]:
  75. p = {"modfile" : "cfg/" + s_name_model, #This the file of the model
  76. "workdir" : os.getcwd(),
  77. "bifpar" : bifpar
  78. }
  79. else:
  80. p = {"modfile" : "cfg/" + s_name_model, #This the file of the model
  81. "workdir" : os.getenv("HOME") + dir_file,
  82. "bifpar" : bifpar
  83. }
  84. ##### getting expressions for currents, membrane potentials and odes
  85. sde, currents, mem_pot, s_description, d_inicond, d_pars, ss_currents = load_mod(p["modfile"],p['bifpar'].keys())
  86. ##### Defining units as 1 to replace later (erase them..)
  87. baseunits2 = [('mV', 1), ('ms', 1),('second', 1), ('cm2', 1), ('cm3', 1), ('uF', 1), ('psiemens', 1), ('um2', 1), ('msiemens', 1), ('cm', 1), ('kelvin', 1), ('mM', 1), ('mol', 1), ('uA', 1), ('mjoule', 1), ('coulomb',1), ('ufarad',1)]
  88. ##### Replacing units for ones.. in the expressions..
  89. varrhs = [(i,sympy.S(j).subs(baseunits2))
  90. for i,j in sde]
  91. currwounits = [(i,sympy.S(j).subs(baseunits2))
  92. for i,j in currents]
  93. sscurrwounits = [(i,sympy.S(j).subs(baseunits2))
  94. for i,j in ss_currents]
  95. mempwounits = [(i,sympy.S(j).subs(baseunits2))
  96. for i,j in mem_pot]
  97. inicondwounits = [(i,sympy.S(j).subs(baseunits2))
  98. for i,j in d_inicond]
  99. #### Removing units from pars
  100. parslist = dict([(i,float(str(S(j).subs(baseunits2)))) for i,j in d_pars.items()])
  101. #### Separating definitions frpm expressions..
  102. if mempwounits==[]:
  103. s_mempot=[]
  104. mempotexp=[]
  105. if mempwounits!=[]:
  106. s_mempot,mempotexp = zip(*mempwounits)
  107. if currwounits==[]:
  108. s_curr=[]
  109. currexp=[]
  110. if currwounits!=[]:
  111. s_curr,currexp = zip(*currwounits)
  112. if sscurrwounits==[]:
  113. s_sscurr=[]
  114. sscurrexp=[]
  115. if sscurrwounits!=[]:
  116. s_sscurr,sscurrexp = zip(*sscurrwounits)
  117. s_svars,svarsexp = zip(*varrhs)
  118. self.s_pars=[j for j,k in bifpar.items()]
  119. self.svarsexp=svarsexp
  120. self.currexp=currexp
  121. self.sscurrexp=sscurrexp
  122. self.mempotexp=mempotexp
  123. self.baseunits=baseunits2
  124. self.s_model_tag=s_description
  125. self.s_model_reference_loc=p["workdir"]
  126. self.s_model_reference=p["modfile"]
  127. self.p = parslist
  128. self.n_state_vars=len(s_svars)
  129. self.s_state_vars=[j for j in s_svars]
  130. self.s_currents=[j for j in s_curr]
  131. self.s_sscurrents=[j for j in s_sscurr]
  132. self.s_concentrations=[]
  133. self.s_resting_membrane_potentials=[j for j in s_mempot]
  134. self.current_state=[float(dict(inicondwounits)[j]) for j in self.s_state_vars]
  135. self.ode_solver="odeint"
  136. self.noisy_current=[]
  137. for i_s in self.s_state_vars:
  138. if '_i' in i_s:
  139. self.s_concentrations.append(i_s)
  140. if '_o' in i_s:
  141. self.s_concentrations.append(i_s)
  142. def changing_pars(self,bifpar,pars4auto=False,strIapp='I_app'):
  143. ### Function that changes parameters (Only changes pars in the instance that calls it)
  144. ## bifpar= dictionary of parameters to be changed and their values
  145. if strIapp in bifpar:
  146. pass
  147. else:
  148. bifpar[strIapp]=[str(-5)+"* uA/cm2"]
  149. p = {"modfile" : self.s_model_reference, #"cfg/wangBuzsaki_brian.json", #This is our model
  150. "workdir" : self.s_model_reference_loc,
  151. "bifpar" : bifpar
  152. }
  153. ##### Recalculating expressions for currents, membrane potentials and odes
  154. sde, currents, mem_pot,s_description, d_inicond, d_pars, ss_currents = load_mod(p["modfile"],p['bifpar'].keys())
  155. baseunits2=self.baseunits
  156. ### Recalculating expressions
  157. bifpar2=dict([(j,k[0]) for j,k in bifpar.items()])
  158. if pars4auto:
  159. for i_p in bifpar.keys():
  160. bifpar2.pop(i_p, None)
  161. if strIapp in bifpar2:
  162. bifpar2.pop(strIapp, None)
  163. varrhs = [(i,sympy.S(str(sympy.S(j).subs(bifpar2))).subs(baseunits2))
  164. for i,j in sde]
  165. currwounits = [(i,sympy.S(str(sympy.S(j).subs(bifpar2))).subs(baseunits2))
  166. for i,j in currents]
  167. mempwounits = [(i,sympy.S(str(sympy.S(j).subs(bifpar2))).subs(baseunits2))
  168. for i,j in mem_pot]
  169. sscurrwounits=[(i,sympy.S(str(sympy.S(j).subs(bifpar2))).subs(baseunits2))
  170. for i,j in ss_currents]
  171. #### Separating definitions from expressions..
  172. if mempwounits==[]:
  173. s_mempot=[]
  174. mempotexp=[]
  175. if mempwounits!=[]:
  176. s_mempot,mempotexp = zip(*mempwounits)
  177. if currwounits==[]:
  178. s_curr=[]
  179. currexp=[]
  180. if currwounits!=[]:
  181. s_curr,currexp = zip(*currwounits)
  182. if sscurrwounits==[]:
  183. s_sscurr=[]
  184. sscurrexp=[]
  185. if sscurrwounits!=[]:
  186. s_sscurr,sscurrexp = zip(*sscurrwounits)
  187. s_svars,svarsexp = zip(*varrhs)
  188. #### adding I_app as par again.. so that instance it can be stimulated afterwards
  189. I_app=0
  190. bifpar_temp={}
  191. bifpar_temp= {
  192. strIapp : [str(I_app)+"* uA/cm2"]
  193. }
  194. #### Removing the annoying u before string
  195. s_pars=[j for j,k in bifpar_temp.items()]
  196. s_svars=[j for j in s_svars]
  197. s_curr=[j for j in s_curr]
  198. ## Adding the changed parameters to the parameters list again..
  199. for s_i,s_bi in bifpar2.items():
  200. d_pars[s_i]=s_bi
  201. ## Removing units again
  202. parslist = dict([(i,float(str(S(j).subs(baseunits2)))) for i,j in d_pars.items()])
  203. self.s_state_vars=s_svars
  204. self.s_pars=s_pars
  205. self.s_curr=s_curr
  206. self.mempotexp=mempotexp
  207. self.svarsexp=svarsexp
  208. self.currexp=currexp
  209. self.p = parslist
  210. def resting_membrane_potentials_fun(self):
  211. sym_svars=symbols(self.s_state_vars)
  212. fun_mempot=lambdify(sym_svars,self.mempotexp)
  213. return fun_mempot
  214. def neuron_currents_fun(self):
  215. sym_svars=symbols(self.s_state_vars)
  216. fun_currents = lambdify(sym_svars,self.currexp)
  217. return fun_currents
  218. def neuron_sscurrents_fun(self):
  219. sym_svars=symbols(self.s_state_vars)
  220. fun_sscurrents = lambdify(sym_svars,self.sscurrexp)
  221. return fun_sscurrents
  222. def neuron_changing_state_fun(self):
  223. # import pdb; pdb.set_trace()
  224. sym_spars=symbols(self.s_pars)
  225. sym_svars=symbols(self.s_state_vars)
  226. fun_ode =lambdify([i for i in sym_svars]+[i for i in sym_spars],self.svarsexp)
  227. return fun_ode
  228. def resting_membrane_potentials(self,v_State_Vars):
  229. fun_mempot=self.resting_membrane_potentials_fun()
  230. return fun_mempot(*v_State_Vars)
  231. def neuron_currents(self,v_State_Vars):
  232. fun_currents=self.neuron_currents_fun()
  233. return fun_currents(*v_State_Vars)
  234. def neuron_sscurrents(self,v):
  235. fun_sscurrents=self.neuron_sscurrents_fun()
  236. return fun_sscurrents(*[0,0,0,v])
  237. def neuron_changing_state(self,v_State_Vars,t,I_app,fun_ode):
  238. n_I=I_app(t)
  239. return fun_ode(* v_State_Vars.tolist()+[n_I])
  240. def stimulate_neuron(self,t,c_ini,I_stim):
  241. fun_ode=self.neuron_changing_state_fun()
  242. sol= odeint(self.neuron_changing_state, c_ini, t, args=(I_stim,fun_ode,))
  243. s_results=[]
  244. s_results=copy(self.s_state_vars)
  245. s_results.append("t")
  246. t_prov=t[...,None]
  247. v_results=np.append(sol,t_prov,1)
  248. return s_results, v_results
  249. ##### To call it neuron=generic_neuron_from_json('MTM_W_PNAs_Temp_snapshot_constleak'+'.json')