forked from NeuralEnsemble/PyNN
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathmorphology.py
More file actions
276 lines (207 loc) · 10.3 KB
/
morphology.py
File metadata and controls
276 lines (207 loc) · 10.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
"""
"""
import numpy as np
from .. import morphology as base_morphology
# --- MorphologyFilters ---
class with_label(base_morphology.with_label):
def __call__(self, morphology, **kwargs):
section_index = np.array([], dtype=int)
labels = list(self.labels)
for label in labels:
if label in morphology.section_groups:
# ids.extend([id(seg) for seg in morphology.section_groups[label]])
section_index = np.hstack((section_index, morphology.section_groups[label]))
labels.remove(label)
if labels:
for i, segment in enumerate(morphology.segments):
if segment.name in labels:
# ids.append(id(segment))
section_index = np.hstack((section_index, np.array([i])))
labels.remove(segment.name)
if labels:
raise ValueError("No sections or groups match label '{}'".format("', '".join(labels)))
return section_index
class dendrites(base_morphology.dendrites):
def __call__(self, morphology, filter_by_section=False):
"""Return an index (integer NumPy array) that can be used
to retrieve the sections corresponding to the filter. """
from morphio import SectionType
section_index = np.array([], dtype=int)
for label in (SectionType.apical_dendrite, SectionType.basal_dendrite):
if label in morphology.section_groups:
section_index = np.hstack((section_index, morphology.section_groups[label]))
if filter_by_section:
section_index = np.intersect1d(section_index,
np.fromiter(filter_by_section, dtype=int))
if section_index.size < 1:
raise Exception("No neurites labelled as dendrites")
return section_index
class apical_dendrites(base_morphology.apical_dendrites):
def __call__(self, morphology, filter_by_section=False):
from morphio import SectionType
if SectionType.apical_dendrite in morphology.section_groups:
section_index = morphology.section_groups[SectionType.apical_dendrite]
if filter_by_section:
section_index = np.intersect1d(section_index,
np.fromiter(filter_by_section, dtype=int))
return section_index
else:
raise Exception("No neurites labelled as apical dendrite")
class basal_dendrites(base_morphology.basal_dendrites):
def __call__(self, morphology, filter_by_section=False):
from morphio import SectionType
if SectionType.basal_dendrite in morphology.section_groups:
section_index = morphology.section_groups[SectionType.basal_dendrite]
if filter_by_section:
section_index = np.intersect1d(section_index,
np.fromiter(filter_by_section, dtype=int))
return section_index
else:
raise Exception("No neurites labelled as basal dendrite")
class axon(base_morphology.axon):
def __call__(self, morphology, filter_by_section=False):
from morphio import SectionType
if SectionType.axon in morphology.section_groups:
section_index = morphology.section_groups[SectionType.axon]
if filter_by_section:
section_index = np.intersect1d(section_index,
np.fromiter(filter_by_section, dtype=int))
return section_index
else:
raise Exception("No neurites labelled as axon")
class soma(base_morphology.axon):
def __call__(self, morphology, filter_by_section=False):
from morphio import SectionType
if SectionType.soma in morphology.section_groups:
section_index = morphology.section_groups[SectionType.soma]
if filter_by_section:
section_index = np.intersect1d(section_index,
np.fromiter(filter_by_section, dtype=int))
return section_index
else:
raise Exception("No neurites labelled as soma")
class random_section(base_morphology.random_section):
def __call__(self, morphology, **kwargs):
section_index = self.f(morphology, **kwargs)
if len(section_index) < 1:
raise Exception("List of sections is empty.")
return [np.random.choice(section_index)]
sample = random_section # alias
# --- IonChannelDistributions ---
class HasSelector:
def get_with_label_selector(self, label):
return with_label(label)
class uniform(base_morphology.uniform, HasSelector):
def value_in(self, morphology, index):
if hasattr(self.selector, "labels") and self.selector.labels == ('all',):
return self.value_provider
elif hasattr(self.selector, "labels") and self.selector.labels == ('soma',):
if index == morphology.soma_index:
return self.value_provider
else:
return self.absence
elif isinstance(self.selector, base_morphology.MorphologyFilter):
selected_indices = self.selector(morphology)
if index in selected_indices:
return self.value_provider
else:
return self.absence
else:
raise NotImplementedError("selector '{}' not yet supported".format(self.selector))
class by_distance(base_morphology.by_distance, HasSelector):
def value_in(self, morphology, index):
distance_function = self.value_provider
if isinstance(self.selector, base_morphology.MorphologyFilter):
selected_indices = self.selector(morphology) # need to cache this, or allow index to be an array
if index in selected_indices:
distance = morphology.get_distance(index)
return distance_function(distance)
else:
return self.absence
else:
raise NotImplementedError("selector '{}' not yet supported".format(self.selector))
class by_diameter(base_morphology.by_diameter, HasSelector):
"""Distribution as a function of neurite diameter."""
def value_in(self, morphology, index):
diameter_function = self.value_provider
if isinstance(self.selector, base_morphology.MorphologyFilter):
selected_indices = self.selector(morphology) # need to cache this, or allow index to be an array
if index in selected_indices:
diameter = morphology.get_diameter(index)
return diameter_function(diameter)
else:
return self.absence
else:
raise NotImplementedError("selector '{}' not yet supported".format(self.selector))
# --- LocationGenerators ---
class LabelledLocations(base_morphology.LabelledLocations, HasSelector):
def generate_locations(self, morphology, label_prefix, cell):
locations = []
for label in self.labels:
if label in cell.section_labels:
section_index = cell.section_labels[label]
assert len(section_index) == 1, "todo"
section_id = list(section_index)[0]
section = cell.sections[section_id]
location_label = f"{label_prefix}{label}"
cell.locations[location_label] = Location(section, section_id, 0.5, label=location_label)
locations.append(location_label)
else:
raise ValueError("Cell has no location labelled '{}'".format(label))
return locations
class at_distances(base_morphology.at_distances, HasSelector):
def generate_locations(self, morphology, label_prefix, cell):
# todo: this only works for a single section at present
assert len(cell.sections) == 1, "not implemented"
section_index = self.selector(morphology)
assert len(section_index) == 1
section = cell.sections[section_index[0]]
locations = []
for d in self.distances:
location_label = f"d-{d}"
if label_prefix:
location_label = f"{label_prefix}-{location_label}"
cell.locations[location_label] = Location(section, section_index, d, label=location_label)
locations.append(location_label)
return locations
class random_placement(base_morphology.random_placement, HasSelector):
def generate_locations(self, morphology, label_prefix, cell):
locations = []
for index, section_id in enumerate(cell.sections):
density = self.density_function.value_in(morphology, index)
section = cell.sections[section_id]
n_synapses = density * section.L
if n_synapses > 0:
n_synapses, remainder = divmod(n_synapses, 1)
rnd = np.random # todo: use the RNG from the parent Population
if rnd.uniform() < remainder:
n_synapses += 1
for i in range(int(n_synapses)):
location_label = f"random-{index}"
if label_prefix:
location_label = f"{label_prefix}-{location_label}"
cell.locations[location_label] = Location(section, section_id, 0.5, label=location_label)
# todo: also randomize the position parameter?
locations.append(location_label)
return locations
class centre(base_morphology.centre, HasSelector):
def generate_locations(self, morphology, label_prefix, cell):
section_index = self.selector(morphology)
section_id = section_index[len(section_index)//2]
section = cell.sections[section_id]
location_label = "centre" # todo: add a part coming from selector
if label_prefix:
location_label = f"{label_prefix}-{location_label}"
cell.locations[location_label] = Location(section, section_id, 0.5, label=location_label)
# todo: also randomize the position parameter?
return [location_label]
center = centre # for trans-Atlantic compatibility
# --- Location ---
class Location:
def __init__(self, section, section_id, position, label=""):
self.section = section
self.section_id = section_id
self.position = position
self.label = label
def get_section_and_position(self):
return (self.section, self.section_id, self.position)