bluecellulab 2.6.40__tar.gz → 2.6.42__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.
Potentially problematic release.
This version of bluecellulab might be problematic. Click here for more details.
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/PKG-INFO +2 -1
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/README.rst +1 -0
- bluecellulab-2.6.42/bluecellulab/analysis/analysis.py +177 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/analysis/inject_sequence.py +69 -16
- bluecellulab-2.6.42/bluecellulab/analysis/plotting.py +57 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/cell/core.py +64 -9
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/tools.py +105 -13
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab.egg-info/PKG-INFO +2 -1
- bluecellulab-2.6.40/bluecellulab/analysis/analysis.py +0 -63
- bluecellulab-2.6.40/bluecellulab/analysis/plotting.py +0 -25
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/.compile_mod.sh +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/.gitattributes +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/.github/dependabot.yml +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/.github/workflows/release.yml +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/.github/workflows/test.yml +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/.gitignore +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/.gitlab-ci.yml +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/.readthedocs.yml +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/.zenodo.json +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/AUTHORS.txt +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/CHANGELOG.rst +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/CITATION.cff +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/CONTRIBUTING.rst +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/LICENSE +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/MANIFEST.in +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/Makefile +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/__init__.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/analysis/__init__.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/cell/__init__.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/cell/ballstick/__init__.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/cell/ballstick/emodel.hoc +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/cell/ballstick/morphology.asc +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/cell/cell_dict.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/cell/injector.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/cell/plotting.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/cell/random.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/cell/recording.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/cell/section_distance.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/cell/serialized_sections.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/cell/sonata_proxy.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/cell/stimuli_generator.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/cell/template.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/circuit/__init__.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/circuit/circuit_access/__init__.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/circuit/circuit_access/bluepy_circuit_access.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/circuit/circuit_access/definition.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/circuit/circuit_access/sonata_circuit_access.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/circuit/config/__init__.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/circuit/config/bluepy_simulation_config.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/circuit/config/definition.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/circuit/config/sections.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/circuit/config/sonata_simulation_config.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/circuit/format.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/circuit/iotools.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/circuit/node_id.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/circuit/simulation_access.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/circuit/synapse_properties.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/circuit/validate.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/circuit_simulation.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/connection.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/dendrogram.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/exceptions.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/graph.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/hoc/Cell.hoc +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/hoc/RNGSettings.hoc +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/hoc/TDistFunc.hoc +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/hoc/TStim.hoc +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/hoc/fileUtils.hoc +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/importer.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/neuron_interpreter.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/plotwindow.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/psection.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/psegment.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/rngsettings.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/simulation/__init__.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/simulation/neuron_globals.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/simulation/parallel.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/simulation/simulation.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/stimulus/__init__.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/stimulus/circuit_stimulus_definitions.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/stimulus/factory.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/synapse/__init__.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/synapse/synapse_factory.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/synapse/synapse_types.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/type_aliases.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/utils.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab/verbosity.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab.egg-info/SOURCES.txt +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab.egg-info/dependency_links.txt +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab.egg-info/requires.txt +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/bluecellulab.egg-info/top_level.txt +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/docs/Makefile +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/docs/images/voltage-readme.png +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/docs/make.bat +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/docs/requirements_docs.txt +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/docs/source/_static/.gitkeep +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/docs/source/api.rst +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/docs/source/changelog.rst +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/docs/source/compiling-mechanisms.rst +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/docs/source/conf.py +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/docs/source/contributing.rst +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/docs/source/index.rst +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/docs/source/list_of_stim.rst +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/docs/source/logo/BlueCelluLabBanner.jpg +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/pyproject.toml +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/setup.cfg +0 -0
- {bluecellulab-2.6.40 → bluecellulab-2.6.42}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: bluecellulab
|
|
3
|
-
Version: 2.6.
|
|
3
|
+
Version: 2.6.42
|
|
4
4
|
Summary: Biologically detailed neural network simulations and analysis.
|
|
5
5
|
Author: Blue Brain Project, EPFL
|
|
6
6
|
License: Apache2.0
|
|
@@ -166,6 +166,7 @@ Copyright
|
|
|
166
166
|
=========
|
|
167
167
|
|
|
168
168
|
Copyright (c) 2023-2024 Blue Brain Project/EPFL
|
|
169
|
+
|
|
169
170
|
Copyright (c) 2025 Open Brain Institute
|
|
170
171
|
|
|
171
172
|
This work is licensed under `Apache 2.0 <https://www.apache.org/licenses/LICENSE-2.0.html>`_
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"""Module for analyzing cell simulation results."""
|
|
2
|
+
try:
|
|
3
|
+
import efel
|
|
4
|
+
except ImportError:
|
|
5
|
+
efel = None
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from bluecellulab.stimulus import StimulusFactory
|
|
9
|
+
from bluecellulab.tools import calculate_rheobase
|
|
10
|
+
from bluecellulab.analysis.inject_sequence import run_stimulus
|
|
11
|
+
from bluecellulab.analysis.plotting import plot_iv_curve, plot_fi_curve
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def compute_plot_iv_curve(cell,
|
|
15
|
+
injecting_section="soma[0]",
|
|
16
|
+
injecting_segment=0.5,
|
|
17
|
+
recording_section="soma[0]",
|
|
18
|
+
recording_segment=0.5,
|
|
19
|
+
stim_start=100.0,
|
|
20
|
+
duration=500.0,
|
|
21
|
+
post_delay=100.0,
|
|
22
|
+
threshold_voltage=-30,
|
|
23
|
+
nb_bins=11):
|
|
24
|
+
"""Compute and plot the Current-Voltage (I-V) curve for a given cell by
|
|
25
|
+
injecting a range of currents.
|
|
26
|
+
|
|
27
|
+
This function evaluates the relationship between the injected current amplitude and the resulting
|
|
28
|
+
steady-state membrane potential of a neuronal cell model. Currents are injected at a specified section
|
|
29
|
+
and segment, and the steady-state voltage at the recording location is used to construct the I-V curve.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
cell (bluecellulab.cell.Cell): The initialized BlueCelluLab cell model.
|
|
33
|
+
injecting_section (str, optional): The name of the section where the stimulus is injected.
|
|
34
|
+
Default is "soma[0]".
|
|
35
|
+
injecting_segment (float, optional): The position along the injecting section (0.0 to 1.0)
|
|
36
|
+
where the stimulus is applied. Default is 0.5.
|
|
37
|
+
recording_section (str, optional): The name of the section where the voltage is recorded.
|
|
38
|
+
Default is "soma[0]".
|
|
39
|
+
recording_segment (float, optional): The position along the recording section (0.0 to 1.0)
|
|
40
|
+
where the voltage is recorded. Default is 0.5.
|
|
41
|
+
stim_start (float, optional): The start time of the current injection (in ms). Default is 100.0 ms.
|
|
42
|
+
duration (float, optional): The duration of the current injection (in ms). Default is 500.0 ms.
|
|
43
|
+
post_delay (float, optional): The delay after the stimulation ends before the simulation stops
|
|
44
|
+
(in ms). Default is 100.0 ms.
|
|
45
|
+
threshold_voltage (float, optional): The voltage threshold (in mV) for detecting a steady-state
|
|
46
|
+
response. Default is -30 mV.
|
|
47
|
+
nb_bins (int, optional): The number of discrete current levels between 0 and the maximum current.
|
|
48
|
+
Default is 11.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
tuple: A tuple containing:
|
|
52
|
+
- list_amp (np.ndarray): The injected current amplitudes (nA).
|
|
53
|
+
- steady_states (np.ndarray): The corresponding steady-state voltages (mV) recorded at the
|
|
54
|
+
specified location.
|
|
55
|
+
|
|
56
|
+
Raises:
|
|
57
|
+
ValueError: If the cell object is invalid, the specified sections/segments are not found, or if
|
|
58
|
+
the simulation results are inconsistent.
|
|
59
|
+
"""
|
|
60
|
+
rheobase = calculate_rheobase(cell=cell, section=injecting_section, segx=injecting_segment)
|
|
61
|
+
|
|
62
|
+
list_amp = np.linspace(rheobase - 2, rheobase - 0.1, nb_bins) # [nA]
|
|
63
|
+
|
|
64
|
+
steps = []
|
|
65
|
+
times = []
|
|
66
|
+
voltages = []
|
|
67
|
+
# inject step current and record voltage response
|
|
68
|
+
stim_factory = StimulusFactory(dt=0.1)
|
|
69
|
+
for amp in list_amp:
|
|
70
|
+
step_stimulus = stim_factory.step(pre_delay=stim_start, duration=duration, post_delay=post_delay, amplitude=amp)
|
|
71
|
+
recording = run_stimulus(cell.template_params,
|
|
72
|
+
step_stimulus,
|
|
73
|
+
section=injecting_section,
|
|
74
|
+
segment=injecting_segment,
|
|
75
|
+
recording_section=recording_section,
|
|
76
|
+
recording_segment=recording_segment)
|
|
77
|
+
steps.append(step_stimulus)
|
|
78
|
+
times.append(recording.time)
|
|
79
|
+
voltages.append(recording.voltage)
|
|
80
|
+
|
|
81
|
+
steady_states = []
|
|
82
|
+
# compute steady state response
|
|
83
|
+
efel.set_setting('Threshold', threshold_voltage)
|
|
84
|
+
for voltage, t in zip(voltages, times):
|
|
85
|
+
trace = {
|
|
86
|
+
'T': t,
|
|
87
|
+
'V': voltage,
|
|
88
|
+
'stim_start': [stim_start],
|
|
89
|
+
'stim_end': [stim_start + duration]
|
|
90
|
+
}
|
|
91
|
+
features_results = efel.get_feature_values([trace], ['steady_state_voltage_stimend'])
|
|
92
|
+
steady_state = features_results[0]['steady_state_voltage_stimend']
|
|
93
|
+
steady_states.append(steady_state)
|
|
94
|
+
|
|
95
|
+
plot_iv_curve(list_amp,
|
|
96
|
+
steady_states,
|
|
97
|
+
injecting_section=injecting_section,
|
|
98
|
+
injecting_segment=injecting_segment,
|
|
99
|
+
recording_section=recording_section,
|
|
100
|
+
recording_segment=recording_segment)
|
|
101
|
+
|
|
102
|
+
return np.array(list_amp), np.array(steady_states)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def compute_plot_fi_curve(cell,
|
|
106
|
+
injecting_section="soma[0]",
|
|
107
|
+
injecting_segment=0.5,
|
|
108
|
+
recording_section="soma[0]",
|
|
109
|
+
recording_segment=0.5,
|
|
110
|
+
stim_start=100.0,
|
|
111
|
+
duration=500.0,
|
|
112
|
+
post_delay=100.0,
|
|
113
|
+
max_current=0.8,
|
|
114
|
+
nb_bins=11):
|
|
115
|
+
"""Compute and plot the Frequency-Current (F-I) curve for a given cell by
|
|
116
|
+
injecting a range of currents.
|
|
117
|
+
|
|
118
|
+
This function evaluates the relationship between injected current amplitude and the firing rate
|
|
119
|
+
of a neuronal cell model. Currents are injected at a specified section and segment, and the number
|
|
120
|
+
of spikes recorded in the specified recording location is used to construct the F-I curve.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
cell (bluecellulab.cell.Cell): The initialized BlueCelluLab cell model.
|
|
124
|
+
injecting_section (str, optional): The name of the section where the stimulus is injected.
|
|
125
|
+
Default is "soma[0]".
|
|
126
|
+
injecting_segment (float, optional): The position along the injecting section (0.0 to 1.0)
|
|
127
|
+
where the stimulus is applied. Default is 0.5.
|
|
128
|
+
recording_section (str, optional): The name of the section where spikes are recorded.
|
|
129
|
+
Default is "soma[0]".
|
|
130
|
+
recording_segment (float, optional): The position along the recording section (0.0 to 1.0)
|
|
131
|
+
where spikes are recorded. Default is 0.5.
|
|
132
|
+
stim_start (float, optional): The start time of the current injection (in ms). Default is 100.0 ms.
|
|
133
|
+
duration (float, optional): The duration of the current injection (in ms). Default is 500.0 ms.
|
|
134
|
+
post_delay (float, optional): The delay after the stimulation ends before the simulation stops
|
|
135
|
+
(in ms). Default is 100.0 ms.
|
|
136
|
+
max_current (float, optional): The maximum amplitude of the injected current (in nA).
|
|
137
|
+
Default is 0.8 nA.
|
|
138
|
+
nb_bins (int, optional): The number of discrete current levels between 0 and `max_current`.
|
|
139
|
+
Default is 11.
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
tuple: A tuple containing:
|
|
143
|
+
- list_amp (np.ndarray): The injected current amplitudes (nA).
|
|
144
|
+
- spike_count (np.ndarray): The corresponding spike counts for each current amplitude.
|
|
145
|
+
|
|
146
|
+
Raises:
|
|
147
|
+
ValueError: If the cell object is invalid or the specified sections/segments are not found.
|
|
148
|
+
"""
|
|
149
|
+
rheobase = calculate_rheobase(cell=cell, section=injecting_section, segx=injecting_segment)
|
|
150
|
+
|
|
151
|
+
list_amp = np.linspace(rheobase, max_current, nb_bins) # [nA]
|
|
152
|
+
steps = []
|
|
153
|
+
spikes = []
|
|
154
|
+
# inject step current and record spike response
|
|
155
|
+
stim_factory = StimulusFactory(dt=0.1)
|
|
156
|
+
for amp in list_amp:
|
|
157
|
+
step_stimulus = stim_factory.step(pre_delay=stim_start, duration=duration, post_delay=post_delay, amplitude=amp)
|
|
158
|
+
recording = run_stimulus(cell.template_params,
|
|
159
|
+
step_stimulus,
|
|
160
|
+
section=injecting_section,
|
|
161
|
+
segment=injecting_segment,
|
|
162
|
+
recording_section=recording_section,
|
|
163
|
+
recording_segment=recording_segment,
|
|
164
|
+
enable_spike_detection=True)
|
|
165
|
+
steps.append(step_stimulus)
|
|
166
|
+
spikes.append(recording.spike)
|
|
167
|
+
|
|
168
|
+
spike_count = [len(spike) for spike in spikes]
|
|
169
|
+
|
|
170
|
+
plot_fi_curve(list_amp,
|
|
171
|
+
spike_count,
|
|
172
|
+
injecting_section=injecting_section,
|
|
173
|
+
injecting_segment=injecting_segment,
|
|
174
|
+
recording_section=recording_section,
|
|
175
|
+
recording_segment=recording_segment)
|
|
176
|
+
|
|
177
|
+
return np.array(list_amp), np.array(spike_count)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Module for injecting a sequence of protocols to the cell."""
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
from enum import Enum, auto
|
|
4
|
-
from typing import NamedTuple, Sequence, Dict
|
|
4
|
+
from typing import NamedTuple, Sequence, Dict, Optional
|
|
5
5
|
|
|
6
6
|
import neuron
|
|
7
7
|
import numpy as np
|
|
@@ -11,6 +11,7 @@ from bluecellulab.simulation.parallel import IsolatedProcess
|
|
|
11
11
|
from bluecellulab.simulation.simulation import Simulation
|
|
12
12
|
from bluecellulab.stimulus.circuit_stimulus_definitions import Hyperpolarizing
|
|
13
13
|
from bluecellulab.stimulus.factory import Stimulus, StimulusFactory
|
|
14
|
+
from bluecellulab.tools import validate_section_and_segment
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
class StimulusName(Enum):
|
|
@@ -24,10 +25,12 @@ class StimulusName(Enum):
|
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
class Recording(NamedTuple):
|
|
27
|
-
"""A tuple of the current, voltage and time recordings
|
|
28
|
+
"""A tuple of the current, voltage and time recordings with optional spike
|
|
29
|
+
recordings."""
|
|
28
30
|
current: np.ndarray
|
|
29
31
|
voltage: np.ndarray
|
|
30
32
|
time: np.ndarray
|
|
33
|
+
spike: np.ndarray | None
|
|
31
34
|
|
|
32
35
|
|
|
33
36
|
StimulusRecordings = Dict[str, Recording]
|
|
@@ -40,41 +43,91 @@ def run_stimulus(
|
|
|
40
43
|
segment: float,
|
|
41
44
|
cvode: bool = True,
|
|
42
45
|
add_hypamp: bool = True,
|
|
46
|
+
recording_section: str = "soma[0]",
|
|
47
|
+
recording_segment: float = 0.5,
|
|
48
|
+
enable_spike_detection: bool = False,
|
|
49
|
+
threshold_spike_detection: float = -30,
|
|
43
50
|
) -> Recording:
|
|
44
|
-
"""Creates a cell
|
|
51
|
+
"""Creates a cell from template parameters, applies a stimulus, and records
|
|
52
|
+
the response.
|
|
53
|
+
|
|
54
|
+
This function simulates the electrical activity of a neuronal cell model by injecting
|
|
55
|
+
a stimulus into a specified section and segment, recording the voltage response, and
|
|
56
|
+
optionally detecting spikes.
|
|
45
57
|
|
|
46
58
|
Args:
|
|
47
|
-
template_params:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
59
|
+
template_params (TemplateParams): Parameters required to create the cell from a
|
|
60
|
+
specified template, including morphology and mechanisms.
|
|
61
|
+
stimulus (Stimulus): The stimulus waveform to inject, defined by time and current arrays.
|
|
62
|
+
section (str): Name of the section of the cell where the stimulus is applied.
|
|
63
|
+
(e.g. soma[0])
|
|
64
|
+
segment (float): The normalized position (0.0 to 1.0) along the injecting
|
|
65
|
+
section where the stimulus is applied.
|
|
66
|
+
cvode (bool, optional): Whether to use variable time-step integration. Defaults to True.
|
|
67
|
+
add_hypamp (bool, optional): If True, adds a hyperpolarizing stimulus before applying
|
|
68
|
+
the main stimulus. Defaults to True.
|
|
69
|
+
recording_section (str): Name of the section of the cell where voltage is recorded.
|
|
70
|
+
recording_segment (float): The normalized position (0.0 to 1.0) along the recording
|
|
71
|
+
section where voltage is recorded.
|
|
72
|
+
enable_spike_detection (bool, optional): If True, enables spike detection at the
|
|
73
|
+
recording location. Defaults to False.
|
|
74
|
+
threshold_spike_detection (float, optional): The voltage threshold (mV) for spike detection.
|
|
75
|
+
Defaults to -30 mV.
|
|
52
76
|
|
|
53
77
|
Returns:
|
|
54
|
-
|
|
78
|
+
Recording: A `Recording` object containing the following:
|
|
79
|
+
- `current` (np.ndarray): The injected current waveform (nA).
|
|
80
|
+
- `voltage` (np.ndarray): The recorded membrane potential (mV) over time.
|
|
81
|
+
- `time` (np.ndarray): The simulation time points (ms).
|
|
82
|
+
- `spike` (np.ndarray or None): The detected spikes, if spike detection is enabled.
|
|
55
83
|
|
|
56
84
|
Raises:
|
|
57
|
-
ValueError: If the time and voltage arrays
|
|
85
|
+
ValueError: If the time, current, and voltage arrays do not have the same length,
|
|
86
|
+
or if the specified sections or segments are not found in the cell model.
|
|
58
87
|
"""
|
|
59
88
|
cell = Cell.from_template_parameters(template_params)
|
|
60
|
-
|
|
89
|
+
|
|
90
|
+
validate_section_and_segment(cell, section, segment)
|
|
91
|
+
validate_section_and_segment(cell, recording_section, recording_segment)
|
|
92
|
+
|
|
61
93
|
if add_hypamp:
|
|
62
94
|
hyp_stim = Hyperpolarizing(target="", delay=0.0, duration=stimulus.stimulus_time)
|
|
63
95
|
cell.add_replay_hypamp(hyp_stim)
|
|
64
|
-
|
|
96
|
+
|
|
97
|
+
cell.add_voltage_recording(cell.sections[recording_section], recording_segment)
|
|
98
|
+
|
|
99
|
+
# Set up spike detection if enabled
|
|
100
|
+
spikes: Optional[np.ndarray] = None
|
|
101
|
+
if enable_spike_detection:
|
|
102
|
+
recording_location = f"{recording_section}({str(recording_segment)})"
|
|
103
|
+
cell.start_recording_spikes(None, location=recording_location, threshold=threshold_spike_detection)
|
|
104
|
+
|
|
105
|
+
# Inject the stimulus and run the simulation
|
|
65
106
|
iclamp, _ = cell.inject_current_waveform(
|
|
66
|
-
stimulus.time, stimulus.current, section=
|
|
107
|
+
stimulus.time, stimulus.current, section=cell.sections[section], segx=segment
|
|
67
108
|
)
|
|
68
109
|
current_vector = neuron.h.Vector()
|
|
69
110
|
current_vector.record(iclamp._ref_i)
|
|
111
|
+
|
|
70
112
|
simulation = Simulation(cell)
|
|
71
113
|
simulation.run(stimulus.stimulus_time, cvode=cvode)
|
|
114
|
+
|
|
115
|
+
# Retrieve simulation results
|
|
72
116
|
current = np.array(current_vector.to_python())
|
|
73
|
-
voltage = cell.get_voltage_recording(
|
|
117
|
+
voltage = cell.get_voltage_recording(cell.sections[recording_section], recording_segment)
|
|
74
118
|
time = cell.get_time()
|
|
119
|
+
|
|
75
120
|
if len(time) != len(voltage) or len(time) != len(current):
|
|
76
|
-
raise ValueError("Time, current and voltage arrays are not the same length")
|
|
77
|
-
|
|
121
|
+
raise ValueError("Time, current, and voltage arrays are not the same length")
|
|
122
|
+
|
|
123
|
+
if enable_spike_detection:
|
|
124
|
+
results = cell.get_recorded_spikes(location=recording_location, threshold=threshold_spike_detection)
|
|
125
|
+
if results is not None:
|
|
126
|
+
spikes = np.array(results)
|
|
127
|
+
else:
|
|
128
|
+
spikes = None
|
|
129
|
+
|
|
130
|
+
return Recording(current=current, voltage=voltage, time=time, spike=spikes)
|
|
78
131
|
|
|
79
132
|
|
|
80
133
|
def apply_multiple_stimuli(
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Module for plotting analysis results of cell simulations."""
|
|
2
|
+
|
|
3
|
+
import matplotlib.pyplot as plt
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def plot_iv_curve(currents, voltages, injecting_section, injecting_segment, recording_section, recording_segment):
|
|
7
|
+
"""Plots the IV curve.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
currents (list): The injected current levels (nA).
|
|
11
|
+
voltages (list): The corresponding steady-state voltages (mV).
|
|
12
|
+
injecting_section (str): The section in the cell where the current was injected.
|
|
13
|
+
injecting_segment (float): The segment position (0.0 to 1.0) where the current was injected.
|
|
14
|
+
recording_section (str): The section in the cell where spikes were recorded.
|
|
15
|
+
recording_segment (float): The segment position (0.0 to 1.0) where spikes were recorded.
|
|
16
|
+
|
|
17
|
+
Raises:
|
|
18
|
+
ValueError: If the lengths of currents and voltages do not match.
|
|
19
|
+
"""
|
|
20
|
+
if len(currents) != len(voltages):
|
|
21
|
+
raise ValueError("currents and voltages must have the same length")
|
|
22
|
+
|
|
23
|
+
plt.figure(figsize=(10, 6))
|
|
24
|
+
plt.plot(currents, voltages, marker='o', linestyle='-', color='b')
|
|
25
|
+
plt.title("I-V Curve")
|
|
26
|
+
plt.xlabel(f"Injected Current [nA] at {injecting_section}({injecting_segment:.2f})")
|
|
27
|
+
plt.ylabel(f"Steady state voltage [mV] at {recording_section}({recording_segment:.2f})")
|
|
28
|
+
plt.grid(True)
|
|
29
|
+
plt.tight_layout()
|
|
30
|
+
plt.show()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def plot_fi_curve(currents, spike_count, injecting_section, injecting_segment, recording_section, recording_segment):
|
|
34
|
+
"""Plots the F-I (Frequency-Current) curve.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
currents (list): The injected current levels (nA).
|
|
38
|
+
spike_count (list): The number of spikes recorded for each current level.
|
|
39
|
+
injecting_section (str): The section in the cell where the current was injected.
|
|
40
|
+
injecting_segment (float): The segment position (0.0 to 1.0) where the current was injected.
|
|
41
|
+
recording_section (str): The section in the cell where spikes were recorded.
|
|
42
|
+
recording_segment (float): The segment position (0.0 to 1.0) where spikes were recorded.
|
|
43
|
+
|
|
44
|
+
Raises:
|
|
45
|
+
ValueError: If the lengths of currents and spike counts do not match.
|
|
46
|
+
"""
|
|
47
|
+
if len(currents) != len(spike_count):
|
|
48
|
+
raise ValueError("currents and spike count must have the same length")
|
|
49
|
+
|
|
50
|
+
plt.figure(figsize=(10, 6))
|
|
51
|
+
plt.plot(currents, spike_count, marker='o')
|
|
52
|
+
plt.title("F-I Curve")
|
|
53
|
+
plt.xlabel(f"Injected Current [nA] at {injecting_section}({injecting_segment:.2f})")
|
|
54
|
+
plt.ylabel(f"Spike Count recorded at {recording_section}({recording_segment:.2f})")
|
|
55
|
+
plt.grid(True)
|
|
56
|
+
plt.tight_layout()
|
|
57
|
+
plt.show()
|
|
@@ -25,6 +25,7 @@ from typing_extensions import deprecated
|
|
|
25
25
|
import neuron
|
|
26
26
|
import numpy as np
|
|
27
27
|
import pandas as pd
|
|
28
|
+
import re
|
|
28
29
|
|
|
29
30
|
import bluecellulab
|
|
30
31
|
from bluecellulab.cell.recording import section_to_voltage_recording_str
|
|
@@ -376,7 +377,11 @@ class Cell(InjectableMixin, PlottableMixin):
|
|
|
376
377
|
|
|
377
378
|
def get_recording(self, var_name: str) -> np.ndarray:
|
|
378
379
|
"""Get recorded values."""
|
|
379
|
-
|
|
380
|
+
try:
|
|
381
|
+
res = np.array(self.recordings[var_name].to_python())
|
|
382
|
+
except KeyError as e:
|
|
383
|
+
raise ValueError(f"No recording for '{var_name}' was found.") from e
|
|
384
|
+
return res
|
|
380
385
|
|
|
381
386
|
def add_replay_synapse(self,
|
|
382
387
|
synapse_id: SynapseID,
|
|
@@ -432,19 +437,42 @@ class Cell(InjectableMixin, PlottableMixin):
|
|
|
432
437
|
def create_netcon_spikedetector(self, target: HocObjectType, location: str, threshold: float = -30.0) -> HocObjectType:
|
|
433
438
|
"""Add and return a spikedetector.
|
|
434
439
|
|
|
435
|
-
This
|
|
436
|
-
connects to target
|
|
440
|
+
This function creates a NetCon object that detects spikes at a specific
|
|
441
|
+
location in the current cell and connects to the provided target point process.
|
|
442
|
+
The location can be specified as a predefined site ('soma' or 'AIS') or as a
|
|
443
|
+
custom location in the format `section[index](position)`. Custom locations
|
|
444
|
+
allow fine-grained control of the spike detection site within the cell's sections.
|
|
437
445
|
|
|
438
446
|
Args:
|
|
439
|
-
target:
|
|
440
|
-
location:
|
|
441
|
-
|
|
447
|
+
target: A NEURON point process object (e.g., synapse) that the NetCon connects to.
|
|
448
|
+
location: The spike detection location. Acceptable formats include:
|
|
449
|
+
|
|
450
|
+
- `"soma"`: Detect spikes in the soma section at the distal end.
|
|
451
|
+
|
|
452
|
+
- `"AIS"`: Detect spikes in the axon initial segment at the midpoint.
|
|
442
453
|
|
|
443
|
-
|
|
454
|
+
- `"section[index](position)"`: Custom location specifying:
|
|
455
|
+
|
|
456
|
+
- `section`: The name of the section (e.g., 'soma', 'axon').
|
|
457
|
+
- `[index]` (optional): Segment index within a section array (e.g., 'soma[0]').
|
|
458
|
+
- `(position)` (optional): Normalized position along the section length (0 to 1).
|
|
459
|
+
Defaults to 0.5 if not provided.
|
|
460
|
+
|
|
461
|
+
threshold: The voltage threshold for spike detection (default: -30.0 mV).
|
|
462
|
+
|
|
463
|
+
Returns:
|
|
464
|
+
A NEURON `NetCon` object configured for spike detection at the specified location.
|
|
444
465
|
|
|
445
466
|
Raises:
|
|
446
|
-
ValueError: If
|
|
467
|
+
ValueError: If:
|
|
468
|
+
|
|
469
|
+
- The `location` is not 'soma', 'AIS', or a valid custom format.
|
|
470
|
+
|
|
471
|
+
- The specified section or segment index does not exist.
|
|
472
|
+
|
|
473
|
+
- The position is out of bounds (e.g., negative or greater than 1.0).
|
|
447
474
|
"""
|
|
475
|
+
|
|
448
476
|
if location == "soma":
|
|
449
477
|
sec = public_hoc_cell(self.cell).soma[0]
|
|
450
478
|
source = sec(1)._ref_v
|
|
@@ -452,7 +480,34 @@ class Cell(InjectableMixin, PlottableMixin):
|
|
|
452
480
|
sec = public_hoc_cell(self.cell).axon[1]
|
|
453
481
|
source = sec(0.5)._ref_v
|
|
454
482
|
else:
|
|
455
|
-
|
|
483
|
+
# Parse custom location (e.g., 'soma[0](0.3)')
|
|
484
|
+
pattern = r'^([a-zA-Z_]+)(?:\[(\d+)\])?(?:\((-?\d+\.\d+)\))?$'
|
|
485
|
+
match = re.search(pattern, location)
|
|
486
|
+
|
|
487
|
+
# Extract the value if a match is found
|
|
488
|
+
if match:
|
|
489
|
+
section_name = match.group(1)
|
|
490
|
+
segment_index = match.group(2)
|
|
491
|
+
pos = match.group(3)
|
|
492
|
+
if pos is None:
|
|
493
|
+
pos = 0.5
|
|
494
|
+
else:
|
|
495
|
+
pos = float(pos)
|
|
496
|
+
|
|
497
|
+
else:
|
|
498
|
+
raise ValueError(f"Invalid location format: {location}")
|
|
499
|
+
|
|
500
|
+
try:
|
|
501
|
+
# Handle section arrays (e.g., soma[0])
|
|
502
|
+
if segment_index is not None:
|
|
503
|
+
sec = getattr(public_hoc_cell(self.cell), section_name)[int(segment_index)]
|
|
504
|
+
else:
|
|
505
|
+
sec = getattr(public_hoc_cell(self.cell), section_name)
|
|
506
|
+
|
|
507
|
+
source = sec(pos)._ref_v
|
|
508
|
+
except (AttributeError, ValueError, IndexError) as e:
|
|
509
|
+
raise ValueError(f"Invalid spike detection location: {location}") from e
|
|
510
|
+
|
|
456
511
|
netcon = neuron.h.NetCon(source, target, sec=sec)
|
|
457
512
|
netcon.threshold = threshold
|
|
458
513
|
return netcon
|