bmtool 0.6.1__tar.gz → 0.6.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bmtool-0.6.1 → bmtool-0.6.3}/PKG-INFO +16 -4
- {bmtool-0.6.1 → bmtool-0.6.3}/README.md +5 -2
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool/SLURM.py +26 -22
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool/bmplot.py +0 -1
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool/synapses.py +203 -90
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool.egg-info/PKG-INFO +16 -4
- {bmtool-0.6.1 → bmtool-0.6.3}/setup.py +3 -2
- {bmtool-0.6.1 → bmtool-0.6.3}/LICENSE +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool/__init__.py +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool/__main__.py +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool/connectors.py +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool/debug/__init__.py +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool/debug/commands.py +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool/debug/debug.py +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool/graphs.py +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool/manage.py +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool/plot_commands.py +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool/singlecell.py +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool/util/__init__.py +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool/util/commands.py +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool/util/neuron/__init__.py +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool/util/neuron/celltuner.py +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool/util/util.py +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool.egg-info/SOURCES.txt +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool.egg-info/dependency_links.txt +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool.egg-info/entry_points.txt +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool.egg-info/requires.txt +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/bmtool.egg-info/top_level.txt +0 -0
- {bmtool-0.6.1 → bmtool-0.6.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: bmtool
|
3
|
-
Version: 0.6.
|
3
|
+
Version: 0.6.3
|
4
4
|
Summary: BMTool
|
5
5
|
Home-page: https://github.com/cyneuro/bmtool
|
6
6
|
Download-URL:
|
@@ -31,6 +31,15 @@ Requires-Dist: pynmodlt
|
|
31
31
|
Requires-Dist: xarray
|
32
32
|
Requires-Dist: fooof
|
33
33
|
Requires-Dist: requests
|
34
|
+
Dynamic: author
|
35
|
+
Dynamic: author-email
|
36
|
+
Dynamic: classifier
|
37
|
+
Dynamic: description
|
38
|
+
Dynamic: description-content-type
|
39
|
+
Dynamic: home-page
|
40
|
+
Dynamic: license
|
41
|
+
Dynamic: requires-dist
|
42
|
+
Dynamic: summary
|
34
43
|
|
35
44
|
# bmtool
|
36
45
|
A collection of modules to make developing [Neuron](https://www.neuron.yale.edu/neuron/) and [BMTK](https://alleninstitute.github.io/bmtk/) models easier.
|
@@ -44,6 +53,7 @@ A collection of modules to make developing [Neuron](https://www.neuron.yale.edu/
|
|
44
53
|
- [Synapses](#synapses-module)
|
45
54
|
- [Connectors](#connectors-module)
|
46
55
|
- [Bmplot](#bmplot-module)
|
56
|
+
- [SLURM](#slurm-module)
|
47
57
|
- [Graphs](#graphs-module)
|
48
58
|
|
49
59
|
## Getting Started
|
@@ -338,9 +348,10 @@ ex: [https://github.com/tjbanks/two-cell-hco](https://github.com/tjbanks/two-cel
|
|
338
348
|
|
339
349
|
### Synapses Module
|
340
350
|
-[SynapticTuner](#synaptictuner)
|
351
|
+
-Gap Junction tuner
|
341
352
|
|
342
353
|
#### SynapticTuner - Aids in the tuning of synapses by printing out synaptic properties and giving the user sliders in a Jupyter notebook to tune the synapse. For more info view the example [here](examples/synapses/synaptic_tuner.ipynb)
|
343
|
-
|
354
|
+
#### GapJunctionTuner - Provides jupyter sliders to tune for coupling coefficient in a similar style to the SynapticTuner an example can be viewed [here](examples/synapses/gap_junction_tuner.ipynb)
|
344
355
|
|
345
356
|
### Connectors Module
|
346
357
|
- [UnidirectionConnector](#unidirectional-connector---unidirectional-connections-in-bmtk-network-model-with-given-probability-within-a-single-population-or-between-two-populations)
|
@@ -459,7 +470,8 @@ bmplot.plot_network_graph(config='config.json',sources='LA',targets='LA',tids='p
|
|
459
470
|
|
460
471
|

|
461
472
|
|
462
|
-
|
473
|
+
## SLURM Module
|
474
|
+
### This is an extremely helpful module that can simplify using SLURM too submit your models. There is also features to enable doing a seedSweep. This will vary the parameters of the simulation and make tuning the model easier. An example can be found [here](examples/SLURM/using_BlockRunner.ipynb)
|
463
475
|
|
464
476
|
|
465
477
|
## Graphs Module
|
@@ -10,6 +10,7 @@ A collection of modules to make developing [Neuron](https://www.neuron.yale.edu/
|
|
10
10
|
- [Synapses](#synapses-module)
|
11
11
|
- [Connectors](#connectors-module)
|
12
12
|
- [Bmplot](#bmplot-module)
|
13
|
+
- [SLURM](#slurm-module)
|
13
14
|
- [Graphs](#graphs-module)
|
14
15
|
|
15
16
|
## Getting Started
|
@@ -304,9 +305,10 @@ ex: [https://github.com/tjbanks/two-cell-hco](https://github.com/tjbanks/two-cel
|
|
304
305
|
|
305
306
|
### Synapses Module
|
306
307
|
-[SynapticTuner](#synaptictuner)
|
308
|
+
-Gap Junction tuner
|
307
309
|
|
308
310
|
#### SynapticTuner - Aids in the tuning of synapses by printing out synaptic properties and giving the user sliders in a Jupyter notebook to tune the synapse. For more info view the example [here](examples/synapses/synaptic_tuner.ipynb)
|
309
|
-
|
311
|
+
#### GapJunctionTuner - Provides jupyter sliders to tune for coupling coefficient in a similar style to the SynapticTuner an example can be viewed [here](examples/synapses/gap_junction_tuner.ipynb)
|
310
312
|
|
311
313
|
### Connectors Module
|
312
314
|
- [UnidirectionConnector](#unidirectional-connector---unidirectional-connections-in-bmtk-network-model-with-given-probability-within-a-single-population-or-between-two-populations)
|
@@ -425,7 +427,8 @@ bmplot.plot_network_graph(config='config.json',sources='LA',targets='LA',tids='p
|
|
425
427
|
|
426
428
|

|
427
429
|
|
428
|
-
|
430
|
+
## SLURM Module
|
431
|
+
### This is an extremely helpful module that can simplify using SLURM too submit your models. There is also features to enable doing a seedSweep. This will vary the parameters of the simulation and make tuning the model easier. An example can be found [here](examples/SLURM/using_BlockRunner.ipynb)
|
429
432
|
|
430
433
|
|
431
434
|
## Graphs Module
|
@@ -379,32 +379,36 @@ class BlockRunner:
|
|
379
379
|
if self.webhook:
|
380
380
|
message = "SIMULATION UPDATE: Simulations have been submited in parallel!"
|
381
381
|
send_teams_message(self.webhook,message)
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
382
|
+
if self.param_values == None:
|
383
|
+
print(f"skipping json editing for block {block.block_name}",flush=True)
|
384
|
+
else:
|
385
|
+
for i, block in enumerate(self.blocks):
|
386
|
+
if block.component_path == None:
|
387
|
+
raise Exception("Unable to use parallel submitter without defining the component path")
|
388
|
+
new_value = self.param_values[i]
|
389
|
+
|
390
|
+
source_dir = block.component_path
|
391
|
+
destination_dir = f"{source_dir}{i+1}"
|
392
|
+
block.component_path = destination_dir
|
393
|
+
|
394
|
+
shutil.copytree(source_dir, destination_dir) # create new components folder
|
395
|
+
json_file_path = os.path.join(destination_dir,self.json_file_path)
|
396
|
+
if self.syn_dict_list == None:
|
397
|
+
json_editor = seedSweep(json_file_path, self.param_name)
|
398
|
+
json_editor.edit_json(new_value)
|
399
|
+
else:
|
400
|
+
json_editor = multiSeedSweep(json_file_path,self.param_name,
|
401
|
+
self.syn_dict_list,base_ratio=1)
|
402
|
+
json_editor.edit_all_jsons(new_value)
|
400
403
|
|
401
404
|
# submit block with new component path
|
402
405
|
print(f"Submitting block: {block.block_name}", flush=True)
|
403
406
|
block.submit_block()
|
404
|
-
if i == len(self.blocks) - 1:
|
405
|
-
|
406
|
-
|
407
|
-
|
407
|
+
if i == len(self.blocks) - 1:
|
408
|
+
if self.webook:
|
409
|
+
while not block.check_block_completed():
|
410
|
+
print(f"Waiting for the last block {i} to complete...")
|
411
|
+
time.sleep(self.check_interval)
|
408
412
|
|
409
413
|
if self.webhook:
|
410
414
|
message = "SIMULATION UPDATE: Simulations are Done!"
|
@@ -46,13 +46,14 @@ class SynapseTuner:
|
|
46
46
|
self.conn_type_settings = conn_type_settings
|
47
47
|
if json_folder_path:
|
48
48
|
print(f"updating settings from json path {json_folder_path}")
|
49
|
-
self.
|
49
|
+
self._update_spec_syn_param(json_folder_path)
|
50
50
|
self.general_settings = general_settings
|
51
51
|
self.conn = self.conn_type_settings[connection]
|
52
52
|
self.synaptic_props = self.conn['spec_syn_param']
|
53
53
|
self.vclamp = general_settings['vclamp']
|
54
54
|
self.current_name = current_name
|
55
55
|
self.other_vars_to_record = other_vars_to_record
|
56
|
+
self.ispk = None
|
56
57
|
|
57
58
|
if slider_vars:
|
58
59
|
# Start by filtering based on keys in slider_vars
|
@@ -63,10 +64,10 @@ class SynapseTuner:
|
|
63
64
|
if key not in self.synaptic_props:
|
64
65
|
try:
|
65
66
|
# Get the alternative value from getattr dynamically
|
66
|
-
self.
|
67
|
-
self.
|
67
|
+
self._set_up_cell()
|
68
|
+
self._set_up_synapse()
|
68
69
|
value = getattr(self.syn,key)
|
69
|
-
print(value)
|
70
|
+
#print(value)
|
70
71
|
self.slider_vars[key] = value
|
71
72
|
except AttributeError as e:
|
72
73
|
print(f"Error accessing '{key}' in syn {self.syn}: {e}")
|
@@ -80,7 +81,7 @@ class SynapseTuner:
|
|
80
81
|
h.steps_per_ms = 1 / h.dt
|
81
82
|
h.celsius = general_settings['celsius']
|
82
83
|
|
83
|
-
def
|
84
|
+
def _update_spec_syn_param(self, json_folder_path):
|
84
85
|
"""
|
85
86
|
Update specific synaptic parameters using JSON files located in the specified folder.
|
86
87
|
|
@@ -99,20 +100,20 @@ class SynapseTuner:
|
|
99
100
|
print(f"JSON file for {conn_type} not found.")
|
100
101
|
|
101
102
|
|
102
|
-
def
|
103
|
+
def _set_up_cell(self):
|
103
104
|
"""
|
104
105
|
Set up the neuron cell based on the specified connection settings.
|
105
106
|
"""
|
106
107
|
self.cell = getattr(h, self.conn['spec_settings']['post_cell'])()
|
107
108
|
|
108
109
|
|
109
|
-
def
|
110
|
+
def _set_up_synapse(self):
|
110
111
|
"""
|
111
112
|
Set up the synapse on the target cell according to the synaptic parameters in `conn_type_settings`.
|
112
113
|
|
113
114
|
Notes:
|
114
115
|
------
|
115
|
-
- `
|
116
|
+
- `_set_up_cell()` should be called before setting up the synapse.
|
116
117
|
- Synapse location, type, and properties are specified within `spec_syn_param` and `spec_settings`.
|
117
118
|
"""
|
118
119
|
self.syn = getattr(h, self.conn['spec_settings']['level_of_detail'])(list(self.cell.all)[self.conn['spec_settings']['sec_id']](self.conn['spec_settings']['sec_x']))
|
@@ -124,7 +125,7 @@ class SynapseTuner:
|
|
124
125
|
print(f"Warning: {key} cannot be assigned as it does not exist in the synapse. Check your mod file or spec_syn_param.")
|
125
126
|
|
126
127
|
|
127
|
-
def
|
128
|
+
def _set_up_recorders(self):
|
128
129
|
"""
|
129
130
|
Set up recording vectors to capture simulation data.
|
130
131
|
|
@@ -171,8 +172,8 @@ class SynapseTuner:
|
|
171
172
|
and then runs the NEURON simulation for a single event. The single synaptic event will occur at general_settings['tstart']
|
172
173
|
Will display graphs and synaptic properies works best with a jupyter notebook
|
173
174
|
"""
|
174
|
-
self.
|
175
|
-
self.
|
175
|
+
self._set_up_cell()
|
176
|
+
self._set_up_synapse()
|
176
177
|
|
177
178
|
# Set up the stimulus
|
178
179
|
self.nstim = h.NetStim()
|
@@ -191,7 +192,7 @@ class SynapseTuner:
|
|
191
192
|
self.vcl.amp[i] = self.conn['spec_settings']['vclamp_amp']
|
192
193
|
self.vcl.dur[i] = vcldur[1][i]
|
193
194
|
|
194
|
-
self.
|
195
|
+
self._set_up_recorders()
|
195
196
|
|
196
197
|
# Run simulation
|
197
198
|
h.tstop = self.general_settings['tstart'] + self.general_settings['tdur']
|
@@ -199,13 +200,13 @@ class SynapseTuner:
|
|
199
200
|
self.nstim.number = 1
|
200
201
|
self.nstim2.start = h.tstop
|
201
202
|
h.run()
|
202
|
-
self.
|
203
|
-
syn_props = self.
|
203
|
+
self._plot_model([self.general_settings['tstart'] - 5, self.general_settings['tstart'] + self.general_settings['tdur']])
|
204
|
+
syn_props = self._get_syn_prop(rise_interval=self.general_settings['rise_interval'])
|
204
205
|
for prop in syn_props.items():
|
205
206
|
print(prop)
|
206
207
|
|
207
208
|
|
208
|
-
def
|
209
|
+
def _find_first(self, x):
|
209
210
|
"""
|
210
211
|
Find the index of the first non-zero element in a given array.
|
211
212
|
|
@@ -224,7 +225,7 @@ class SynapseTuner:
|
|
224
225
|
return idx[0] if idx.size else None
|
225
226
|
|
226
227
|
|
227
|
-
def
|
228
|
+
def _get_syn_prop(self, rise_interval=(0.2, 0.8), dt=h.dt, short=False):
|
228
229
|
"""
|
229
230
|
Calculate synaptic properties such as peak amplitude, latency, rise time, decay time, and half-width.
|
230
231
|
|
@@ -269,22 +270,22 @@ class SynapseTuner:
|
|
269
270
|
ipk = ipk[0]
|
270
271
|
peak = isyn[ipk]
|
271
272
|
# latency
|
272
|
-
istart = self.
|
273
|
+
istart = self._find_first(np.diff(isyn[:ipk + 1]) > 0)
|
273
274
|
latency = dt * (istart + 1)
|
274
275
|
# rise time
|
275
|
-
rt1 = self.
|
276
|
-
rt2 = self.
|
276
|
+
rt1 = self._find_first(isyn[istart:ipk + 1] > rise_interval[0] * peak)
|
277
|
+
rt2 = self._find_first(isyn[istart:ipk + 1] > rise_interval[1] * peak)
|
277
278
|
rise_time = (rt2 - rt1) * dt
|
278
279
|
# decay time
|
279
|
-
iend = self.
|
280
|
+
iend = self._find_first(np.diff(isyn[ipk:]) > 0)
|
280
281
|
iend = isyn.size - 1 if iend is None else iend + ipk
|
281
282
|
decay_len = iend - ipk + 1
|
282
283
|
popt, _ = curve_fit(lambda t, a, tau: a * np.exp(-t / tau), dt * np.arange(decay_len),
|
283
284
|
isyn[ipk:iend + 1], p0=(peak, dt * decay_len / 2))
|
284
285
|
decay_time = popt[1]
|
285
286
|
# half-width
|
286
|
-
hw1 = self.
|
287
|
-
hw2 = self.
|
287
|
+
hw1 = self._find_first(isyn[istart:ipk + 1] > 0.5 * peak)
|
288
|
+
hw2 = self._find_first(isyn[ipk:] < 0.5 * peak)
|
288
289
|
hw2 = isyn.size if hw2 is None else hw2 + ipk
|
289
290
|
half_width = dt * (hw2 - hw1)
|
290
291
|
output = {'baseline': baseline, 'sign': sign, 'latency': latency,
|
@@ -292,7 +293,7 @@ class SynapseTuner:
|
|
292
293
|
return output
|
293
294
|
|
294
295
|
|
295
|
-
def
|
296
|
+
def _plot_model(self, xlim):
|
296
297
|
"""
|
297
298
|
Plots the results of the simulation, including synaptic current, soma voltage,
|
298
299
|
and any additional recorded variables.
|
@@ -319,6 +320,11 @@ class SynapseTuner:
|
|
319
320
|
|
320
321
|
# Plot synaptic current (always included)
|
321
322
|
axs[0].plot(self.t, 1000 * self.rec_vectors[self.current_name])
|
323
|
+
if self.ispk !=None:
|
324
|
+
for num in range(len(self.ispk)):
|
325
|
+
current = 1000 * np.array(self.rec_vectors[self.current_name].to_python())
|
326
|
+
axs[0].text(self.t[self.ispk[num]],current[self.ispk[num]],f"{str(num+1)}")
|
327
|
+
|
322
328
|
axs[0].set_ylabel('Synaptic Current (pA)')
|
323
329
|
|
324
330
|
# Plot voltage clamp or soma voltage (always included)
|
@@ -332,6 +338,7 @@ class SynapseTuner:
|
|
332
338
|
else:
|
333
339
|
soma_v_plt = np.array(self.soma_v)
|
334
340
|
soma_v_plt[:ispk] = soma_v_plt[ispk]
|
341
|
+
|
335
342
|
axs[1].plot(self.t, soma_v_plt)
|
336
343
|
axs[1].set_ylabel('Soma Voltage (mV)')
|
337
344
|
|
@@ -353,11 +360,11 @@ class SynapseTuner:
|
|
353
360
|
for j in range(num_vars_to_plot, len(axs)):
|
354
361
|
fig.delaxes(axs[j])
|
355
362
|
|
356
|
-
plt.tight_layout()
|
363
|
+
#plt.tight_layout()
|
357
364
|
plt.show()
|
358
365
|
|
359
366
|
|
360
|
-
def
|
367
|
+
def _set_drive_train(self,freq=50., delay=250.):
|
361
368
|
"""
|
362
369
|
Configures trains of 12 action potentials at a specified frequency and delay period
|
363
370
|
between pulses 8 and 9.
|
@@ -390,7 +397,7 @@ class SynapseTuner:
|
|
390
397
|
return tstop
|
391
398
|
|
392
399
|
|
393
|
-
def
|
400
|
+
def _response_amplitude(self):
|
394
401
|
"""
|
395
402
|
Calculates the amplitude of the synaptic response by analyzing the recorded synaptic current.
|
396
403
|
|
@@ -402,17 +409,25 @@ class SynapseTuner:
|
|
402
409
|
"""
|
403
410
|
isyn = np.asarray(self.rec_vectors['i'])
|
404
411
|
tspk = np.append(np.asarray(self.tspk), h.tstop)
|
405
|
-
syn_prop = self.
|
412
|
+
syn_prop = self._get_syn_prop(short=True)
|
406
413
|
# print("syn_prp[sign] = " + str(syn_prop['sign']))
|
407
414
|
isyn = (isyn - syn_prop['baseline'])
|
408
415
|
isyn *= syn_prop['sign']
|
409
|
-
# print(isyn)
|
410
416
|
ispk = np.floor((tspk + self.general_settings['delay']) / h.dt).astype(int)
|
411
|
-
|
417
|
+
|
418
|
+
try:
|
419
|
+
amp = [isyn[ispk[i]:ispk[i + 1]].max() for i in range(ispk.size - 1)]
|
420
|
+
# indexs of where the max of the synaptic current is at. This is then plotted
|
421
|
+
self.ispk = [np.argmax(isyn[ispk[i]:ispk[i + 1]]) + ispk[i] for i in range(ispk.size - 1)]
|
422
|
+
# Sometimes the sim can cutoff at the peak of synaptic activity. So we just reduce the range by 1 and ingore that point
|
423
|
+
except:
|
424
|
+
amp = [isyn[ispk[i]:ispk[i + 1]].max() for i in range(ispk.size - 2)]
|
425
|
+
self.ispk = [np.argmax(isyn[ispk[i]:ispk[i + 1]]) + ispk[i] for i in range(ispk.size - 2)]
|
426
|
+
|
412
427
|
return amp
|
413
428
|
|
414
429
|
|
415
|
-
def
|
430
|
+
def _find_max_amp(self, amp, normalize_by_trial=True):
|
416
431
|
"""
|
417
432
|
Determines the maximum amplitude from the response data.
|
418
433
|
|
@@ -435,7 +450,7 @@ class SynapseTuner:
|
|
435
450
|
return max_amp
|
436
451
|
|
437
452
|
|
438
|
-
def
|
453
|
+
def _print_ppr_induction_recovery(self,amp, normalize_by_trial=True):
|
439
454
|
"""
|
440
455
|
Calculates induction and recovery metrics from the synaptic response amplitudes.
|
441
456
|
|
@@ -457,54 +472,48 @@ class SynapseTuner:
|
|
457
472
|
"""
|
458
473
|
amp = np.array(amp)
|
459
474
|
amp = amp.reshape(-1, amp.shape[-1])
|
475
|
+
maxamp = amp.max(axis=1 if normalize_by_trial else None)
|
476
|
+
|
477
|
+
# functions used to round array to 2 sig figs
|
478
|
+
def format_value(x):
|
479
|
+
return f"{x:.2g}"
|
480
|
+
|
481
|
+
# Function to apply format_value to an entire array
|
482
|
+
def format_array(arr):
|
483
|
+
# Flatten the array and format each element
|
484
|
+
return ' '.join([format_value(x) for x in arr.flatten()])
|
460
485
|
|
486
|
+
print("Short Term Plasticity")
|
487
|
+
print("PPR: above 1 is facilitating below 1 is depressing")
|
488
|
+
print("Induction: above 0 is facilitating below 0 is depressing")
|
489
|
+
print("Recovery: measure of how fast STP decays")
|
490
|
+
print("")
|
461
491
|
|
462
|
-
|
492
|
+
ppr = amp[:,1:2] / amp[:,0:1]
|
493
|
+
print(f"Paired Pulse Response Calculation: 2nd pulse / 1st pulse ")
|
494
|
+
print(f"{format_array(amp[:,1:2])} - {format_array(amp[:,0:1])} = {format_array(ppr)}")
|
495
|
+
print("")
|
496
|
+
|
463
497
|
induction = np.mean((amp[:, 5:8].mean(axis=1) - amp[:, :1].mean(axis=1)) / maxamp)
|
498
|
+
print(f"Induction Calculation: (avg(6,7,8 pulses) - 1 pulse) / max amps")
|
499
|
+
# Format and print arrays with 2 significant figures
|
500
|
+
print(f"{format_array(amp[:, 5:8])} - {format_array(amp[:, :1])} / {format_array(maxamp)}")
|
501
|
+
print(f"{format_array(amp[:, 5:8].mean(axis=1))} - {format_array(amp[:, :1].mean(axis=1))} / {format_array(maxamp)} = {format_array(induction)}")
|
502
|
+
print("")
|
503
|
+
|
464
504
|
recovery = np.mean((amp[:, 8:12].mean(axis=1) - amp[:, :4].mean(axis=1)) / maxamp)
|
505
|
+
print("Recovery Calculation: avg(9,10,11,12 pulses) - avg(1,2,3,4 pulses) / max amps")
|
506
|
+
print(f"{format_array(amp[:, 8:12])} - {format_array(amp[:, :4])} / {format_array(maxamp)}")
|
507
|
+
print(f"{format_array(amp[:, 8:12].mean(axis=1))} - {format_array(amp[:, :4].mean(axis=1))} / {format_array(maxamp)} = {format_array(recovery)}")
|
508
|
+
print("")
|
465
509
|
|
510
|
+
|
466
511
|
# maxamp = max(amp, key=lambda x: abs(x[0]))
|
467
512
|
maxamp = maxamp.max()
|
468
|
-
return induction, recovery, maxamp
|
513
|
+
#return induction, recovery, maxamp
|
469
514
|
|
470
515
|
|
471
|
-
def
|
472
|
-
"""
|
473
|
-
Computes the paired-pulse ratio (PPR) based on the recorded synaptic current or voltage.
|
474
|
-
|
475
|
-
Parameters:
|
476
|
-
-----------
|
477
|
-
dt : float, optional
|
478
|
-
Time step in milliseconds. Default is the NEURON simulation time step.
|
479
|
-
|
480
|
-
Returns:
|
481
|
-
--------
|
482
|
-
ppr : float
|
483
|
-
The ratio between the second and first pulse amplitudes.
|
484
|
-
|
485
|
-
Notes:
|
486
|
-
------
|
487
|
-
- The function handles both voltage-clamp and current-clamp conditions.
|
488
|
-
- A minimum of two spikes is required to calculate PPR.
|
489
|
-
"""
|
490
|
-
if self.vclamp:
|
491
|
-
isyn = self.ivcl
|
492
|
-
else:
|
493
|
-
isyn = self.rec_vectors['i']
|
494
|
-
isyn = np.asarray(isyn)
|
495
|
-
tspk = np.asarray(self.tspk)
|
496
|
-
if tspk.size < 2:
|
497
|
-
raise ValueError("Need at least two spikes.")
|
498
|
-
syn_prop = self.get_syn_prop()
|
499
|
-
isyn = (isyn - syn_prop['baseline']) * syn_prop['sign']
|
500
|
-
ispk2 = int(np.floor(tspk[1] / dt))
|
501
|
-
ipk, _ = find_peaks(isyn[ispk2:])
|
502
|
-
ipk2 = ipk[0] + ispk2
|
503
|
-
peak2 = isyn[ipk2]
|
504
|
-
return peak2 / syn_prop['amp']
|
505
|
-
|
506
|
-
|
507
|
-
def set_syn_prop(self, **kwargs):
|
516
|
+
def _set_syn_prop(self, **kwargs):
|
508
517
|
"""
|
509
518
|
Sets the synaptic parameters based on user inputs from sliders.
|
510
519
|
|
@@ -517,7 +526,7 @@ class SynapseTuner:
|
|
517
526
|
setattr(self.syn, key, value)
|
518
527
|
|
519
528
|
|
520
|
-
def
|
529
|
+
def _simulate_model(self,input_frequency, delay, vclamp=None):
|
521
530
|
"""
|
522
531
|
Runs the simulation with the specified input frequency, delay, and voltage clamp settings.
|
523
532
|
|
@@ -532,7 +541,7 @@ class SynapseTuner:
|
|
532
541
|
|
533
542
|
"""
|
534
543
|
if self.input_mode == False:
|
535
|
-
self.tstop = self.
|
544
|
+
self.tstop = self._set_drive_train(input_frequency, delay)
|
536
545
|
h.tstop = self.tstop
|
537
546
|
|
538
547
|
vcldur = [[0, 0, 0], [self.general_settings['tstart'], self.tstop, 1e9]]
|
@@ -556,13 +565,9 @@ class SynapseTuner:
|
|
556
565
|
"""
|
557
566
|
Sets up interactive sliders for short-term plasticity (STP) experiments in a Jupyter Notebook.
|
558
567
|
|
559
|
-
Notes:
|
560
|
-
------
|
561
|
-
- The sliders allow control over synaptic properties dynamically based on slider_vars.
|
562
|
-
- Additional buttons allow running the simulation and configuring voltage clamp settings.
|
563
568
|
"""
|
564
569
|
# Widgets setup (Sliders)
|
565
|
-
freqs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 50, 100, 200]
|
570
|
+
freqs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 35, 50, 100, 200]
|
566
571
|
delays = [125, 250, 500, 1000, 2000, 4000]
|
567
572
|
durations = [300, 500, 1000, 2000, 5000, 10000]
|
568
573
|
freq0 = 50
|
@@ -602,19 +607,17 @@ class SynapseTuner:
|
|
602
607
|
self.input_mode = w_input_mode.value
|
603
608
|
# Update synaptic properties based on slider values
|
604
609
|
syn_props = {var: slider.value for var, slider in dynamic_sliders.items()}
|
605
|
-
self.
|
610
|
+
self._set_syn_prop(**syn_props)
|
606
611
|
if self.input_mode == False:
|
607
|
-
self.
|
612
|
+
self._simulate_model(w_input_freq.value, self.w_delay.value, w_vclamp.value)
|
608
613
|
else:
|
609
|
-
self.
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
print('
|
615
|
-
print('
|
616
|
-
print(f'Induction: {induction_single:.2f}; Recovery: {recovery:.2f}')
|
617
|
-
print(f'Rest Amp: {amp[0]:.2f}; Maximum Amp: {maxamp:.2f}')
|
614
|
+
self._simulate_model(w_input_freq.value, self.w_duration.value, w_vclamp.value)
|
615
|
+
amp = self._response_amplitude()
|
616
|
+
self._plot_model([self.general_settings['tstart'] - self.nstim.interval / 3, self.tstop])
|
617
|
+
self._print_ppr_induction_recovery(amp)
|
618
|
+
# print('Single trial ' + ('PSC' if self.vclamp else 'PSP'))
|
619
|
+
# print(f'Induction: {induction_single:.2f}; Recovery: {recovery:.2f}')
|
620
|
+
#print(f'Rest Amp: {amp[0]:.2f}; Maximum Amp: {maxamp:.2f}')
|
618
621
|
|
619
622
|
# Function to switch between delay and duration sliders
|
620
623
|
def switch_slider(*args):
|
@@ -628,7 +631,7 @@ class SynapseTuner:
|
|
628
631
|
# Link input mode to slider switch
|
629
632
|
w_input_mode.observe(switch_slider, names='value')
|
630
633
|
|
631
|
-
# Hide the duration slider initially
|
634
|
+
# Hide the duration slider initially until the user selects it
|
632
635
|
self.w_duration.layout.display = 'none' # Hide duration slider
|
633
636
|
|
634
637
|
w_run.on_click(update_ui)
|
@@ -647,6 +650,116 @@ class SynapseTuner:
|
|
647
650
|
ui = VBox([HBox([w_run, w_vclamp, w_input_mode]), HBox([w_input_freq, self.w_delay, self.w_duration]), slider_columns])
|
648
651
|
|
649
652
|
display(ui)
|
653
|
+
# run model with default parameters
|
654
|
+
update_ui()
|
655
|
+
|
656
|
+
class GapJunctionTuner:
|
657
|
+
def __init__(self, mechanisms_dir: str, templates_dir: str, general_settings: dict, conn_type_settings: dict):
|
658
|
+
neuron.load_mechanisms(mechanisms_dir)
|
659
|
+
h.load_file(templates_dir)
|
660
|
+
|
661
|
+
self.general_settings = general_settings
|
662
|
+
self.conn_type_settings = conn_type_settings
|
663
|
+
|
664
|
+
h.tstop = general_settings['tstart'] + general_settings['tdur'] + 100.
|
665
|
+
h.dt = general_settings['dt'] # Time step (resolution) of the simulation in ms
|
666
|
+
h.steps_per_ms = 1 / h.dt
|
667
|
+
h.celsius = general_settings['celsius']
|
668
|
+
|
669
|
+
self.cell_name = conn_type_settings['cell']
|
670
|
+
|
671
|
+
# set up gap junctions
|
672
|
+
pc = h.ParallelContext()
|
673
|
+
|
674
|
+
self.cell1 = getattr(h, self.cell_name)()
|
675
|
+
self.cell2 = getattr(h, self.cell_name)()
|
676
|
+
|
677
|
+
self.icl = h.IClamp(self.cell1.soma[0](0.5))
|
678
|
+
self.icl.delay = self.general_settings['tstart']
|
679
|
+
self.icl.dur = self.general_settings['tdur']
|
680
|
+
self.icl.amp = self.conn_type_settings['iclamp_amp'] # nA
|
681
|
+
|
682
|
+
sec1 = list(self.cell1.all)[conn_type_settings['sec_id']]
|
683
|
+
sec2 = list(self.cell2.all)[conn_type_settings['sec_id']]
|
650
684
|
|
685
|
+
pc.source_var(sec1(conn_type_settings['sec_x'])._ref_v, 0, sec=sec1)
|
686
|
+
self.gap_junc_1 = h.Gap(sec1(0.5))
|
687
|
+
pc.target_var(self.gap_junc_1 ._ref_vgap, 1)
|
651
688
|
|
652
|
-
|
689
|
+
pc.source_var(sec2(conn_type_settings['sec_x'])._ref_v, 1, sec=sec2)
|
690
|
+
self.gap_junc_2 = h.Gap(sec2(0.5))
|
691
|
+
pc.target_var(self.gap_junc_2._ref_vgap, 0)
|
692
|
+
|
693
|
+
pc.setup_transfer()
|
694
|
+
|
695
|
+
def model(self,resistance):
|
696
|
+
|
697
|
+
self.gap_junc_1.g = resistance
|
698
|
+
self.gap_junc_2.g = resistance
|
699
|
+
|
700
|
+
t_vec = h.Vector()
|
701
|
+
soma_v_1 = h.Vector()
|
702
|
+
soma_v_2 = h.Vector()
|
703
|
+
t_vec.record(h._ref_t)
|
704
|
+
soma_v_1.record(self.cell1.soma[0](0.5)._ref_v)
|
705
|
+
soma_v_2.record(self.cell2.soma[0](0.5)._ref_v)
|
706
|
+
|
707
|
+
self.t_vec = t_vec
|
708
|
+
self.soma_v_1 = soma_v_1
|
709
|
+
self.soma_v_2 = soma_v_2
|
710
|
+
|
711
|
+
h.finitialize(-70 * mV)
|
712
|
+
h.continuerun(h.tstop * ms)
|
713
|
+
|
714
|
+
|
715
|
+
def plot_model(self):
|
716
|
+
t_range = [self.general_settings['tstart'] - 100., self.general_settings['tstart']+self.general_settings['tdur'] + 100.]
|
717
|
+
t = np.array(self.t_vec)
|
718
|
+
v1 = np.array(self.soma_v_1)
|
719
|
+
v2 = np.array(self.soma_v_2)
|
720
|
+
tidx = (t >= t_range[0]) & (t <= t_range[1])
|
721
|
+
|
722
|
+
plt.figure()
|
723
|
+
plt.plot(t[tidx], v1[tidx], 'b', label=f'{self.cell_name} 1')
|
724
|
+
plt.plot(t[tidx], v2[tidx], 'r', label=f'{self.cell_name} 2')
|
725
|
+
plt.title(f"{self.cell_name} gap junction")
|
726
|
+
plt.xlabel('Time (ms)')
|
727
|
+
plt.ylabel('Membrane Voltage (mV)')
|
728
|
+
plt.legend()
|
729
|
+
plt.show()
|
730
|
+
|
731
|
+
|
732
|
+
def coupling_coefficient(self,t, v1, v2, t_start, t_end, dt=h.dt):
|
733
|
+
t = np.asarray(t)
|
734
|
+
v1 = np.asarray(v1)
|
735
|
+
v2 = np.asarray(v2)
|
736
|
+
idx1 = np.nonzero(t < t_start)[0][-1]
|
737
|
+
idx2 = np.nonzero(t < t_end)[0][-1]
|
738
|
+
return (v2[idx2] - v2[idx1]) / (v1[idx2] - v1[idx1])
|
739
|
+
|
740
|
+
|
741
|
+
def run_model(self):
|
742
|
+
w_run = widgets.Button(description='Run', icon='history', button_style='primary')
|
743
|
+
values = [i * 10**-4 for i in range(1, 101)] # From 1e-4 to 1e-2
|
744
|
+
|
745
|
+
# Create the SelectionSlider widget with appropriate formatting
|
746
|
+
resistance = widgets.SelectionSlider(
|
747
|
+
options=[("%g"%i,i) for i in values], # Use scientific notation for display
|
748
|
+
value=10**-3, # Default value
|
749
|
+
description='Resistance: ',
|
750
|
+
continuous_update=True
|
751
|
+
)
|
752
|
+
|
753
|
+
ui = VBox([w_run,resistance])
|
754
|
+
display(ui)
|
755
|
+
def on_button(*args):
|
756
|
+
clear_output()
|
757
|
+
display(ui)
|
758
|
+
resistance_for_gap = resistance.value
|
759
|
+
self.model(resistance_for_gap)
|
760
|
+
self.plot_model()
|
761
|
+
cc = self.coupling_coefficient(self.t_vec, self.soma_v_1, self.soma_v_2, 500, 1000)
|
762
|
+
print(f"coupling_coefficient is {cc:0.4f}")
|
763
|
+
|
764
|
+
on_button()
|
765
|
+
w_run.on_click(on_button)
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: bmtool
|
3
|
-
Version: 0.6.
|
3
|
+
Version: 0.6.3
|
4
4
|
Summary: BMTool
|
5
5
|
Home-page: https://github.com/cyneuro/bmtool
|
6
6
|
Download-URL:
|
@@ -31,6 +31,15 @@ Requires-Dist: pynmodlt
|
|
31
31
|
Requires-Dist: xarray
|
32
32
|
Requires-Dist: fooof
|
33
33
|
Requires-Dist: requests
|
34
|
+
Dynamic: author
|
35
|
+
Dynamic: author-email
|
36
|
+
Dynamic: classifier
|
37
|
+
Dynamic: description
|
38
|
+
Dynamic: description-content-type
|
39
|
+
Dynamic: home-page
|
40
|
+
Dynamic: license
|
41
|
+
Dynamic: requires-dist
|
42
|
+
Dynamic: summary
|
34
43
|
|
35
44
|
# bmtool
|
36
45
|
A collection of modules to make developing [Neuron](https://www.neuron.yale.edu/neuron/) and [BMTK](https://alleninstitute.github.io/bmtk/) models easier.
|
@@ -44,6 +53,7 @@ A collection of modules to make developing [Neuron](https://www.neuron.yale.edu/
|
|
44
53
|
- [Synapses](#synapses-module)
|
45
54
|
- [Connectors](#connectors-module)
|
46
55
|
- [Bmplot](#bmplot-module)
|
56
|
+
- [SLURM](#slurm-module)
|
47
57
|
- [Graphs](#graphs-module)
|
48
58
|
|
49
59
|
## Getting Started
|
@@ -338,9 +348,10 @@ ex: [https://github.com/tjbanks/two-cell-hco](https://github.com/tjbanks/two-cel
|
|
338
348
|
|
339
349
|
### Synapses Module
|
340
350
|
-[SynapticTuner](#synaptictuner)
|
351
|
+
-Gap Junction tuner
|
341
352
|
|
342
353
|
#### SynapticTuner - Aids in the tuning of synapses by printing out synaptic properties and giving the user sliders in a Jupyter notebook to tune the synapse. For more info view the example [here](examples/synapses/synaptic_tuner.ipynb)
|
343
|
-
|
354
|
+
#### GapJunctionTuner - Provides jupyter sliders to tune for coupling coefficient in a similar style to the SynapticTuner an example can be viewed [here](examples/synapses/gap_junction_tuner.ipynb)
|
344
355
|
|
345
356
|
### Connectors Module
|
346
357
|
- [UnidirectionConnector](#unidirectional-connector---unidirectional-connections-in-bmtk-network-model-with-given-probability-within-a-single-population-or-between-two-populations)
|
@@ -459,7 +470,8 @@ bmplot.plot_network_graph(config='config.json',sources='LA',targets='LA',tids='p
|
|
459
470
|
|
460
471
|

|
461
472
|
|
462
|
-
|
473
|
+
## SLURM Module
|
474
|
+
### This is an extremely helpful module that can simplify using SLURM too submit your models. There is also features to enable doing a seedSweep. This will vary the parameters of the simulation and make tuning the model easier. An example can be found [here](examples/SLURM/using_BlockRunner.ipynb)
|
463
475
|
|
464
476
|
|
465
477
|
## Graphs Module
|
@@ -6,7 +6,7 @@ with open("README.md", "r") as fh:
|
|
6
6
|
|
7
7
|
setup(
|
8
8
|
name="bmtool",
|
9
|
-
version='0.6.
|
9
|
+
version='0.6.3',
|
10
10
|
author="Neural Engineering Laboratory at the University of Missouri",
|
11
11
|
author_email="gregglickert@mail.missouri.edu",
|
12
12
|
description="BMTool",
|
@@ -41,7 +41,8 @@ setup(
|
|
41
41
|
'Topic :: Software Development :: Libraries :: Python Modules',
|
42
42
|
"Operating System :: OS Independent",
|
43
43
|
],
|
44
|
-
packages=find_packages(
|
44
|
+
packages=find_packages(), # Automatically finds all packages
|
45
|
+
include_package_data=True,
|
45
46
|
entry_points={
|
46
47
|
'console_scripts': [
|
47
48
|
'bmtool = bmtool.manage:cli'
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|