OSCR

Linking functional and structural dendritic spine remodeling during fear learning and extinction in vivo.

Code ↔ Paper

2 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 2 matches
  1. [1] § MATERIALS AND METHODS › Simulation of the biophysically detailed neural network model › Basic setting of the simulation ↔ orig/netParams.py, lines 872–937 · score 0.57 · NetPyNE, cell models, Python, cortical, PV, spike
  2. [2] § MATERIALS AND METHODS › Simulation of the biophysically detailed neural network model › Basic setting of the simulation ↔ seed_search/netParams.py, lines 868–933 · score 0.57 · NetPyNE, cell models, Python, cortical, PV, spike

Paper

Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

Python · 937 lines · 50 KB · no license · 1 match

  1. """
  2. netParams.py
  3. High-level specifications for M1 network model using NetPyNE
  4. Contributors: [email hidden]
  5. """
  6. from netpyne import specs, sim
  7. from neuron import h
  8. import pickle, json
  9. import random
  10. import numpy as np
  11. import math
  12. import os
  13. netParams = specs.NetParams() # object of class NetParams to store the network parameters
  14. netParams.version = 56
  15. try:
  16. from __main__ import cfg # import SimConfig object with params from parent module
  17. except:
  18. from cfg import cfg
  19. num_PT = 20
  20. num_PV = 10
  21. num_SOM = 10
  22. num_dict = {'PT': num_PT, 'PV': num_PV, 'SOM': num_SOM}
  23. seclist = {'PT': {'dend':[], 'all':[]}, 'PV': [], 'SOM': []} #'all' except axon
  24. #------------------------------------------------------------------------------
  25. #
  26. # Random sequence generation
  27. #
  28. #------------------------------------------------------------------------------
  29. class RandomSequenceNetParams:
  30. def __init__(self):
  31. self.randomlist = None
  32. def initializeRandomSequence(self, simConfig):
  33. from mpi4py import MPI
  34. comm = MPI.COMM_WORLD
  35. rank = comm.Get_rank()
  36. # Set random seeds consistently across nodes
  37. sd = 255
  38. random.seed(sd)
  39. if rank == 0:
  40. print(f'Using {sd} -- random seed for connection generation')
  41. # Initialize the randomlist structure based on population parameters
  42. self.randomlist = {
  43. 'EI': {k: [[[] for _ in range(num_PT)]
  44. for _ in range(num_dict[k])]
  45. for k in ['PV', 'SOM']},
  46. 'PVE': [[{'soma': []} for _ in range(num_dict['PV'])]
  47. for _ in range(num_PT)],
  48. 'SOME': [[{s: [] for s in ['Adend1', 'Adend2', 'Adend3', 'Bdend']}
  49. for _ in range(num_dict['SOM'])]
  50. for _ in range(num_PT)],
  51. 'II': {posttype: { pretype: [[[] for _ in range(num_dict[pretype] - 1 if pretype == posttype
  52. else num_dict[pretype])]
  53. for _ in range(num_dict[posttype])]
  54. for pretype in ['PV', 'SOM']}
  55. for posttype in ['PV', 'SOM']},
  56. 'LongE': {k: {sec: [[[] for _ in range(numCells_long)]
  57. for _ in range(num_PT)]
  58. for sec in ['Adend1', 'Adend2', 'Adend3', 'Bdend']}
  59. for k in ['S1_4K', 'S1_12K', 'OC']}
  60. }
  61. if rank == 0: # Only generate on master node
  62. # Generate weights and locations
  63. weights, seglocs = self._generate_random_values()
  64. # Process connections
  65. self._process_all_connections(weights, seglocs)
  66. # Broadcast fram rank 0 to all other ranks
  67. self.randomlist = comm.bcast(self.randomlist, root=0)
  68. def _generate_random_values(self):
  69. weights = {}
  70. seglocs = {}
  71. # Generate weights for each postsynaptic neuron (ipost)
  72. for celltype in ['PT', 'PV', 'SOM']:
  73. weights[celltype] = {}
  74. seglocs[celltype] = self._create_segment_locations(celltype)
  75. if celltype == 'PT':
  76. # For PT cells, generate weights for each compartment
  77. weights[celltype]['soma'] = []
  78. for ipost in range(num_PT):
  79. # Sample weights for this ipost
  80. weights[celltype]['soma'].append(
  81. self.sample_custom_distribution(
  82. self._calculate_total_synapses(celltype)['axosomatic'] // num_PT,
  83. 0.4, 3, 15
  84. )
  85. )
  86. for sec in seclist['PT']['dend']:
  87. weights[celltype][sec] = []
  88. for ipost in range(num_PT):
  89. weights[celltype][sec].append(
  90. self.sample_custom_distribution(
  91. self._calculate_total_synapses(celltype)['axodendritic'][sec] // num_PT,
  92. 0.4, 3, 15
  93. )
  94. )
  95. else:
  96. weights[celltype] = []
  97. for ipost in range(num_dict[celltype]):
  98. weights[celltype].append(
  99. self.sample_custom_distribution(
  100. self._calculate_total_synapses(celltype)['axosomatic'] // num_dict[celltype],
  101. 0.4, 3, 15
  102. )
  103. )
  104. return weights, seglocs
  105. def sample_custom_distribution(self, n_samples, prob, weight_threshold, maxweight=1.0):
  106. # Generate random numbers from a uniform distribution
  107. u = [random.uniform(0, 1) for _ in range(n_samples)]
  108. # Allocate samples as a list of zeros
  109. samples = [0.0] * n_samples
  110. for i, ui in enumerate(u):
  111. if ui <= prob: # prob in [0, weight]
  112. samples[i] = weight_threshold * (ui / prob) # Scale uniformly in [0, weight]
  113. else: # 1-prob in (weight, 1]
  114. samples[i] = weight_threshold + (ui - prob) * (maxweight-weight_threshold) / (1-prob) # Scale uniformly in (weight, 1]
  115. return samples
  116. def _calculate_total_synapses(self, celltype):
  117. # Calculate based on connection rules and population sizes
  118. total = {'axosomatic':0, 'axodendritic':{k: 0 for k in seclist['PT']['dend']}}
  119. if celltype == 'PT':
  120. total['axosomatic'] = (num_PT *
  121. num_PV) # PVE connections
  122. for sec in seclist['PT']['dend']:
  123. total['axodendritic'][sec] += math.ceil(nseg['PT'][sec]/numCells_long) * numCells_long * num_PT * 3 # LongE connections (3 types)
  124. total['axodendritic'][sec] += (num_PT *
  125. num_SOM) # SOME connections
  126. else: # PV or SOM
  127. total['axosomatic'] += (num_dict[celltype] *
  128. num_PT) # EI connections
  129. total['axosomatic'] += (num_dict[celltype] *
  130. (num_PV +
  131. num_SOM - 1)) # II connections
  132. return total
  133. def _create_segment_locations(self, celltype):
  134. seglocs = {}
  135. if celltype == 'PT':
  136. # For PT cells, generate segment locations for each compartment
  137. for sec in seclist['PT']['all']:
  138. seglocs[sec] = []
  139. for ipost in range(num_PT):
  140. # Generate segment locations for this ipost
  141. seglocs[sec].append(
  142. [1 / (2 * nseg[celltype][sec]) + i * 1 / nseg[celltype][sec]
  143. for i in range(math.ceil(nseg[celltype][sec]))]
  144. )
  145. if sec == 'soma':
  146. k = self._calculate_total_synapses(celltype)['axosomatic'] // num_PT - math.ceil(nseg[celltype][sec])
  147. else:
  148. k = self._calculate_total_synapses(celltype)['axodendritic'][sec] // num_PT - math.ceil(nseg[celltype][sec])
  149. seglocs[sec][ipost].extend(random.choices(seglocs[sec][ipost], k = k))
  150. random.shuffle(seglocs[sec][ipost])
  151. else:
  152. # For PV and SOM cells, generate segment locations for each ipost
  153. seglocs = []
  154. for ipost in range(num_dict[celltype]):
  155. seglocs.append(
  156. [1 / (2 * nseg[celltype]['soma']) + i * 1 / nseg[celltype]['soma']
  157. for i in range(math.ceil(nseg[celltype]['soma']))]
  158. )
  159. seglocs[ipost].extend(
  160. random.choices(seglocs[ipost],
  161. k=self._calculate_total_synapses(celltype)['axosomatic'] // num_dict[celltype] - math.ceil(nseg[celltype]['soma']))
  162. )
  163. random.shuffle(seglocs[ipost])
  164. return seglocs
  165. def _process_all_connections(self, weights, seglocs):
  166. for conntype in self.randomlist.keys():
  167. self._process_connections(conntype, weights, seglocs)
  168. def _process_connections(self, conntype, weights, seglocs):
  169. if conntype == 'LongE':
  170. synsperconn = {}
  171. for sec in seclist['PT']['all']:
  172. synsperconn[sec] = math.ceil(nseg['PT'][sec]/numCells_long)
  173. for ipost in range(num_PT):
  174. for pretype in ['S1_4K', 'S1_12K', 'OC']:
  175. for ipre in range(numCells_long):
  176. self._process_single_connection(conntype, 'PT', pretype,
  177. ipost, ipre, weights, seglocs, synsperconn)
  178. elif conntype in ['PVE', 'SOME']:
  179. if conntype == 'PVE':
  180. pretype = 'PV'
  181. else:
  182. pretype = 'SOM'
  183. for ipost in range(num_PT):
  184. for ipre in range(num_dict[pretype]):
  185. self._process_single_connection(conntype, 'PT', pretype,
  186. ipost, ipre, weights, seglocs, 1)
  187. elif conntype == 'EI':
  188. for posttype in ['PV', 'SOM']:
  189. for ipost in range(num_dict[posttype]):
  190. for ipre in range(num_PT):
  191. self._process_single_connection(conntype, posttype, None,
  192. ipost, ipre, weights, seglocs, 1)
  193. elif conntype == 'II':
  194. for posttype in ['PV', 'SOM']:
  195. for pretype in ['PV', 'SOM']:
  196. num_cells = num_dict[pretype]
  197. for ipost in range(num_dict[posttype]):
  198. for ipre in range(num_cells - (1 if posttype == pretype else 0)):
  199. self._process_single_connection(conntype, posttype, pretype,
  200. ipost, ipre, weights, seglocs, 1)
  201. def _process_single_connection(self, conntype, posttype, pretype, ipost, ipre, weights, seglocs, synsperconn):
  202. if posttype == 'PT':
  203. selected_weights = {}
  204. selected_locs = {}
  205. if conntype == 'LongE':
  206. for sec in seclist['PT']['dend']:
  207. selected_weights[sec] = [weights[posttype][sec][ipost].pop() for _ in range(synsperconn[sec])]
  208. selected_locs[sec] = [seglocs[posttype][sec][ipost].pop() for _ in range(synsperconn[sec])]
  209. else:
  210. if pretype == 'PV':
  211. selected_weights['soma'] = [weights[posttype]['soma'][ipost].pop() for _ in range(synsperconn)]
  212. selected_locs['soma'] = [seglocs[posttype]['soma'][ipost].pop() for _ in range(synsperconn)]
  213. else:
  214. for sec in seclist['PT']['dend']:
  215. selected_weights[sec] = [weights[posttype][sec][ipost].pop() for _ in range(synsperconn)]
  216. selected_locs[sec] = [seglocs[posttype][sec][ipost].pop() for _ in range(synsperconn)]
  217. else:
  218. selected_weights = [weights[posttype][ipost].pop() for _ in range(synsperconn)]
  219. selected_locs = [seglocs[posttype][ipost].pop() for _ in range(synsperconn)]
  220. # Store the weights and locations in randomlist
  221. if conntype == 'II':
  222. self.randomlist[conntype][posttype][pretype][ipost][ipre] = list(zip(selected_locs, selected_weights))
  223. elif conntype == 'EI':
  224. self.randomlist[conntype][posttype][ipost][ipre] = list(zip(selected_locs, selected_weights))
  225. elif conntype == 'LongE':
  226. for sec in seclist['PT']['dend']:
  227. self.randomlist[conntype][pretype][sec][ipost][ipre] = list(zip(selected_locs[sec], selected_weights[sec]))
  228. else:
  229. if pretype == 'SOM':
  230. for sec in seclist['PT']['dend']:
  231. self.randomlist[conntype][ipost][ipre][sec] = list(zip(selected_locs[sec], selected_weights[sec]))
  232. else:
  233. self.randomlist[conntype][ipost][ipre]['soma'] = list(zip(selected_locs['soma'], selected_weights['soma']))
  234. #------------------------------------------------------------------------------
  235. #
  236. # NETWORK PARAMETERS
  237. #
  238. #------------------------------------------------------------------------------
  239. #------------------------------------------------------------------------------
  240. # General network parameters
  241. #------------------------------------------------------------------------------
  242. netParams.scale = cfg.scale # Scale factor for number of cells
  243. netParams.sizeX = cfg.sizeX # x-dimension (horizontal length) size in um
  244. netParams.sizeY = cfg.sizeY # y-dimension (vertical height or cortical depth) size in um
  245. netParams.sizeZ = cfg.sizeZ # z-dimension (horizontal depth) size in um
  246. netParams.shape = 'cylinder' # cylindrical (column-like) volume
  247. #------------------------------------------------------------------------------
  248. # General connectivity parameters
  249. #------------------------------------------------------------------------------
  250. netParams.scaleConnWeight = 1.0 # Connection weight scale factor (default if no model specified)
  251. #netParams.scaleConnWeightModels = {'HH_full': 1.0} #scale conn weight factor for each cell model
  252. #netParams.scaleConnWeightNetStims = 1.0 #0.5 # scale conn weight factor for NetStims
  253. netParams.defaultThreshold = -5.0 # spike threshold, 10 mV is NetCon default, lower it for all cells
  254. netParams.defaultDelay = 2.0 # default conn delay (ms)
  255. netParams.propVelocity = 500.0 # propagation velocity (um/ms)
  256. netParams.probLambda = 100.0 # length constant (lambda) for connection probability decay (um)
  257. netParams.defineCellShapes = True # convert stylized geoms to 3d points
  258. # special condition to change Kgbar together with ih when running batch
  259. # note min Kgbar is assumed to be 0.5, so this is set here as an offset
  260. #if cfg.makeKgbarFactorEqualToNewFactor:
  261. # cfg.KgbarFactor = 0.5 + cfg.modifyMechs['newFactor']
  262. #------------------------------------------------------------------------------
  263. # Cell parameters
  264. #------------------------------------------------------------------------------
  265. #cellModels = ['HH_full']
  266. cellModels = ['HH_reduced']
  267. layer = {'1':[0.0, 0.1],'5B': [0.47,0.8],'longS1_4K': [2.2,2.3],'longS1_12K': [2.2,2.3], 'longOC': [2.2,2.3]} # normalized layer boundaries
  268. netParams.correctBorder = {'threshold': [cfg.correctBorderThreshold, cfg.correctBorderThreshold, cfg.correctBorderThreshold],
  269. 'yborders': [layer['1'][0], layer['5B'][0], layer['5B'][1]]} # correct conn border effect
  270. #------------------------------------------------------------------------------
  271. ## Load cell rules previously saved using netpyne format
  272. cellParamLabels = ['PV_simple', 'SOM_simple', 'PT5B_reduced']# ['VIP_reduced', 'NGF_simple','PT5B_full'] # # list of cell rules to load from file
  273. loadCellParams = cellParamLabels
  274. saveCellParams = False #True
  275. for ruleLabel in loadCellParams:
  276. netParams.loadCellParamsRule(label=ruleLabel, fileName='cells/'+ruleLabel+'_cellParams.pkl')
  277. # Adapt K gbar
  278. if ruleLabel in ['IT2_reduced', 'IT4_reduced', 'IT5A_reduced', 'IT5B_reduced', 'IT6_reduced', 'CT6_reduced', 'IT5A_full']:
  279. cellRule = netParams.cellParams[ruleLabel]
  280. for secName in cellRule['secs']:
  281. for kmech in [k for k in cellRule['secs'][secName]['mechs'].keys() if k.startswith('k') and k!='kBK']:
  282. cellRule['secs'][secName]['mechs'][kmech]['gbar'] *= cfg.KgbarFactor
  283. if ruleLabel in ['PT5B_reduced']:
  284. cellRule = netParams.cellParams[ruleLabel]
  285. seclist['PT']['dend'] = cellRule['secLists']['alldend']
  286. seclist['PT']['all'] = [sec for sec in cellRule['secs'] if sec not in ['axon']]
  287. secL_PT = {k: 0.0 for k in cellRule['secs']}
  288. for secName in cellRule['secs']:
  289. #cellRule['secs'][secName]['geom']['L'] = 5
  290. secL_PT[secName] = cellRule['secs'][secName]['geom']['L']
  291. cellRule['secs'][secName]['geom']['nseg'] = math.floor(cellRule['secs'][secName]['geom']['L'])
  292. cellRule['secs'][secName]['weightNorm'] = None
  293. elif ruleLabel in ['PV_simple']:
  294. cellRule = netParams.cellParams[ruleLabel]
  295. secL_PV = {'soma': 0.0, 'dend': 0.0, 'axon': 0.0}
  296. for secName in cellRule['secs']:
  297. #cellRule['secs'][secName]['geom']['L'] = 5
  298. secL_PV[secName] = cellRule['secs'][secName]['geom']['L']
  299. cellRule['secs'][secName]['geom']['nseg'] = math.floor(cellRule['secs'][secName]['geom']['L'])
  300. cellRule['secs'][secName]['weightNorm'] = None
  301. elif ruleLabel in ['SOM_simple']:
  302. cellRule = netParams.cellParams[ruleLabel]
  303. secL_SOM = {'soma': 0.0, 'dend': 0.0, 'axon': 0.0}
  304. for secName in cellRule['secs']:
  305. #cellRule['secs'][secName]['geom']['L'] = 5
  306. secL_SOM[secName] = cellRule['secs'][secName]['geom']['L']
  307. cellRule['secs'][secName]['geom']['nseg'] = math.floor(cellRule['secs'][secName]['geom']['L'])
  308. cellRule['secs'][secName]['weightNorm'] = None
  309. #print('sec length:', secL_PT, secL_PV, secL_SOM)
  310. #------------------------------------------------------------------------------
  311. ## PT5B full cell model params (700+ comps)
  312. if 'PT5B_full' not in loadCellParams:
  313. ihMod2str = {'harnett': 1, 'kole': 2, 'migliore': 3}
  314. cellRule = netParams.importCellParams(label='PT5B_full', conds={'cellType': 'PT', 'cellModel': 'HH_full'},
  315. fileName='cells/PTcell.hoc', cellName='PTcell', cellArgs=[ihMod2str[cfg.ihModel], cfg.ihSlope], somaAtOrigin=True)
  316. nonSpiny = ['apic_0', 'apic_1']
  317. netParams.addCellParamsSecList(label='PT5B_full', secListName='perisom', somaDist=[0, 50]) # sections within 50 um of soma
  318. netParams.addCellParamsSecList(label='PT5B_full', secListName='below_soma', somaDistY=[-600, 0]) # sections within 0-300 um of soma
  319. for sec in nonSpiny: cellRule['secLists']['perisom'].remove(sec)
  320. cellRule['secLists']['alldend'] = [sec for sec in cellRule.secs if ('dend' in sec or 'apic' in sec)] # basal+apical
  321. cellRule['secLists']['apicdend'] = [sec for sec in cellRule.secs if ('apic' in sec)] # apical
  322. cellRule['secLists']['spiny'] = [sec for sec in cellRule['secLists']['alldend'] if sec not in nonSpiny]
  323. # Adapt ih params based on cfg param
  324. for secName in cellRule['secs']:
  325. for mechName,mech in cellRule['secs'][secName]['mechs'].items():
  326. if mechName in ['ih','h','h15', 'hd']:
  327. mech['gbar'] = [g*cfg.ihGbar for g in mech['gbar']] if isinstance(mech['gbar'],list) else mech['gbar']*cfg.ihGbar
  328. if cfg.ihModel == 'migliore':
  329. mech['clk'] = cfg.ihlkc # migliore's shunt current factor
  330. mech['elk'] = cfg.ihlke # migliore's shunt current reversal potential
  331. if secName.startswith('dend'):
  332. mech['gbar'] *= cfg.ihGbarBasal # modify ih conductance in soma+basal dendrites
  333. mech['clk'] *= cfg.ihlkcBasal # modify ih conductance in soma+basal dendrites
  334. if secName in cellRule['secLists']['below_soma']: #secName.startswith('dend'):
  335. mech['clk'] *= cfg.ihlkcBelowSoma # modify ih conductance in soma+basal dendrites
  336. # Adapt K gbar
  337. for kmech in [k for k in cellRule['secs'][secName]['mechs'].keys() if k.startswith('k') and k!='kBK']:
  338. cellRule['secs'][secName]['mechs'][kmech]['gbar'] *= cfg.KgbarFactor
  339. # NOT Reduce dend Na to HAVE dend spikes
  340. for secName in cellRule['secLists']['alldend']:
  341. cellRule['secs'][secName]['mechs']['nax']['gbar'] = 0.0153130368342 * cfg.dendNa # 1
  342. cellRule['secs']['soma']['mechs']['nax']['gbar'] = 0.0153130368342 * cfg.somaNa # 5
  343. cellRule['secs']['axon']['mechs']['nax']['gbar'] = 0.0153130368342 * cfg.axonNa # 5
  344. cellRule['secs']['axon']['geom']['Ra'] = 137.494564931 * cfg.axonRa # 0.005
  345. # Remove Na (TTX)
  346. if cfg.removeNa:
  347. for secName in cellRule['secs']: cellRule['secs'][secName]['mechs']['nax']['gbar'] = 0.0
  348. #netParams.addCellParamsWeightNorm('PT5B_full', 'conn/PT5B_full_weightNorm.pkl', threshold=cfg.weightNormThreshold) # load weight norm
  349. if saveCellParams: netParams.saveCellParamsRule(label='PT5B_full', fileName='cells/PT5B_full_cellParams.pkl')
  350. #------------------------------------------------------------------------------
  351. # Reduced cell model params (6-comp)
  352. reducedCells = { # layer and cell type for reduced cell models
  353. #'PT5B_reduced': {'layer': '5B', 'cname': 'SPI6', 'carg': None}
  354. }
  355. reducedSecList = { # section Lists for reduced cell model
  356. 'alldend': ['Adend1', 'Adend2', 'Adend3', 'Bdend'],
  357. 'spiny': ['Adend1', 'Adend2', 'Adend3', 'Bdend'],
  358. 'apicdend': ['Adend1', 'Adend2', 'Adend3'],
  359. 'perisom': ['soma']}
  360. for label, p in reducedCells.items(): # create cell rules that were not loaded
  361. if label not in loadCellParams:
  362. cellRule = netParams.importCellParams(label=label, conds={'cellType': label[0], 'cellModel': 'HH_reduced', 'ynorm': layer[p['layer']]},
  363. fileName='cells/'+p['cname']+'.py', cellName=p['cname'], cellArgs={'params': p['carg']} if p['carg'] else None)
  364. dendL = (layer[p['layer']][0]+(layer[p['layer']][1]-layer[p['layer']][0])/2.0) * cfg.sizeY # adapt dend L based on layer
  365. for secName in ['Adend1', 'Adend2', 'Adend3', 'Bdend']:
  366. cellRule['secs'][secName]['geom']['L'] = dendL / 3.0
  367. for k,v in reducedSecList.items(): cellRule['secLists'][k] = v # add secLists
  368. netParams.addCellParamsWeightNorm('PT5B_reduced', 'conn/'+'PT5B_reduced'+'_weightNorm.pkl', threshold=cfg.weightNormThreshold) # add weightNorm
  369. if saveCellParams: netParams.saveCellParamsRule(label='PT5B_reduced', fileName='cells/'+'PT5B_reduced'+'_cellParams.pkl')
  370. # set 3d points
  371. offset, prevL = 0, 0
  372. somaL = netParams.cellParams[label]['secs']['soma']['geom']['L']
  373. for secName, sec in netParams.cellParams[label]['secs'].items():
  374. sec['geom']['pt3d'] = []
  375. if secName in ['soma', 'Adend1', 'Adend2', 'Adend3']: # set 3d geom of soma and Adends
  376. sec['geom']['pt3d'].append([offset+0, prevL, 0, sec['geom']['diam']])
  377. prevL = float(prevL + sec['geom']['L'])
  378. sec['geom']['pt3d'].append([offset+0, prevL, 0, sec['geom']['diam']])
  379. if secName in ['Bdend']: # set 3d geom of Bdend
  380. sec['geom']['pt3d'].append([offset+0, somaL, 0, sec['geom']['diam']])
  381. sec['geom']['pt3d'].append([offset+sec['geom']['L'], somaL, 0, sec['geom']['diam']])
  382. if secName in ['axon']: # set 3d geom of axon
  383. sec['geom']['pt3d'].append([offset+0, 0, 0, sec['geom']['diam']])
  384. sec['geom']['pt3d'].append([offset+0, -sec['geom']['L'], 0, sec['geom']['diam']])
  385. #------------------------------------------------------------------------------
  386. ## PV cell params (3-comp)
  387. if 'PV_simple' not in loadCellParams:
  388. cellRule = netParams.importCellParams(label='PV_simple', conds={'cellType':'PV', 'cellModel':'HH_simple'},
  389. fileName='cells/FS3.hoc', cellName='FScell1', cellInstance = True)
  390. cellRule['secLists']['spiny'] = ['soma', 'dend']
  391. #netParams.addCellParamsWeightNorm('PV_simple', 'conn/PV_simple_weightNorm.pkl', threshold=cfg.weightNormThreshold)
  392. if saveCellParams: netParams.saveCellParamsRule(label='PV_simple', fileName='cells/PV_simple_cellParams.pkl')
  393. #------------------------------------------------------------------------------
  394. ## SOM cell params (3-comp)
  395. if 'SOM_simple' not in loadCellParams:
  396. cellRule = netParams.importCellParams(label='SOM_simple', conds={'cellType':'SOM', 'cellModel':'HH_simple'},
  397. fileName='cells/LTS3.hoc', cellName='LTScell1', cellInstance = True)
  398. cellRule['secLists']['spiny'] = ['soma', 'dend']
  399. #netParams.addCellParamsWeightNorm('SOM_simple', 'conn/SOM_simple_weightNorm.pkl', threshold=cfg.weightNormThreshold)
  400. if saveCellParams: netParams.saveCellParamsRule(label='SOM_simple', fileName='cells/SOM_simple_cellParams.pkl')
  401. #------------------------------------------------------------------------------
  402. # Population parameters
  403. #------------------------------------------------------------------------------
  404. #------------------------------------------------------------------------------
  405. ## load densities
  406. with open('cells/cellDensity.pkl', 'rb') as fileObj: density = pickle.load(fileObj)['density']
  407. ## Local populations
  408. #netParams.popParams['PT5B'] = {'cellModel': cfg.cellmod['PT5B'], 'cellType': 'PT', 'ynormRange': layer['5B'], 'numCells': num_PT}
  409. netParams.popParams['PT5B_reduced'] = {'cellModel': 'HH_reduced', 'cellType': 'PT', 'ynormRange': layer['5B'], 'numCells': num_PT}
  410. netParams.popParams['SOM5B'] = {'cellModel': 'HH_simple', 'cellType': 'SOM','ynormRange': layer['5B'], 'numCells': num_SOM}
  411. netParams.popParams['PV5B'] = {'cellModel': 'HH_simple', 'cellType': 'PV', 'ynormRange': layer['5B'], 'numCells': num_PV}
  412. #netParams.popParams['rnd'] = {'cellModel': 'Randomizer', 'numCells': 1}
  413. if cfg.singleCellPops:
  414. for pop in netParams.popParams.values(): pop['numCells'] = 1
  415. #------------------------------------------------------------------------------
  416. ## Long-range input populations (VecStims)
  417. numCells_long = 20
  418. ''' spkTimes_4K = np.concatenate((np.arange(0, 20, 1), np.arange(cfg.t_HSP + 5*1000, cfg.t_HSP + 15*1000, 1/rate['4K']*1000) ,
  419. np.arange(ts['D1train'], ts['D1train'] + 10*1000, 1/rate['4K']*1000) ,
  420. np.arange(ts['D1train'] + 11*1000, ts['D1train'] + 21*1000, 1/rate['4K']*1000) ,
  421. np.arange(ts['D1train'] + 22*1000, ts['D1train'] + 32*1000, 1/rate['4K']*1000) ,
  422. np.arange(ts['D1test'] + 5*1000, ts['D1test'] + 15*1000, 1/rate['4K']*1000) ,
  423. np.arange(ts['D3test'] + 5*1000, ts['D3test'] + 15*1000, 1/rate['4K']*1000) ,
  424. np.arange(ts['D4extinct'], ts['D4extinct'] + 40*1000, 1/rate['4K']*1000) ,
  425. np.arange(ts['D4extinct'] + 41*1000, ts['D4extinct'] + 81*1000, 1/rate['4K']*1000) ,
  426. np.arange(ts['D4extinct'] + 82*1000, ts['D4extinct'] + 122*1000, 1/rate['4K']*1000) ,
  427. np.arange(ts['D4extinct'] + 123*1000, ts['D4extinct'] + 163*1000, 1/rate['4K']*1000) ,
  428. np.arange(ts['D4extinct'] + 164*1000, ts['D4extinct'] + 204*1000, 1/rate['4K']*1000) ,
  429. np.arange(ts['D4test'] + 5*1000, ts['D4test'] + 15*1000, 1/rate['4K']*1000) ,
  430. np.arange(ts['D5extinct'], ts['D5extinct'] + 40*1000, 1/rate['4K']*1000) ,
  431. np.arange(ts['D5extinct'] + 41*1000, ts['D5extinct'] + 81*1000, 1/rate['4K']*1000),
  432. np.arange(ts['D5extinct'] + 123*1000, ts['D5extinct'] + 163*1000, 1/rate['4K']*1000) ,
  433. np.arange(ts['D5extinct'] + 164*1000, ts['D5extinct'] + 204*1000, 1/rate['4K']*1000) ,
  434. np.arange(ts['D5test'] + 5*1000, ts['D5test'] + 15*1000, 1/rate['4K']*1000)))
  435. spkTimes_12K = np.concatenate((np.arange(cfg.t_HSP + 35*1000, cfg.t_HSP + 45*1000, 1/rate['12K']*1000),
  436. np.arange(ts['D1test'] + 35*1000, ts['D1test'] + 45*1000, 1/rate['12K']*1000) ,
  437. np.arange(ts['D3test'] + 35*1000, ts['D3test'] + 45*1000, 1/rate['12K']*1000),
  438. np.arange(ts['D4test'] + 35*1000, ts['D4test'] + 45*1000, 1/rate['12K']*1000),
  439. np.arange(ts['D5test'] + 35*1000, ts['D5test'] + 45*1000, 1/rate['12K']*1000)))
  440. spkTimes_shock = np.concatenate((np.arange(ts['D1train'] + 8*1000, ts['D1train'] + 10*1000, 1/rate['shock']*1000),
  441. np.arange(ts['D1train'] + 19*1000, ts['D1train'] + 21*1000, 1/rate['shock']*1000),
  442. np.arange(ts['D1train'] + 30*1000, ts['D1train'] + 32*1000, 1/rate['shock']*1000)))
  443. '''
  444. ts = cfg.tstart
  445. if cfg.addLongConn:
  446. # VecStims
  447. longPops = ['S1_4K','S1_12K', 'OC']
  448. # create list of pulses (each item is a dict with pulse params) #noise(0 = deterministic; 1 = completely random)
  449. rate = {'4K': 50, '12K': 50, 'shock': 100} #Hz
  450. hspRate = 5
  451. pulses_4K = [{'start': ts['HSPset0'], 'end': ts['HSPset0']+cfg.t_hspvtrg, 'rate': hspRate, 'noise': 0.25}, #HSP
  452. {'start': ts['HSPset1'], 'end': ts['HSPset1']+cfg.t_hspvtrg, 'rate': hspRate, 'noise': 0.25}, #HSP
  453. {'start': ts['HSP0'], 'end': ts['HSP0']+cfg.t_HSP, 'rate': hspRate, 'noise': 0.25}, #HSP
  454. {'start': ts['HSPset2'], 'end': ts['HSPset2']+cfg.t_hspvtrg, 'rate': hspRate, 'noise': 0.25}, #HSP
  455. {'start': ts['HSP1'], 'end': ts['HSP1']+cfg.t_HSP , 'rate': hspRate, 'noise': 0.25}, #HSP
  456. {'start': ts['Baseline'] + 5*1000, 'end': ts['Baseline'] + 15*1000, 'rate': rate['4K'], 'noise': 0}, #Baseline
  457. {'start': ts['D1train'], 'end': ts['D1train'] + 10*1000, 'rate': rate['4K'], 'noise': 0}, #D1 FC
  458. {'start': ts['D1train'] + 11*1000, 'end': ts['D1train'] + 21*1000, 'rate': rate['4K'], 'noise': 0}, #D1 FC
  459. {'start': ts['D1train'] + 22*1000, 'end': ts['D1train'] + 32*1000, 'rate': rate['4K'], 'noise': 0}, #D1 FC
  460. {'start': ts['D1test'] + 5*1000, 'end': ts['D1test'] + 15*1000, 'rate': rate['4K'], 'noise': 0}, #D1 test
  461. {'start': ts['D3test'] + 5*1000, 'end': ts['D3test'] + 15*1000, 'rate': rate['4K'], 'noise': 0}, #D3 test
  462. {'start': ts['D4extinct'], 'end': ts['D4extinct'] + 40*1000, 'rate': rate['4K'], 'noise': 0}, #D4 FC
  463. {'start': ts['D4extinct'] + 41*1000, 'end': ts['D4extinct'] + 81*1000, 'rate': rate['4K'], 'noise': 0}, #D4 FC
  464. {'start': ts['D4extinct'] + 82*1000, 'end': ts['D4extinct'] + 122*1000, 'rate': rate['4K'], 'noise': 0}, #D4 FC
  465. {'start': ts['D4extinct'] + 123*1000, 'end': ts['D4extinct'] + 163*1000, 'rate': rate['4K'], 'noise': 0}, #D4 FC
  466. {'start': ts['D4extinct'] + 164*1000, 'end': ts['D4extinct'] + 204*1000, 'rate': rate['4K'], 'noise': 0}, #D4 FC
  467. {'start': ts['D4test'] + 5*1000, 'end': ts['D4test'] + 15*1000, 'rate': rate['4K'], 'noise': 0}, #D4 test
  468. {'start': ts['D5extinct'], 'end': ts['D5extinct'] + 40*1000, 'rate': rate['4K'], 'noise': 0}, #D5 FC
  469. {'start': ts['D5extinct'] + 41*1000, 'end': ts['D5extinct'] + 81*1000, 'rate': rate['4K'], 'noise': 0}, #D5 FC
  470. {'start': ts['D5extinct'] + 82*1000, 'end': ts['D5extinct'] + 122*1000, 'rate': rate['4K'], 'noise': 0}, #D5 FC
  471. {'start': ts['D5extinct'] + 123*1000, 'end': ts['D5extinct'] + 163*1000, 'rate': rate['4K'], 'noise': 0}, #D5 FC
  472. {'start': ts['D5extinct'] + 164*1000, 'end': ts['D5extinct'] + 204*1000, 'rate': rate['4K'], 'noise': 0}, #D5 FC
  473. {'start': ts['D5test'] + 5*1000, 'end': ts['D5test'] + 15*1000, 'rate': rate['4K'], 'noise': 0} #D5 test
  474. ]
  475. pulses_12K = [
  476. {'start': ts['HSPset0'], 'end': ts['HSPset0']+cfg.t_hspvtrg, 'rate': hspRate, 'noise': 0.25}, #HSP
  477. {'start': ts['HSPset1'], 'end': ts['HSPset1']+cfg.t_hspvtrg, 'rate': hspRate, 'noise': 0.25}, #HSP
  478. {'start': ts['HSP0'], 'end': ts['HSP0']+cfg.t_HSP, 'rate': hspRate, 'noise': 0.25}, #HSP
  479. {'start': ts['HSPset2'], 'end': ts['HSPset2']+cfg.t_hspvtrg, 'rate': hspRate, 'noise': 0.25}, #HSP
  480. {'start': ts['HSP1'], 'end': ts['HSP1']+cfg.t_HSP , 'rate': hspRate, 'noise': 0.25}, #HSP
  481. {'start': ts['Baseline'] + 35*1000, 'end': ts['Baseline'] + 45*1000, 'rate': rate['12K'], 'noise': 0}, #Baseline
  482. {'start': ts['D1test'] + 35*1000, 'end': ts['D1test'] + 45*1000, 'rate': rate['12K'], 'noise': 0}, #D1 test
  483. {'start': ts['D3test'] + 35*1000, 'end': ts['D3test'] + 45*1000, 'rate': rate['12K'], 'noise': 0}, #D3 test
  484. {'start': ts['D4test'] + 35*1000, 'end': ts['D4test'] + 45*1000, 'rate': rate['12K'], 'noise': 0}, #D4 test
  485. {'start': ts['D5test'] + 35*1000, 'end': ts['D5test'] + 45*1000, 'rate': rate['12K'], 'noise': 0} #D5 test
  486. ]
  487. pulses_shock = [
  488. {'start': ts['HSPset0'], 'end': ts['HSPset0']+cfg.t_hspvtrg, 'rate': hspRate, 'noise': 0.25}, #HSP
  489. {'start': ts['HSPset1'], 'end': ts['HSPset1']+cfg.t_hspvtrg, 'rate': hspRate, 'noise': 0.25}, #HSP
  490. {'start': ts['HSP0'], 'end': ts['HSP0']+cfg.t_HSP, 'rate': hspRate, 'noise': 0.25}, #HSP
  491. {'start': ts['HSPset2'], 'end': ts['HSPset2']+cfg.t_hspvtrg, 'rate': hspRate, 'noise': 0.25}, #HSP
  492. {'start': ts['HSP1'], 'end': ts['HSP1']+cfg.t_HSP , 'rate': hspRate, 'noise': 0.25}, #HSP
  493. {'start': ts['D1train'] + 8*1000, 'end': ts['D1train'] + 10*1000, 'rate': rate['shock'], 'noise': 0}, #D1 FC
  494. {'start': ts['D1train'] + 19*1000, 'end': ts['D1train'] + 21*1000, 'rate': rate['shock'], 'noise': 0}, #D1 FC
  495. {'start': ts['D1train'] + 30*1000, 'end': ts['D1train'] + 32*1000, 'rate': rate['shock'], 'noise': 0} #D1 FC
  496. ]
  497. netParams.popParams['S1_4K'] = {'cellModel': 'VecStim', 'numCells': numCells_long,
  498. 'ynormRange': layer['longS1_4K'], 'spkTimes': [cfg.duration], 'pulses': pulses_4K}
  499. netParams.popParams['S1_12K'] = {'cellModel': 'VecStim', 'numCells': numCells_long,
  500. 'ynormRange': layer['longS1_12K'], 'spkTimes': [cfg.duration], 'pulses': pulses_12K}
  501. netParams.popParams['OC'] = {'cellModel': 'VecStim', 'numCells': numCells_long,
  502. 'ynormRange': layer['longOC'], 'spkTimes': [cfg.duration], 'pulses': pulses_shock}
  503. '''netParams.popParams['HSP1'] = {'cellModel': 'VecStim', 'numCells': 1,
  504. 'spikePattern': {'type': 'poisson', 'start': 0, 'stop': cfg.t_hspvtrg, 'frequency': 10}}
  505. netParams.popParams['HSP2'] = {'cellModel': 'VecStim', 'numCells': 1,
  506. 'spikePattern': {'type': 'poisson', 'start': ts['D1test'] + cfg.t_test +cfg.t_cool-20, 'stop': ts['D3test'], 'frequency': 10}}
  507. netParams.popParams['HSP3'] = {'cellModel': 'VecStim', 'numCells': 1,
  508. 'spikePattern': {'type': 'poisson', 'start': ts['D4test'] + cfg.t_test +cfg.t_cool-20, 'stop': ts['D5extinct'], 'frequency': 10}}
  509. '''
  510. #netParams.popParams['HSP'] = {'cellModel': 'VecStim', 'numCells': 1,
  511. # 'spkTimes': [ts['D1test'] + cfg.t_test +cfg.t_cool], 'pulses': pulses_HSP}
  512. #------------------------------------------------------------------------------
  513. # Synaptic mechanism parameters
  514. #------------------------------------------------------------------------------
  515. netParams.synMechParams['NMDA'] = {'mod': 'MyExp2SynNMDABB', 'tau1NMDA': 15, 'tau2NMDA': 150, 'e': 0}
  516. netParams.synMechParams['AMPA'] = {'mod':'MyExp2SynBB', 'tau1': 0.05, 'tau2': 5.3*cfg.AMPATau2Factor, 'e': 0}
  517. netParams.synMechParams['GABAB'] = {'mod':'MyExp2SynBB', 'tau1': 3.5, 'tau2': 260.9, 'e': -93}
  518. netParams.synMechParams['GABAA'] = {'mod':'MyExp2SynBB', 'tau1': 0.07, 'tau2': 18.2, 'e': -80}
  519. netParams.synMechParams['GABAASlow'] = {'mod': 'MyExp2SynBB','tau1': 2, 'tau2': 100, 'e': -80}
  520. netParams.synMechParams['GABAASlowSlow'] = {'mod': 'MyExp2SynBB', 'tau1': 200, 'tau2': 400, 'e': -80}
  521. ESynMech = ['AMPA', 'NMDA']
  522. SOMESynMech = ['GABAASlow','GABAB']
  523. SOMISynMech = ['GABAASlow']
  524. PVSynMech = ['GABAA']
  525. #------------------------------------------------------------------------------
  526. # Local connectivity parameters
  527. #------------------------------------------------------------------------------
  528. # Store the number of segments in a dictionary
  529. nseg = {'PV': {key: math.floor(value) for key, value in secL_PV.items()},
  530. 'SOM': {key: math.floor(value) for key, value in secL_SOM.items()},
  531. 'PT': {key: math.floor(value) for key, value in secL_PT.items()}} #highest possible spine density = 1/um
  532. # plasticity parameters
  533. STDPparams = {'hebbwt': .5, 'antiwt':-.5, 'wmax': 15, 'RLon': 0 , 'RLhebbwt': 0.1, 'RLantiwt': -0.100, \
  534. 'tauhebb': 10, 'RLwindhebb': 50, 'useRLexp': 0, 'softthresh': 1, 'verbose':0}
  535. randomlistgen = RandomSequenceNetParams()
  536. randomlistgen.initializeRandomSequence(cfg)
  537. # Use configurable data directory
  538. data_dir = os.environ.get('SIM_DATA_DIR', './data')
  539. randomlist_path = os.path.join(data_dir, f'seed{cfg.rdseed}', f'randomlistgen{cfg.rdseed}.txt')
  540. os.makedirs(os.path.dirname(randomlist_path), exist_ok=True)
  541. with open(randomlist_path, 'w') as f:
  542. f.write(json.dumps(randomlistgen.randomlist, indent=4))
  543. '''cell_types = ['PT', 'PV', 'SOM']
  544. total_synapses_all_cells = 0
  545. for celltype in cell_types:
  546. synapse_counts = randomlistgen._calculate_total_synapses(celltype)
  547. axosomatic_synapses = synapse_counts['axosomatic']
  548. axodendritic_synapses = sum(synapse_counts['axodendritic'].values())
  549. total_synapses = axosomatic_synapses + axodendritic_synapses
  550. total_synapses_all_cells += total_synapses
  551. print(total_synapses_all_cells)'''
  552. #------------------------------------------------------------------------------
  553. ## E -> I
  554. if cfg.EIGain: # Use IEGain if value set
  555. cfg.EPVGain = cfg.EIGain
  556. cfg.ESOMGain = cfg.EIGain
  557. else:
  558. cfg.EIGain = (cfg.EPVGain+cfg.ESOMGain)/2.0
  559. if cfg.addConn and (cfg.EPVGain > 0.0 or cfg.ESOMGain > 0.0):
  560. preTypes = ['PT']
  561. postTypes = ['PV', 'SOM']
  562. ESynMech = ['AMPA','NMDA']
  563. lGain = [cfg.EPVGain, cfg.ESOMGain] # E -> PV or E -> SOM
  564. for ipost, postType in enumerate(postTypes):
  565. weights = [
  566. randomlistgen.randomlist['EI'][postType][j][i][0][1]
  567. for i in range(num_PT)
  568. for j in range(num_dict[postType])
  569. ]
  570. weights_syns = [[x, x] for x in weights]
  571. locs = [
  572. randomlistgen.randomlist['EI'][postType][j][i][0][0]
  573. for i in range(num_PT)
  574. for j in range(num_dict[postType])
  575. ]
  576. locs_syns = [[x, x] for x in locs]
  577. ruleLabel = 'EI'+'_'+ postType
  578. netParams.connParams[ruleLabel] = {
  579. 'preConds': {'cellType': preTypes},#, 'ynorm': list(preBin)},
  580. 'postConds': {'cellType': postType},#, 'ynorm': list(postBin)},
  581. 'synMech': ESynMech,
  582. 'connList': [(i, j) for i in range(num_PT) for j in range(num_dict[postType])],
  583. 'weight': weights_syns,#lambda pre, post: randomlistgen.randomlist['EI'][postType][post.index][pre.index][0][1],
  584. 'loc': locs_syns, #lambda pre, post: randomlistgen.randomlist['EI'][postType][post.index][pre.index][0][0],
  585. #'delay': 'defaultDelay+dist_3D/propVelocity',
  586. 'sec': 'soma',
  587. 'synsPerConn': 1,
  588. 'plast': {'mech': 'STDP', 'params': STDPparams}} # simple I cells used right now only have soma
  589. #debug: line 695 in compartCell.py, conn['plast'] -> conn
  590. #------------------------------------------------------------------------------
  591. ## I -> all
  592. if cfg.addConn:
  593. preCellTypes = ['SOM', 'PV']
  594. ynorms = [[0,1]]*2 # <----not local, interneuron can connect to all layers
  595. postCellTypes = ['PT', 'PV', 'SOM']
  596. disynapticBias = None # default, used for I->I
  597. for i,(preCellType, ynorm) in enumerate(zip(preCellTypes, ynorms)):
  598. for ipost, postCellType in enumerate(postCellTypes):
  599. if postCellType == 'PV': # postsynaptic I cell
  600. sec = 'soma'
  601. synWeightFraction = [1]
  602. if preCellType == 'PV': # PV->PV
  603. # weight = IIweight * cfg.PVPVGain
  604. synMech = PVSynMech
  605. else: # SOM->PV
  606. # weight = IIweight * cfg.SOMPVGain
  607. synMech = SOMISynMech
  608. elif postCellType == 'SOM': # postsynaptic I cell
  609. sec = 'soma'
  610. synWeightFraction = [1]
  611. if preCellType == 'PV': # PV->SOM
  612. # weight = IIweight * cfg.PVSOMGain
  613. synMech = PVSynMech
  614. else: # SOM->SOM
  615. # weight = IIweight * cfg.SOMSOMGain
  616. synMech = SOMISynMech
  617. elif postCellType == 'PT': # postsynaptic PT cell
  618. #disynapticBias = IEdisynBias
  619. if preCellType == 'PV': # PV->E
  620. #weight = IEweight * cfg.IPTGain * cfg.PVEGain
  621. synMech = PVSynMech
  622. sec = 'perisom'
  623. else: # SOM->E
  624. #weight = IEweight * cfg.IPTGain * cfg.SOMEGain
  625. synMech = SOMESynMech
  626. sec = 'spiny'
  627. synWeightFraction = cfg.synWeightFractionSOME
  628. if postCellType == 'PT':
  629. numCell = num_PT
  630. else:
  631. numCell = num_dict[postCellType]
  632. if postCellType == 'PT':
  633. if sec in ['soma', 'perisom']:
  634. sec = 'soma'
  635. weights = [
  636. randomlistgen.randomlist[preCellType+'E'][j][i][sec][0][1]
  637. for i in range(num_dict[preCellType])
  638. for j in range(num_PT)
  639. ]
  640. locs = [
  641. randomlistgen.randomlist[preCellType+'E'][j][i][sec][0][0]
  642. for i in range(num_dict[preCellType])
  643. for j in range(num_PT)
  644. ]
  645. ruleLabel = preCellType +'_'+ postCellType
  646. netParams.connParams[ruleLabel] = {
  647. 'preConds': {'cellType': preCellType, 'ynorm': ynorm},
  648. 'postConds': {'cellType': postCellType, 'ynorm': ynorm},
  649. 'synMech': synMech,
  650. 'connList': [(i, j) for i in range(num_dict[preCellType]) for j in range(numCell)],
  651. 'weight': weights, #lambda pre, post: randomlistgen.randomlist[preCellType + 'E'][postCellType][post.index][pre.index][sec][0][1],
  652. 'loc': locs, #lambda pre, post: randomlistgen.randomlist[preCellType+'E'][postCellType][post.index][pre.index][sec][0][0],
  653. #'delay': 'defaultDelay+dist_3D/propVelocity',
  654. 'synsPerConn': 1,
  655. 'sec': sec,
  656. #'disynapticBias': disynapticBias,
  657. 'plast': {'mech': 'STDP', 'params': STDPparams}}
  658. else:
  659. for s in seclist['PT']['dend']:
  660. weights = [
  661. randomlistgen.randomlist[preCellType+'E'][j][i][s][0][1]
  662. for i in range(num_dict[preCellType])
  663. for j in range(num_PT)
  664. ]
  665. locs = [
  666. randomlistgen.randomlist[preCellType+'E'][j][i][s][0][0]
  667. for i in range(num_dict[preCellType])
  668. for j in range(num_PT)
  669. ]
  670. ruleLabel = preCellType +'_'+ postCellType + '_' + s
  671. netParams.connParams[ruleLabel] = {
  672. 'preConds': {'cellType': preCellType, 'ynorm': ynorm},
  673. 'postConds': {'cellType': postCellType, 'ynorm': ynorm},
  674. 'synMech': synMech,
  675. 'connList': [(i, j) for i in range(num_dict[preCellType]) for j in range(numCell)],
  676. 'weight': weights, #lambda pre, post: randomlistgen.randomlist[preCellType + 'E'][postCellType][post.index][pre.index][s][0][1],
  677. 'loc': locs, #lambda pre, post: randomlistgen.randomlist[preCellType + 'E'][postCellType][post.index][pre.index][s][0][0],
  678. #'delay': 'defaultDelay+dist_3D/propVelocity',
  679. 'synsPerConn': 1,
  680. 'sec': s,
  681. #'disynapticBias': disynapticBias,
  682. 'plast': {'mech': 'STDP', 'params': STDPparams}}
  683. else:
  684. if preCellType == postCellType:
  685. weights = [
  686. randomlistgen.randomlist['II'][postCellType][preCellType][j][i][0][1]
  687. for i in range(num_dict[preCellType]-1)
  688. for j in range(num_dict[postCellType])
  689. ]
  690. locs = [
  691. randomlistgen.randomlist['II'][postCellType][preCellType][j][i][0][0]
  692. for i in range(num_dict[preCellType]-1)
  693. for j in range(num_dict[postCellType])
  694. ]
  695. else:
  696. weights = [
  697. randomlistgen.randomlist['II'][postCellType][preCellType][j][i][0][1]
  698. for i in range(num_dict[preCellType])
  699. for j in range(num_dict[postCellType])
  700. ]
  701. locs = [
  702. randomlistgen.randomlist['II'][postCellType][preCellType][j][i][0][0]
  703. for i in range(num_dict[preCellType])
  704. for j in range(num_dict[postCellType])
  705. ]
  706. ruleLabel = preCellType + '_' + postCellType
  707. netParams.connParams[ruleLabel] = {
  708. 'preConds': {'cellType': preCellType, 'ynorm': ynorm},
  709. 'postConds': {'cellType': postCellType, 'ynorm': ynorm},
  710. 'synMech': synMech,
  711. 'connList': [(i, j) for i in range(num_dict[preCellType]-1) for j in range(numCell)],
  712. 'weight': weights, #lambda pre, post: randomlistgen.randomlist[preCellType + 'E'][postCellType][post.index][pre.index][sec][0][1],
  713. 'loc': locs, #lambda pre, post: randomlistgen.randomlist[preCellType+'E'][postCellType][post.index][pre.index][sec][0][0],
  714. #'delay': 'defaultDelay+dist_3D/propVelocity',
  715. 'synsPerConn': 1,
  716. 'sec': sec,
  717. #'disynapticBias': disynapticBias,
  718. 'plast': {'mech': 'STDP', 'params': STDPparams}}
  719. #------------------------------------------------------------------------------
  720. # Long-range connectivity parameters
  721. #------------------------------------------------------------------------------
  722. if cfg.addLongConn:
  723. longPops = ['S1_4K','S1_12K', 'OC']
  724. cellTypes = ['PT']
  725. for longPop in longPops:
  726. for secName in seclist['PT']['dend']:
  727. weights = [
  728. [syn[1] for syn in randomlistgen.randomlist['LongE'][longPop][secName][j][i]]
  729. for i in range(numCells_long)
  730. for j in range(num_PT)
  731. ]
  732. weights_syns = [[x, x] for x in weights]
  733. locs = [
  734. [syn[0] for syn in randomlistgen.randomlist['LongE'][longPop][secName][j][i]]
  735. for i in range(numCells_long)
  736. for j in range(num_PT)
  737. ]
  738. locs_syns = [[x, x] for x in locs]
  739. ruleLabel = longPop+'_'+secName
  740. netParams.connParams[ruleLabel] = {
  741. 'preConds': {'pop': longPop},
  742. 'postConds': {'cellType': 'PT'},
  743. 'synMech': ESynMech,
  744. 'connList': [(i, j) for i in range(numCells_long) for j in range(num_PT)],
  745. 'weight': weights_syns,
  746. 'loc': locs_syns,
  747. 'synsPerConn': math.ceil(nseg['PT'][secName]/numCells_long),
  748. 'delay': 'defaultDelay+dist_3D/propVelocity',
  749. 'sec': secName,
  750. 'plast': {'mech': 'STDP', 'params': STDPparams}}
  751. #------------------------------------------------------------------------------
  752. # Description
  753. #------------------------------------------------------------------------------
  754. netParams.description = """
  755. - M1 net, 6 layers, 7 cell types
  756. - NCD-based connectivity from Weiler et al. 2008; Anderson et al. 2010; Kiritani et al. 2012;
  757. Yamawaki & Shepherd 2015; Apicella et al. 2012
  758. - Parametrized version based on Sam's code
  759. - Updated cell models and mod files
  760. - Added parametrized current inputs
  761. - Fixed bug: prev was using cell models in /usr/site/nrniv/local/python/ instead of cells
  762. - Use 5 synsperconn for 5-comp cells (HH_reduced); and 1 for 1-comp cells (HH_simple)
  763. - Fixed bug: made global h params separate for each cell model
  764. - Fixed v_init for different cell models
  765. - New IT cell with same geom as PT
  766. - Cleaned cfg and moved background inputs here
  767. - Set EIGain and IEGain for each inh cell type
  768. - Added secLists for PT full
  769. - Fixed reduced CT (wrong vinit and file)
  770. - Added subcellular conn rules to distribute synapses
  771. - PT full model soma centered at 0,0,0
  772. - Set cfg seeds here to ensure they get updated
  773. - Added PVSOMGain and SOMPVGain
  774. - PT subcellular distribution as a cfg param
  775. - Cylindrical volume
  776. - DefaultDelay (for local conns) = 2ms
  777. - Added long range connections based on Yamawaki 2015a,b; Suter 2015; Hooks 2013; Meyer 2011
  778. - Updated cell densities based on Tsai 2009; Lefort 2009; Katz 2011; Wall 2016;
  779. - Separated PV and SOM of L5A vs L5B
  780. - Fixed bugs in local conn (PT, PV5, SOM5, L6)
  781. - Added perisom secList including all sections 50um from soma
  782. - Added subcellular conn rules (for both full and reduced models)
  783. - Improved cell models, including PV and SOM fI curves
  784. - Improved subcell conn rules based on data from Suter15, Hooks13 and others
  785. - Adapted Bdend L of reduced cell models
  786. - Made long pop rates a cfg param
  787. - Set threshold to 0.0 mV
  788. - Parametrized I->E/I layer weights
  789. - Added missing subconn rules (IT6->PT; S1,S2,cM1->IT/CT; long->SOM/PV)
  790. - Added threshold to weightNorm (PT threshold=10x)
  791. - weightNorm threshold as a cfg parameter
  792. - Separate PV->SOM, SOM->PV, SOM->SOM, PV->PV gains
  793. - Conn changes: reduced IT2->IT4, IT5B->CT6, IT5B,6->IT2,4,5A, IT2,4,5A,6->IT5B; increased CT->PV6+SOM6
  794. - Parametrized PT ih gbar
  795. - Added IFullGain parameter: I->E gain for full detailed cell models
  796. - Replace PT ih with Migliore 2012
  797. - Parametrized ihGbar, ihGbarBasal, dendNa, axonNa, axonRa, removeNa
  798. - Replaced cfg list params with dicts
  799. - Parametrized ihLkcBasal and AMPATau2Factor
  800. - Fixed synMechWeightFactor
  801. - Parametrized PT ih slope
  802. - Added disynapticBias to I->E (Yamawaki&Shepherd,2015)
  803. - Fixed E->CT bin 0.9-1.0
  804. - Replaced GABAB with exp2syn and adapted synMech ratios
  805. - Parametrized somaNa
  806. - Added ynorm condition to NetStims
  807. - Added option to play back recorded spikes into long-range inputs
  808. - Fixed Bdend pt3d y location
  809. - Added netParams.convertCellShapes = True to convert stylized geoms to 3d points
  810. - New layer boundaries, cell densities, conn, FS+SOM L4 grouped with L2/3, low cortical input to L4
  811. - Increased exc->L4 based on Yamawaki 2015 fig 5
  812. - v54: Moved from NetPyNE v0.7.9 to v0.9.1 (v54_batch1-6)
  813. - v54: Moved to NetPyNE v0.9.1 and py3 (v54_batch7 onwards)
  814. - v56: Reduced dt from 0.05 to 0.025 (note this version follows from v54, i.e. without new cell types; branch 'paper2019_py3')
  815. - v56: (included in prev version): Added cfg.KgbarFactor
  816. """

netParams.py at commit 8edb39e, no license · at the source

Overview

  1. School of Biomedical Sciences, LKS Faculty of Medicine, The University of Hong Kong, Hong Kong, China
  2. Advanced Biomedical Instrumentation Centre, Hong Kong Science Park, Shatin, New Territories, Hong Kong, China
  3. Department of Electrical and Electronic Engineering, The University of Hong Kong, Hong Kong, China
Institutions: University of Hong Kong (Hong Kong SAR China); Hong Kong Science and Technology Parks Corporation (Hong Kong SAR China)
Journal: Science advances, volume 12, issue 29, article eaec3961
Dates: received 18 September 2025; accepted 2 June 2026; published online 17 July 2026; in print July 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1126/sciadv.aec3961 · PMID 42467781 · PMCID PMC13378561 · OpenAlex W7169527484
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: histology / microscopy (modality), mouse (organism), cognitive (subfield)
Methods: Statistics, Smoothing, state filtering, decompositions, Connectivity, fMRI & imaging, Single-unit activity, calcium imaging
MeSH: Dendritic Spines*, Extinction, Psychological*, Fear*, Learning*, Neuronal Plasticity*, Animals, Male, Mice (* major topic)
Topic: Neuroscience and Neuropharmacology Research (Cellular and Molecular Neuroscience, Neuroscience), according to OpenAlex
Funding: National Natural Science Foundation of China (N_HKU735/21); Research Grants Council, University Grants Committee (C1024-22GF, C7074-21G, 17103922, C7011-24GF, 17108821, C7026-25G, 17102525); Innovation and Technology Commission; Health and Medical Research Fund (09200966); Li Ka Shing Faculty of Medicine, University of Hong Kong
Citations: not cited yet (Europe PMC); 84 references in the paper

Abstract

Structural plasticity of dendritic spines has been observed during different learning paradigms, but how the functional dynamics of dendritic spines changes with memory processing and how these patterns relate to structural plasticity and dendritic integration remain unclear. Here, we perform longitudinal functional and structural in vivo imaging of the frontal association cortex in mice subject to fear conditioning and extinction over several days. We show that fear learning induced responsive spines that are more likely to be synchronous and clustered, which are consolidated over the following days but attenuated by extinction. We develop a causal inference model demonstrating that the active spine calcium signals during fear learning prevent the spines from being eliminated while promoting the elimination of neighboring spines after memory consolidation. Furthermore, the dendritic responsive signal reveals a learning-dependent tone discrimination pattern that is correlated to spines’ structural remodeling. Our findings provide in vivo evidence consistent with functional-structural link of dendritic spines in a bidirectional learning paradigm.

Reproduced under the paper's license (CC BY), from the paper cited above.

Repositories

Its files are read in the Code ↔ Paper reader above, with 2 matches between paragraphs and lines of code.

Zenodo 20301802

License: CC-BY-4.0
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Size: 1 file
Software Heritage: not checked
Found in: “Data, code, and materials availability:”
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Availability: 1 check, the latest on 27 September 2026: the link answers (HTTP 200)
  • 27 September 2026: the link answers (HTTP 200)

4768/reversible_spine_model

License: none: the authors keep all their rights
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: 8edb39e800efb9af9fc2a80421d0de4267bdbab8, 2 September 2025
Languages: NEURON (455), Python (80), C/C++ (7)
Size: 794 files, 542 scripts
Software Heritage: not archived
Found in: “Data, code, and materials availability:”
Holds: README, environment (requirements.txt)
Not found: license file, CITATION.cff, tests, continuous integration, documentation
Tools: NEURON (511 files), NumPy (43 files), NetPyNE (37 files), Matplotlib (33 files), SciPy (24 files), Pillow (7 files), pandas (2 files)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
543 files

The paper's code and data availability statement is in the Data section.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 2 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 542 scripts, each with its path and the digest of its content;
  • 2 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

No dataset and no data link were found in the paper.

Data, code, and materials availability

This study did not generate new materials. All data and code needed to evaluate and reproduce the results in the paper are present in the paper and/or the Supplemental Materials. The raw data files and simulation model codes have been deposited to Zenodo under the following accession DOI: https://doi.org/10.5281/zenodo.20301802. The simulation model codes used in this paper are also available in the following repository: https://github.com/4768/reversible_spine_model.git.

Reproduced under the paper's license (CC BY), from the paper cited above.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 2, 28 September 2026

  • Funding: added National Natural Science Foundation of China: N_HKU735/21; Research Grants Council, University Grants Committee: C1024-22GF, C7074-21G, 17103922, C7011-24GF, 17108821, C7026-25G, 17102525; Innovation and Technology Commission; Health and Medical Research Fund: 09200966; Li Ka Shing Faculty of Medicine, University of Hong Kong

Version 1, 27 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 5 authors, 8 MeSH terms, 84 references.

Cite

This paper

Li, X., Zheng, Q., Wong, K. H. K., Wong, K. K. Y., & Lai, C. S. W. (2026). Linking functional and structural dendritic spine remodeling during fear learning and extinction in vivo. Science advances, 12(29), eaec3961. https://doi.org/10.1126/sciadv.aec3961

BibTeX

@article{li2026linking,
author = {Li, Xiaoyang and Zheng, Qiyu and Wong, Kim Hoi Kin and Wong, Kenneth Kin Yip and Lai, Cora Sau Wan},
title = {{Linking functional and structural dendritic spine remodeling during fear learning and extinction in vivo}},
journal = {Science advances},
year = {2026},
month = jul,
volume = {12},
number = {29},
pages = {eaec3961},
publisher = {American Association for the Advancement of Science},
issn = {2375-2548},
doi = {10.1126/sciadv.aec3961},
url = {https://doi.org/10.1126/sciadv.aec3961},
pmid = {42467781},
pmcid = {PMC13378561}
}

RIS

TY - JOUR
AU - Li, Xiaoyang
AU - Zheng, Qiyu
AU - Wong, Kim Hoi Kin
AU - Wong, Kenneth Kin Yip
AU - Lai, Cora Sau Wan
TI - Linking functional and structural dendritic spine remodeling during fear learning and extinction in vivo
T2 - Science advances
J2 - Sci Adv
PY - 2026
DA - 2026/07/17
VL - 12
IS - 29
SP - eaec3961
SN - 2375-2548
PB - American Association for the Advancement of Science
DO - 10.1126/sciadv.aec3961
UR - https://doi.org/10.1126/sciadv.aec3961
LA - en
ER -

CSL-JSON

{
"id": "10.1126/sciadv.aec3961",
"type": "article-journal",
"title": "Linking functional and structural dendritic spine remodeling during fear learning and extinction in vivo",
"container-title": "Science advances",
"author": [
{
"family": "Li",
"given": "Xiaoyang"
},
{
"family": "Zheng",
"given": "Qiyu"
},
{
"family": "Wong",
"given": "Kim Hoi Kin"
},
{
"family": "Wong",
"given": "Kenneth Kin Yip"
},
{
"family": "Lai",
"given": "Cora Sau Wan"
}
],
"container-title-short": "Sci Adv",
"volume": "12",
"issue": "29",
"page": "eaec3961",
"DOI": "10.1126/sciadv.aec3961",
"PMID": "42467781",
"PMCID": "PMC13378561",
"ISSN": "2375-2548",
"publisher": "American Association for the Advancement of Science",
"URL": "https://doi.org/10.1126/sciadv.aec3961",
"language": "en",
"issued": {
"date-parts": [
[
2026,
7,
17
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.1016/j.celrep.2026.117793 [code]
Clustered inputs engage dendritic nonlinearities and calcium signaling to support efficient place-field formation in CA1 pyramidal neurons.
Journal: Cell reports
In common: NEURON, pandas, SciPy, 2 other tools, 14 references
[2] doi:10.1016/j.isci.2026.117010 [code]
Deep learning-assisted mapping of dendritic spines using sequential 2D two-photon calcium imaging.
Journal: iScience
In common: pandas, SciPy, Matplotlib, 1 other tool, histology / microscopy, 9 references
[3] doi:10.1038/s41467-026-77800-w [code]
Learning reorganizes dendritic and stabilizes axon initial segment inhibitory synapses in CA1 pyramidal neurons.
Journal: Nature communications
In common: mouse, 8 references
[4] doi:10.1126/sciadv.adz4123 [code]
Highly attenuated dendritic propagation of isolated synaptic potentials in vivo.
Journal: Science advances
In common: mouse, 8 references
[5] doi:10.7554/elife.108352 [code]
Analysis of dendritic input currents during place field dynamics.
Journal: eLife
In common: NEURON, pandas, Matplotlib, 1 other tool, 5 references
[6] doi:10.7554/elife.89629 [code]
Active dendrites enable robust spiking computations despite timing jitter.
Journal: eLife
In common: NEURON, pandas, Matplotlib, 1 other tool, 5 references
[7] doi:10.1073/pnas.2533168123 [code]
Dendritic morphology and synaptic nonlinearities enhance functional complexity in human cortical neurons.
Journal: Proceedings of the National Academy of Sciences of the United States of America
In common: NEURON, pandas, SciPy, 2 other tools, 4 references
[8] doi:10.7554/elife.111876 [code]
Distinct sensorimotor encoding in tuft dendrites and somata associated with action, correction, and learning.
Journal: eLife
In common: Pillow, pandas, SciPy, 2 other tools, mouse, 3 references
[9] doi:10.7554/elife.95562 [code]
Spatially targeted inhibitory rhythms differentially affect neuronal integration.
Journal: eLife
In common: pandas, SciPy, Matplotlib, 1 other tool, 4 references
[10] doi: [code]
Going deeper with morphologically detailed neural networks by simulation-based gradient propagation
Journal: Frontiers in computational neuroscience
In common: NEURON, SciPy, Matplotlib, 1 other tool, 3 references

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.

Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.