dendrotweaks 0.3.1__py3-none-any.whl
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.
- dendrotweaks/__init__.py +10 -0
- dendrotweaks/analysis/__init__.py +11 -0
- dendrotweaks/analysis/ephys_analysis.py +482 -0
- dendrotweaks/analysis/morphometric_analysis.py +106 -0
- dendrotweaks/membrane/__init__.py +6 -0
- dendrotweaks/membrane/default_mod/AMPA.mod +65 -0
- dendrotweaks/membrane/default_mod/AMPA_NMDA.mod +100 -0
- dendrotweaks/membrane/default_mod/CaDyn.mod +54 -0
- dendrotweaks/membrane/default_mod/GABAa.mod +65 -0
- dendrotweaks/membrane/default_mod/Leak.mod +27 -0
- dendrotweaks/membrane/default_mod/NMDA.mod +72 -0
- dendrotweaks/membrane/default_mod/vecstim.mod +76 -0
- dendrotweaks/membrane/default_templates/NEURON_template.py +354 -0
- dendrotweaks/membrane/default_templates/default.py +73 -0
- dendrotweaks/membrane/default_templates/standard_channel.mod +87 -0
- dendrotweaks/membrane/default_templates/template_jaxley.py +108 -0
- dendrotweaks/membrane/default_templates/template_jaxley_new.py +108 -0
- dendrotweaks/membrane/distributions.py +324 -0
- dendrotweaks/membrane/groups.py +103 -0
- dendrotweaks/membrane/io/__init__.py +11 -0
- dendrotweaks/membrane/io/ast.py +201 -0
- dendrotweaks/membrane/io/code_generators.py +312 -0
- dendrotweaks/membrane/io/converter.py +108 -0
- dendrotweaks/membrane/io/factories.py +144 -0
- dendrotweaks/membrane/io/grammar.py +417 -0
- dendrotweaks/membrane/io/loader.py +90 -0
- dendrotweaks/membrane/io/parser.py +499 -0
- dendrotweaks/membrane/io/reader.py +212 -0
- dendrotweaks/membrane/mechanisms.py +574 -0
- dendrotweaks/model.py +1916 -0
- dendrotweaks/model_io.py +75 -0
- dendrotweaks/morphology/__init__.py +5 -0
- dendrotweaks/morphology/domains.py +100 -0
- dendrotweaks/morphology/io/__init__.py +5 -0
- dendrotweaks/morphology/io/factories.py +212 -0
- dendrotweaks/morphology/io/reader.py +66 -0
- dendrotweaks/morphology/io/validation.py +212 -0
- dendrotweaks/morphology/point_trees.py +681 -0
- dendrotweaks/morphology/reduce/__init__.py +16 -0
- dendrotweaks/morphology/reduce/reduce.py +155 -0
- dendrotweaks/morphology/reduce/reduced_cylinder.py +129 -0
- dendrotweaks/morphology/sec_trees.py +1112 -0
- dendrotweaks/morphology/seg_trees.py +157 -0
- dendrotweaks/morphology/trees.py +567 -0
- dendrotweaks/path_manager.py +261 -0
- dendrotweaks/simulators.py +235 -0
- dendrotweaks/stimuli/__init__.py +3 -0
- dendrotweaks/stimuli/iclamps.py +73 -0
- dendrotweaks/stimuli/populations.py +265 -0
- dendrotweaks/stimuli/synapses.py +203 -0
- dendrotweaks/utils.py +239 -0
- dendrotweaks-0.3.1.dist-info/METADATA +70 -0
- dendrotweaks-0.3.1.dist-info/RECORD +56 -0
- dendrotweaks-0.3.1.dist-info/WHEEL +5 -0
- dendrotweaks-0.3.1.dist-info/licenses/LICENSE +674 -0
- dendrotweaks-0.3.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,261 @@
|
|
1
|
+
import os
|
2
|
+
from typing import List, Dict
|
3
|
+
import shutil
|
4
|
+
|
5
|
+
class PathManager:
|
6
|
+
"""
|
7
|
+
A manager class for handling file and directory paths related to models data.
|
8
|
+
|
9
|
+
Parameters
|
10
|
+
----------
|
11
|
+
path_to_model : str
|
12
|
+
The path to the model directory.
|
13
|
+
|
14
|
+
Attributes
|
15
|
+
----------
|
16
|
+
path_to_model : str
|
17
|
+
The path to the model directory.
|
18
|
+
paths : Dict[str, str]
|
19
|
+
A dictionary of paths for different file types.
|
20
|
+
"""
|
21
|
+
def __init__(self, path_to_model: str):
|
22
|
+
if not os.path.isdir(path_to_model):
|
23
|
+
raise FileNotFoundError(f"Directory {path_to_model} does not exist.")
|
24
|
+
self.path_to_model = path_to_model
|
25
|
+
self.paths = {
|
26
|
+
'default_mod': os.path.join(self.path_to_data, 'Default'),
|
27
|
+
'templates': os.path.join(self.path_to_data, 'Templates'),
|
28
|
+
'morphology': os.path.join(self.path_to_model, 'morphology'),
|
29
|
+
'membrane': os.path.join(self.path_to_model, 'membrane'),
|
30
|
+
'mod': os.path.join(self.path_to_model, 'membrane', 'mod'),
|
31
|
+
'python': os.path.join(self.path_to_model, 'membrane', 'python'),
|
32
|
+
'stimuli': os.path.join(self.path_to_model, 'stimuli'),
|
33
|
+
}
|
34
|
+
self._ensure_paths_exist()
|
35
|
+
|
36
|
+
|
37
|
+
def _ensure_paths_exist(self):
|
38
|
+
"""
|
39
|
+
Ensure all necessary paths exist.
|
40
|
+
"""
|
41
|
+
os.makedirs(self.path_to_model, exist_ok=True)
|
42
|
+
for path in self.paths.values():
|
43
|
+
os.makedirs(path, exist_ok=True)
|
44
|
+
# if empty, copy default mod files
|
45
|
+
if not os.listdir(self.paths['default_mod']):
|
46
|
+
self.copy_default_mod_files()
|
47
|
+
if not os.listdir(self.paths['templates']):
|
48
|
+
self.copy_template_files()
|
49
|
+
|
50
|
+
@property
|
51
|
+
def path_to_data(self):
|
52
|
+
"""
|
53
|
+
The path to the data directory.
|
54
|
+
"""
|
55
|
+
return os.path.dirname(self.path_to_model)
|
56
|
+
|
57
|
+
def __repr__(self):
|
58
|
+
return f"PathManager({self.path_to_model})"
|
59
|
+
|
60
|
+
def copy_default_mod_files(self):
|
61
|
+
"""
|
62
|
+
Copy default mod files to the data directory.
|
63
|
+
"""
|
64
|
+
# __file__ + 'membrane' + 'default_mod'
|
65
|
+
DEFAULT_MOD_DIR = os.path.join(os.path.dirname(__file__), 'membrane', 'default_mod')
|
66
|
+
for file_name in os.listdir(DEFAULT_MOD_DIR):
|
67
|
+
source = os.path.join(DEFAULT_MOD_DIR, file_name)
|
68
|
+
destination = os.path.join(self.paths['default_mod'], file_name)
|
69
|
+
shutil.copyfile(source, destination)
|
70
|
+
|
71
|
+
def copy_template_files(self):
|
72
|
+
"""
|
73
|
+
Copy template files to the data directory.
|
74
|
+
"""
|
75
|
+
# __file__ + 'membrane' + 'templates'
|
76
|
+
TEMPLATES_DIR = os.path.join(os.path.dirname(__file__), 'membrane', 'default_templates')
|
77
|
+
for file_name in os.listdir(TEMPLATES_DIR):
|
78
|
+
source = os.path.join(TEMPLATES_DIR, file_name)
|
79
|
+
destination = os.path.join(self.paths['templates'], file_name)
|
80
|
+
shutil.copyfile(source, destination)
|
81
|
+
|
82
|
+
|
83
|
+
def get_path(self, file_type: str) -> str:
|
84
|
+
"""
|
85
|
+
Get the path for a specific file type.
|
86
|
+
|
87
|
+
Parameters
|
88
|
+
----------
|
89
|
+
file_type : str
|
90
|
+
The type of file (e.g., 'mod', 'swc').
|
91
|
+
|
92
|
+
Returns
|
93
|
+
-------
|
94
|
+
str
|
95
|
+
The full directory path.
|
96
|
+
"""
|
97
|
+
path = self.paths.get(file_type, None)
|
98
|
+
if os.path.isdir(path):
|
99
|
+
return path
|
100
|
+
raise FileNotFoundError(f"Directory for {file_type} does not exist.")
|
101
|
+
|
102
|
+
def get_file_path(self, file_type: str, file_name: str, extension: str) -> str:
|
103
|
+
"""
|
104
|
+
Construct a file path with an optional extension for a specific type.
|
105
|
+
|
106
|
+
Parameters
|
107
|
+
----------
|
108
|
+
file_type : str
|
109
|
+
The type of file (e.g., 'morphology', 'stimuli').
|
110
|
+
file_name : str
|
111
|
+
The name of the file.
|
112
|
+
extension : str
|
113
|
+
The file extension (e.g., 'mod', 'swc').
|
114
|
+
|
115
|
+
Returns
|
116
|
+
-------
|
117
|
+
str
|
118
|
+
The full file path.
|
119
|
+
"""
|
120
|
+
dir_path = self.get_path(file_type)
|
121
|
+
file_name = f"{file_name}.{extension}"
|
122
|
+
return os.path.join(dir_path, file_name)
|
123
|
+
|
124
|
+
def list_files(self, file_type: str, extension: str = "") -> List[str]:
|
125
|
+
"""
|
126
|
+
List all files of a given type and optional archive.
|
127
|
+
|
128
|
+
Parameters
|
129
|
+
----------
|
130
|
+
file_type : str
|
131
|
+
The type of file (e.g. 'morphology', 'stimuli').
|
132
|
+
extension : str
|
133
|
+
The file extension to filter by (e.g., 'mod', 'swc').
|
134
|
+
|
135
|
+
Returns
|
136
|
+
-------
|
137
|
+
List[str]
|
138
|
+
A list of file names.
|
139
|
+
"""
|
140
|
+
directory = self.paths.get(file_type, "")
|
141
|
+
if not extension.startswith('.'): extension = f".{extension}"
|
142
|
+
if not os.path.isdir(directory):
|
143
|
+
return []
|
144
|
+
return [f.replace(extension, '')
|
145
|
+
for f in os.listdir(directory) if f.endswith(extension)]
|
146
|
+
|
147
|
+
|
148
|
+
def list_morphologies(self, extension: str = '.swc') -> List[str]:
|
149
|
+
"""
|
150
|
+
List all SWC files.
|
151
|
+
|
152
|
+
Returns
|
153
|
+
-------
|
154
|
+
List[str]
|
155
|
+
A list of SWC file names.
|
156
|
+
"""
|
157
|
+
return self.list_files('morphology', extension=extension)
|
158
|
+
|
159
|
+
|
160
|
+
def list_stimuli(self, extension: str = '.json') -> List[str]:
|
161
|
+
"""
|
162
|
+
List all JSON files.
|
163
|
+
|
164
|
+
Returns
|
165
|
+
-------
|
166
|
+
List[str]
|
167
|
+
A list of JSON file names.
|
168
|
+
"""
|
169
|
+
return self.list_files('stimuli', extension=extension)
|
170
|
+
|
171
|
+
|
172
|
+
def list_membrane(self):
|
173
|
+
"""
|
174
|
+
List all membrane files.
|
175
|
+
|
176
|
+
Returns
|
177
|
+
-------
|
178
|
+
List[str]
|
179
|
+
A list of membrane file
|
180
|
+
"""
|
181
|
+
return self.list_files('membrane', extension='.json')
|
182
|
+
|
183
|
+
|
184
|
+
def print_directory_tree(self, subfolder=None) -> None:
|
185
|
+
"""
|
186
|
+
Print a directory tree for a given file type.
|
187
|
+
|
188
|
+
Parameters
|
189
|
+
----------
|
190
|
+
file_type : str
|
191
|
+
The type of file (e.g., 'mod', 'swc').
|
192
|
+
"""
|
193
|
+
base_path = self.paths.get('model') if not subfolder else self.paths.get(subfolder)
|
194
|
+
if not base_path or not os.path.isdir(base_path):
|
195
|
+
print(f"Directory for {file_type} does not exist.")
|
196
|
+
return
|
197
|
+
|
198
|
+
def print_tree(path, prefix=""):
|
199
|
+
items = os.listdir(path)
|
200
|
+
for idx, item in enumerate(sorted(items)):
|
201
|
+
is_last = idx == len(items) - 1
|
202
|
+
connector = "└──" if is_last else "├──"
|
203
|
+
item_path = os.path.join(path, item)
|
204
|
+
print(f"{prefix}{connector} {item}")
|
205
|
+
if os.path.isdir(item_path) and not item.startswith('x86_64'):
|
206
|
+
extension = "│ " if not is_last else " "
|
207
|
+
print_tree(item_path, prefix + extension)
|
208
|
+
|
209
|
+
print_tree(base_path)
|
210
|
+
|
211
|
+
def get_channel_paths(self, mechanism_name: str,
|
212
|
+
python_template_name: str = None) -> Dict[str, str]:
|
213
|
+
"""
|
214
|
+
Get all necessary paths for creating a channel.
|
215
|
+
|
216
|
+
Parameters
|
217
|
+
----------
|
218
|
+
mechanism_name : str
|
219
|
+
The name of the mechanism.
|
220
|
+
python_template_name : str, optional
|
221
|
+
The name of the Python template file.
|
222
|
+
|
223
|
+
Returns
|
224
|
+
-------
|
225
|
+
Dict[str, str]
|
226
|
+
A dictionary of paths.
|
227
|
+
"""
|
228
|
+
python_template_name = python_template_name or "default"
|
229
|
+
return {
|
230
|
+
'path_to_mod_file': self.get_file_path('mod', mechanism_name, 'mod'),
|
231
|
+
'path_to_python_file': self.get_file_path('python', mechanism_name, 'py'),
|
232
|
+
'path_to_python_template': self.get_file_path('templates', python_template_name, 'py'),
|
233
|
+
}
|
234
|
+
|
235
|
+
def get_standard_channel_paths(self, mechanism_name: str,
|
236
|
+
python_template_name: str = None,
|
237
|
+
mod_template_name: str = None) -> Dict[str, str]:
|
238
|
+
"""
|
239
|
+
Get all necessary paths for creating a standard channel.
|
240
|
+
|
241
|
+
Parameters
|
242
|
+
----------
|
243
|
+
mechanism_name : str
|
244
|
+
The name of the mechanism.
|
245
|
+
python_template_name : str, optional
|
246
|
+
The name of the Python template file.
|
247
|
+
mod_template_name : str, optional
|
248
|
+
The name of the MOD template file.
|
249
|
+
|
250
|
+
Returns
|
251
|
+
-------
|
252
|
+
Dict[str, str]
|
253
|
+
A dictionary of paths.
|
254
|
+
"""
|
255
|
+
python_template_name = python_template_name or "default"
|
256
|
+
mod_template_name = mod_template_name or "standard_channel"
|
257
|
+
return {
|
258
|
+
# **self.get_channel_paths(mechanism_name, python_template_name),
|
259
|
+
'path_to_mod_template': self.get_file_path('templates', mod_template_name, 'mod'),
|
260
|
+
'path_to_standard_mod_file': self.get_file_path('mod', f"std{mechanism_name}", 'mod'),
|
261
|
+
}
|
@@ -0,0 +1,235 @@
|
|
1
|
+
from collections import defaultdict
|
2
|
+
import warnings
|
3
|
+
|
4
|
+
import matplotlib.pyplot as plt
|
5
|
+
import neuron
|
6
|
+
from neuron import h
|
7
|
+
from neuron.units import ms, mV
|
8
|
+
h.load_file('stdrun.hoc')
|
9
|
+
# h.load_file('import3d.hoc')
|
10
|
+
# h.load_file('nrngui.hoc')
|
11
|
+
# h.load_file('import3d')
|
12
|
+
|
13
|
+
import contextlib
|
14
|
+
|
15
|
+
@contextlib.contextmanager
|
16
|
+
def push_section(section):
|
17
|
+
section.push()
|
18
|
+
yield
|
19
|
+
h.pop_section()
|
20
|
+
|
21
|
+
def reset_neuron():
|
22
|
+
|
23
|
+
# h('forall delete_section()')
|
24
|
+
# h('forall delete_all()')
|
25
|
+
# h('forall delete()')
|
26
|
+
|
27
|
+
for sec in h.allsec():
|
28
|
+
with push_section(sec):
|
29
|
+
h.delete_section()
|
30
|
+
|
31
|
+
reset_neuron()
|
32
|
+
|
33
|
+
class Simulator:
|
34
|
+
"""
|
35
|
+
A generic simulator class.
|
36
|
+
"""
|
37
|
+
def __init__(self):
|
38
|
+
self.vs = None
|
39
|
+
self.t = None
|
40
|
+
self.dt = None
|
41
|
+
self.recordings = {}
|
42
|
+
|
43
|
+
def plot_voltage(self, ax=None, segments=None, **kwargs):
|
44
|
+
if ax is None:
|
45
|
+
fig, ax = plt.subplots()
|
46
|
+
if segments is None:
|
47
|
+
segments = self.recordings.keys()
|
48
|
+
for seg, v in self.vs.items():
|
49
|
+
if segments and seg not in segments:
|
50
|
+
continue
|
51
|
+
ax.plot(self.t, v, label=f'{seg.domain} {seg.idx}', **kwargs)
|
52
|
+
|
53
|
+
if len(segments) < 10:
|
54
|
+
ax.legend()
|
55
|
+
# ax.set_ylim(-100, 60)
|
56
|
+
ax.set_xlabel('Time (ms)')
|
57
|
+
ax.set_ylabel('Voltage (mV)')
|
58
|
+
|
59
|
+
|
60
|
+
class NEURONSimulator(Simulator):
|
61
|
+
"""
|
62
|
+
A class to represent the NEURON simulator.
|
63
|
+
|
64
|
+
Parameters
|
65
|
+
----------
|
66
|
+
temperature : float
|
67
|
+
The temperature of the simulation in Celsius.
|
68
|
+
v_init : float
|
69
|
+
The initial membrane potential of the neuron in mV.
|
70
|
+
dt : float
|
71
|
+
The time step of the simulation in ms.
|
72
|
+
cvode : bool
|
73
|
+
Whether to use the CVode variable time step integrator.
|
74
|
+
|
75
|
+
Attributes
|
76
|
+
----------
|
77
|
+
temperature : float
|
78
|
+
The temperature of the simulation in Celsius.
|
79
|
+
v_init : float
|
80
|
+
The initial membrane potential of the neuron in mV.
|
81
|
+
dt : float
|
82
|
+
The time step of the simulation in ms.
|
83
|
+
"""
|
84
|
+
|
85
|
+
def __init__(self, temperature=37, v_init=-70, dt=0.025, cvode=False):
|
86
|
+
super().__init__()
|
87
|
+
|
88
|
+
self.temperature = temperature
|
89
|
+
self.v_init = v_init * mV
|
90
|
+
self._duration = 300
|
91
|
+
|
92
|
+
self.dt = dt
|
93
|
+
self._cvode = cvode
|
94
|
+
|
95
|
+
|
96
|
+
def add_recording(self, sec, loc, var='v'):
|
97
|
+
"""
|
98
|
+
Add a recording to the simulator.
|
99
|
+
|
100
|
+
Parameters
|
101
|
+
----------
|
102
|
+
sec : Section
|
103
|
+
The section to record from.
|
104
|
+
loc : float
|
105
|
+
The location along the normalized section length to record from.
|
106
|
+
var : str
|
107
|
+
The variable to record. Default is 'v' (voltage).
|
108
|
+
"""
|
109
|
+
seg = sec(loc)
|
110
|
+
if self.recordings.get(seg):
|
111
|
+
self.remove_recording(sec, loc)
|
112
|
+
self.recordings[seg] = h.Vector().record(getattr(seg._ref, f'_ref_{var}'))
|
113
|
+
|
114
|
+
def remove_recording(self, sec, loc):
|
115
|
+
"""
|
116
|
+
Remove a recording from the simulator.
|
117
|
+
|
118
|
+
Parameters
|
119
|
+
----------
|
120
|
+
sec : Section
|
121
|
+
The section to remove the recording from.
|
122
|
+
loc : float
|
123
|
+
The location along the normalized section length to remove the recording from.
|
124
|
+
"""
|
125
|
+
seg = sec(loc)
|
126
|
+
if self.recordings.get(seg):
|
127
|
+
self.recordings[seg] = None
|
128
|
+
self.recordings.pop(seg)
|
129
|
+
|
130
|
+
def remove_all_recordings(self):
|
131
|
+
"""
|
132
|
+
Remove all recordings from the simulator.
|
133
|
+
"""
|
134
|
+
for seg in list(self.recordings.keys()):
|
135
|
+
sec, loc = seg._section, seg.x
|
136
|
+
self.remove_recording(sec, loc)
|
137
|
+
if self.recordings:
|
138
|
+
warnings.warn(f'Not all recordings were removed: {self.recordings}')
|
139
|
+
self.recordings = {}
|
140
|
+
|
141
|
+
|
142
|
+
def _init_simulation(self):
|
143
|
+
h.CVode().active(self._cvode)
|
144
|
+
h.celsius = self.temperature
|
145
|
+
h.dt = self.dt
|
146
|
+
h.stdinit()
|
147
|
+
h.init()
|
148
|
+
h.finitialize(self.v_init)
|
149
|
+
if h.cvode.active():
|
150
|
+
h.cvode.re_init()
|
151
|
+
else:
|
152
|
+
h.fcurrent()
|
153
|
+
h.frecord_init()
|
154
|
+
|
155
|
+
def run(self, duration=300):
|
156
|
+
"""
|
157
|
+
Run a simulation.
|
158
|
+
|
159
|
+
Parameters
|
160
|
+
----------
|
161
|
+
duration : float
|
162
|
+
The duration of the simulation in milliseconds.
|
163
|
+
"""
|
164
|
+
self._duration = duration
|
165
|
+
|
166
|
+
|
167
|
+
# vs = list(self.recordings.values())
|
168
|
+
Is = []
|
169
|
+
|
170
|
+
# for v in self.recordings.values():
|
171
|
+
# # v = h.Vector().record(seg._ref_v)
|
172
|
+
# vs.append(v)
|
173
|
+
|
174
|
+
t = h.Vector().record(h._ref_t)
|
175
|
+
|
176
|
+
# if self.ch is None:
|
177
|
+
# pass
|
178
|
+
# else:
|
179
|
+
# for seg in self.recordings.keys():
|
180
|
+
# if getattr(seg, f'_ref_i_{self.ch.suffix}', None) is None:
|
181
|
+
# logger.warning(
|
182
|
+
# f'No current recorded for {self.ch.suffix} at {seg}. Make i a RANGE variable in mod file.')
|
183
|
+
# continue
|
184
|
+
# I = h.Vector().record(getattr(seg, f'_ref_i_{self.ch.suffix}'))
|
185
|
+
# Is.append(I)
|
186
|
+
|
187
|
+
self._init_simulation()
|
188
|
+
|
189
|
+
h.continuerun(duration * ms)
|
190
|
+
|
191
|
+
self.t = t.to_python()
|
192
|
+
self.vs = {seg: v.to_python() for seg, v in self.recordings.items()}
|
193
|
+
|
194
|
+
|
195
|
+
def to_dict(self):
|
196
|
+
"""
|
197
|
+
Convert the simulator to a dictionary.
|
198
|
+
|
199
|
+
Returns
|
200
|
+
-------
|
201
|
+
dict
|
202
|
+
A dictionary representation of the simulator.
|
203
|
+
"""
|
204
|
+
return {
|
205
|
+
'temperature': self.temperature,
|
206
|
+
'v_init': self.v_init,
|
207
|
+
'dt': self.dt,
|
208
|
+
'duration': self._duration
|
209
|
+
}
|
210
|
+
|
211
|
+
def from_dict(self, data):
|
212
|
+
"""
|
213
|
+
Create a simulator from a dictionary.
|
214
|
+
|
215
|
+
Parameters
|
216
|
+
----------
|
217
|
+
data : dict
|
218
|
+
The dictionary representation of the simulator.
|
219
|
+
"""
|
220
|
+
self.temperature = data['temperature']
|
221
|
+
self.v_init = data['v_init']
|
222
|
+
self.dt = data['dt']
|
223
|
+
self._duration = data['duration']
|
224
|
+
|
225
|
+
|
226
|
+
class JaxleySimulator(Simulator):
|
227
|
+
"""
|
228
|
+
A class to represent a Jaxley simulator.
|
229
|
+
"""
|
230
|
+
|
231
|
+
def __init__(self):
|
232
|
+
super().__init__()
|
233
|
+
...
|
234
|
+
|
235
|
+
|
@@ -0,0 +1,73 @@
|
|
1
|
+
from neuron import h
|
2
|
+
h.load_file('stdrun.hoc')
|
3
|
+
|
4
|
+
class IClamp():
|
5
|
+
"""
|
6
|
+
A current clamp stimulus.
|
7
|
+
|
8
|
+
Parameters
|
9
|
+
----------
|
10
|
+
sec : Section
|
11
|
+
The section to place the stimulus on.
|
12
|
+
loc : float
|
13
|
+
The location along the section to place the stimulus.
|
14
|
+
Can be a float between 0 and 1.
|
15
|
+
amp : float
|
16
|
+
The amplitude of the stimulus, in nA.
|
17
|
+
delay : int
|
18
|
+
The delay of the stimulus, in ms.
|
19
|
+
dur : int
|
20
|
+
The duration of the stimulus, in ms.
|
21
|
+
|
22
|
+
Attributes
|
23
|
+
----------
|
24
|
+
sec : Section
|
25
|
+
The section to place the stimulus on.
|
26
|
+
loc : float
|
27
|
+
The location along the section to place the stimulus.
|
28
|
+
"""
|
29
|
+
|
30
|
+
def __init__(self, sec, loc, amp=0, delay=100, dur=100):
|
31
|
+
self.sec = sec
|
32
|
+
self.loc = loc
|
33
|
+
self._iclamp = h.IClamp(sec(loc)._ref)
|
34
|
+
self._iclamp.amp = amp
|
35
|
+
self._iclamp.delay = delay
|
36
|
+
self._iclamp.dur = dur
|
37
|
+
|
38
|
+
def __repr__(self):
|
39
|
+
return f"<IClamp(sec[{self.sec.idx}]({self.loc:.2f}))>"
|
40
|
+
|
41
|
+
@property
|
42
|
+
def amp(self):
|
43
|
+
"""
|
44
|
+
The amplitude of the stimulus, in nA.
|
45
|
+
"""
|
46
|
+
return self._iclamp.amp
|
47
|
+
|
48
|
+
@amp.setter
|
49
|
+
def amp(self, new_amp):
|
50
|
+
self._iclamp.amp = new_amp
|
51
|
+
|
52
|
+
|
53
|
+
@property
|
54
|
+
def delay(self):
|
55
|
+
"""
|
56
|
+
The delay of the stimulus, in ms.
|
57
|
+
"""
|
58
|
+
return self._iclamp.delay
|
59
|
+
|
60
|
+
@delay.setter
|
61
|
+
def delay(self, new_delay):
|
62
|
+
self._iclamp.delay = new_delay
|
63
|
+
|
64
|
+
@property
|
65
|
+
def dur(self):
|
66
|
+
"""
|
67
|
+
The duration of the stimulus, in ms.
|
68
|
+
"""
|
69
|
+
return self._iclamp.dur
|
70
|
+
|
71
|
+
@dur.setter
|
72
|
+
def dur(self, new_dur):
|
73
|
+
self._iclamp.dur = new_dur
|