bsb-arbor 0.0.0b1__py2.py3-none-any.whl → 4.0.0__py2.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.
Potentially problematic release.
This version of bsb-arbor might be problematic. Click here for more details.
- bsb_arbor/__init__.py +12 -12
- bsb_arbor/adapter.py +443 -364
- bsb_arbor/cell.py +81 -84
- bsb_arbor/connection.py +67 -68
- bsb_arbor/device.py +45 -48
- bsb_arbor/devices/__init__.py +3 -3
- bsb_arbor/devices/poisson_generator.py +23 -23
- bsb_arbor/devices/probe.py +55 -55
- bsb_arbor/devices/spike_recorder.py +43 -43
- bsb_arbor/simulation.py +23 -25
- {bsb_arbor-0.0.0b1.dist-info → bsb_arbor-4.0.0.dist-info}/METADATA +6 -4
- bsb_arbor-4.0.0.dist-info/RECORD +15 -0
- bsb_arbor-0.0.0b1.dist-info/RECORD +0 -15
- {bsb_arbor-0.0.0b1.dist-info → bsb_arbor-4.0.0.dist-info}/LICENSE +0 -0
- {bsb_arbor-0.0.0b1.dist-info → bsb_arbor-4.0.0.dist-info}/WHEEL +0 -0
- {bsb_arbor-0.0.0b1.dist-info → bsb_arbor-4.0.0.dist-info}/entry_points.txt +0 -0
bsb_arbor/cell.py
CHANGED
|
@@ -1,84 +1,81 @@
|
|
|
1
|
-
import abc
|
|
2
|
-
import typing
|
|
3
|
-
|
|
4
|
-
import arbor
|
|
5
|
-
from bsb import config
|
|
6
|
-
|
|
7
|
-
from
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
from
|
|
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
|
-
def
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
morphology, labels, decor
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def
|
|
60
|
-
pass
|
|
61
|
-
|
|
62
|
-
def
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def
|
|
66
|
-
return
|
|
67
|
-
|
|
68
|
-
def
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return
|
|
82
|
-
|
|
83
|
-
def make_receiver_collection(self):
|
|
84
|
-
return SingleReceiverCollection()
|
|
1
|
+
import abc
|
|
2
|
+
import typing
|
|
3
|
+
|
|
4
|
+
import arbor
|
|
5
|
+
from bsb import CellModel, ConfigurationError, config, types
|
|
6
|
+
|
|
7
|
+
from .adapter import SingleReceiverCollection
|
|
8
|
+
|
|
9
|
+
if typing.TYPE_CHECKING:
|
|
10
|
+
from bsb import PlacementSet
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@config.dynamic(
|
|
14
|
+
attr_name="model_strategy",
|
|
15
|
+
auto_classmap=True,
|
|
16
|
+
required=True,
|
|
17
|
+
classmap_entry=None,
|
|
18
|
+
)
|
|
19
|
+
class ArborCell(CellModel):
|
|
20
|
+
gap = config.attr(type=bool, default=False)
|
|
21
|
+
model = config.attr(type=types.class_(), required=True)
|
|
22
|
+
|
|
23
|
+
@abc.abstractmethod
|
|
24
|
+
def cache_population_data(self, simdata, ps: "PlacementSet"):
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
@abc.abstractmethod
|
|
28
|
+
def discard_population_data(self):
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
@abc.abstractmethod
|
|
32
|
+
def get_prefixed_catalogue(self):
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
@abc.abstractmethod
|
|
36
|
+
def get_cell_kind(self, gid):
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
@abc.abstractmethod
|
|
40
|
+
def make_receiver_collection(self):
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
def get_description(self, gid):
|
|
44
|
+
morphology, labels, decor = self.model.cable_cell_template()
|
|
45
|
+
labels = self._add_labels(gid, labels, morphology)
|
|
46
|
+
decor = self._add_decor(gid, decor)
|
|
47
|
+
cc = arbor.cable_cell(morphology, labels, decor)
|
|
48
|
+
return cc
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@config.node
|
|
52
|
+
class LIFCell(ArborCell, classmap_entry="lif"):
|
|
53
|
+
model = config.unset()
|
|
54
|
+
constants = config.dict(type=types.any_())
|
|
55
|
+
|
|
56
|
+
def cache_population_data(self, simdata, ps: "PlacementSet"):
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
def discard_population_data(self):
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
def get_prefixed_catalogue(self):
|
|
63
|
+
return None, None
|
|
64
|
+
|
|
65
|
+
def get_cell_kind(self, gid):
|
|
66
|
+
return arbor.cell_kind.lif
|
|
67
|
+
|
|
68
|
+
def get_description(self, gid):
|
|
69
|
+
cell = arbor.lif_cell(f"-1_-1", f"-1_-1_0")
|
|
70
|
+
try:
|
|
71
|
+
for k, v in self.constants.items():
|
|
72
|
+
setattr(cell, k, v)
|
|
73
|
+
except AttributeError:
|
|
74
|
+
node_name = type(self).constants.get_node_name(self)
|
|
75
|
+
raise ConfigurationError(
|
|
76
|
+
f"'{k}' is not a valid LIF parameter in '{node_name}'."
|
|
77
|
+
) from None
|
|
78
|
+
return cell
|
|
79
|
+
|
|
80
|
+
def make_receiver_collection(self):
|
|
81
|
+
return SingleReceiverCollection()
|
bsb_arbor/connection.py
CHANGED
|
@@ -1,68 +1,67 @@
|
|
|
1
|
-
import arbor
|
|
2
|
-
import tqdm
|
|
3
|
-
from bsb import config
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
self.
|
|
10
|
-
self.
|
|
11
|
-
self.
|
|
12
|
-
self.
|
|
13
|
-
self.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
b
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
self.
|
|
37
|
-
self.
|
|
38
|
-
self.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
conn
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
)
|
|
68
|
-
return arbor.gap_junction_connection(g, l, self.weight)
|
|
1
|
+
import arbor
|
|
2
|
+
import tqdm
|
|
3
|
+
from bsb import ConnectionModel, config
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Receiver:
|
|
7
|
+
def __init__(self, conn_model, from_gid, loc_from, loc_on, index=-1):
|
|
8
|
+
self.conn_model = conn_model
|
|
9
|
+
self.from_gid = from_gid
|
|
10
|
+
self.loc_from = loc_from
|
|
11
|
+
self.loc_on = loc_on
|
|
12
|
+
self.synapse = arbor.synapse("expsyn")
|
|
13
|
+
self.index = index
|
|
14
|
+
|
|
15
|
+
def from_(self):
|
|
16
|
+
b, p = self.loc_from
|
|
17
|
+
return arbor.cell_global_label(self.from_gid, f"{b}_{p}")
|
|
18
|
+
|
|
19
|
+
def on(self):
|
|
20
|
+
# self.index is set on us by the ReceiverCollection when we are appended.
|
|
21
|
+
b, p = self.loc_on
|
|
22
|
+
return arbor.cell_local_label(f"{b}_{p}_{self.index}")
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def weight(self):
|
|
26
|
+
return self.conn_model.weight
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def delay(self):
|
|
30
|
+
return self.conn_model.delay
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Connection:
|
|
34
|
+
def __init__(self, pre_loc, post_loc):
|
|
35
|
+
self.from_id = pre_loc[0]
|
|
36
|
+
self.to_id = post_loc[0]
|
|
37
|
+
self.pre_loc = pre_loc[1:]
|
|
38
|
+
self.post_loc = post_loc[1:]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@config.node
|
|
42
|
+
class ArborConnection(ConnectionModel):
|
|
43
|
+
gap = config.attr(type=bool, default=False)
|
|
44
|
+
weight = config.attr(type=float, required=True)
|
|
45
|
+
delay = config.attr(type=float, required=True)
|
|
46
|
+
|
|
47
|
+
def create_gap_junctions_on(self, gj_on_gid, conns):
|
|
48
|
+
for pre_loc, post_loc in conns:
|
|
49
|
+
conn = Connection(pre_loc, post_loc)
|
|
50
|
+
gj_on_gid.setdefault(conn.from_id, []).append(conn)
|
|
51
|
+
|
|
52
|
+
def create_connections_on(self, conns_on_gid, conns, pop_pre, pop_post):
|
|
53
|
+
for pre_loc, post_loc in tqdm.tqdm(conns, total=len(conns), desc=self.name):
|
|
54
|
+
conns_on_gid[post_loc[0] + pop_post.offset].append(
|
|
55
|
+
Receiver(self, pre_loc[0] + pop_pre.offset, pre_loc[1:], post_loc[1:])
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def create_connections_from(self, conns_from_gid, conns, pop_pre, pop_post):
|
|
59
|
+
for pre_loc, post_loc in conns:
|
|
60
|
+
conns_from_gid[int(pre_loc[0] + pop_pre.offset)].append(pre_loc[1:])
|
|
61
|
+
|
|
62
|
+
def gap_junction(self, conn):
|
|
63
|
+
l = arbor.cell_local_label(f"gap_{conn.to_compartment.id}")
|
|
64
|
+
g = arbor.cell_global_label(
|
|
65
|
+
int(conn.from_id), f"gap_{conn.from_compartment.id}"
|
|
66
|
+
)
|
|
67
|
+
return arbor.gap_junction_connection(g, l, self.weight)
|
bsb_arbor/device.py
CHANGED
|
@@ -1,48 +1,45 @@
|
|
|
1
|
-
import abc
|
|
2
|
-
|
|
3
|
-
import arbor
|
|
4
|
-
from bsb import config
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def
|
|
17
|
-
self.
|
|
18
|
-
|
|
19
|
-
def
|
|
20
|
-
self.
|
|
21
|
-
|
|
22
|
-
def
|
|
23
|
-
self.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return sim.
|
|
34
|
-
|
|
35
|
-
def
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
@abc.abstractmethod
|
|
47
|
-
def implement_generators(self, simdata, target):
|
|
48
|
-
pass
|
|
1
|
+
import abc
|
|
2
|
+
|
|
3
|
+
import arbor
|
|
4
|
+
from bsb import DeviceModel, Targetting, config, types
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@config.dynamic(attr_name="device", auto_classmap=True, classmap_entry=None)
|
|
8
|
+
class ArborDevice(DeviceModel):
|
|
9
|
+
targetting = config.attr(type=Targetting, required=True)
|
|
10
|
+
resolution = config.attr(type=float)
|
|
11
|
+
sampling_policy = config.attr(type=types.in_(["exact"]))
|
|
12
|
+
|
|
13
|
+
def __init__(self, **kwargs):
|
|
14
|
+
self._probe_ids = []
|
|
15
|
+
|
|
16
|
+
def __boot__(self):
|
|
17
|
+
self.resolution = self.resolution or self.simulation.resolution
|
|
18
|
+
|
|
19
|
+
def register_probe_id(self, gid, tag):
|
|
20
|
+
self._probe_ids.append((gid, tag))
|
|
21
|
+
|
|
22
|
+
def prepare_samples(self, simdata):
|
|
23
|
+
self._handles = [
|
|
24
|
+
self.sample(simdata.arbor_sim, probe_id) for probe_id in self._probe_ids
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
def sample(self, sim, probe_id):
|
|
28
|
+
schedule = arbor.regular_schedule(self.resolution)
|
|
29
|
+
sampling_policy = getattr(arbor.sampling_policy, self.sampling_policy)
|
|
30
|
+
return sim.sample(probe_id, schedule, sampling_policy)
|
|
31
|
+
|
|
32
|
+
def get_samples(self, sim):
|
|
33
|
+
return [sim.samples(handle) for handle in self._handles]
|
|
34
|
+
|
|
35
|
+
def get_meta(self):
|
|
36
|
+
attrs = ("name", "sampling_policy", "resolution")
|
|
37
|
+
return dict(zip(attrs, (getattr(self, attr) for attr in attrs)))
|
|
38
|
+
|
|
39
|
+
@abc.abstractmethod
|
|
40
|
+
def implement_probes(self, simdata, target):
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
@abc.abstractmethod
|
|
44
|
+
def implement_generators(self, simdata, target):
|
|
45
|
+
pass
|
bsb_arbor/devices/__init__.py
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
from .poisson_generator import PoissonGenerator
|
|
2
|
-
from .probe import Probe
|
|
3
|
-
from .spike_recorder import SpikeRecorder
|
|
1
|
+
from .poisson_generator import PoissonGenerator
|
|
2
|
+
from .probe import Probe
|
|
3
|
+
from .spike_recorder import SpikeRecorder
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import arbor
|
|
2
|
-
from bsb import config
|
|
3
|
-
|
|
4
|
-
from ..connection import Receiver
|
|
5
|
-
from ..device import ArborDevice
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
@config.node
|
|
9
|
-
class PoissonGenerator(ArborDevice, classmap_entry="poisson_generator"):
|
|
10
|
-
record = config.attr(type=bool, default=True)
|
|
11
|
-
rate = config.attr(type=float, required=True)
|
|
12
|
-
weight = config.attr(type=float, required=True)
|
|
13
|
-
delay = config.attr(type=float, required=True)
|
|
14
|
-
|
|
15
|
-
def implement_probes(self, simdata, gid):
|
|
16
|
-
return []
|
|
17
|
-
|
|
18
|
-
def implement_generators(self, simdata, gid):
|
|
19
|
-
target = Receiver(self, None, [-1, -1], [-1, -1], 0).on()
|
|
20
|
-
gen = arbor.event_generator(
|
|
21
|
-
target, self.weight, arbor.poisson_schedule(0, self.rate / 1000, gid)
|
|
22
|
-
)
|
|
23
|
-
return [gen]
|
|
1
|
+
import arbor
|
|
2
|
+
from bsb import config
|
|
3
|
+
|
|
4
|
+
from ..connection import Receiver
|
|
5
|
+
from ..device import ArborDevice
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@config.node
|
|
9
|
+
class PoissonGenerator(ArborDevice, classmap_entry="poisson_generator"):
|
|
10
|
+
record = config.attr(type=bool, default=True)
|
|
11
|
+
rate = config.attr(type=float, required=True)
|
|
12
|
+
weight = config.attr(type=float, required=True)
|
|
13
|
+
delay = config.attr(type=float, required=True)
|
|
14
|
+
|
|
15
|
+
def implement_probes(self, simdata, gid):
|
|
16
|
+
return []
|
|
17
|
+
|
|
18
|
+
def implement_generators(self, simdata, gid):
|
|
19
|
+
target = Receiver(self, None, [-1, -1], [-1, -1], 0).on()
|
|
20
|
+
gen = arbor.event_generator(
|
|
21
|
+
target, self.weight, arbor.poisson_schedule(0, self.rate / 1000, gid)
|
|
22
|
+
)
|
|
23
|
+
return [gen]
|
bsb_arbor/devices/probe.py
CHANGED
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
import arbor
|
|
2
|
-
from bsb.exceptions import ConfigurationError
|
|
3
|
-
|
|
4
|
-
from ..device import ArborDevice
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class Probe(ArborDevice):
|
|
8
|
-
required = ["targetting", "probe_type"]
|
|
9
|
-
|
|
10
|
-
def get_probe_name(self):
|
|
11
|
-
return f"cable_probe_{self.probe_type}"
|
|
12
|
-
|
|
13
|
-
def validate_specifics(self):
|
|
14
|
-
|
|
15
|
-
if self.get_probe_name() not in vars(arbor):
|
|
16
|
-
raise ConfigurationError(
|
|
17
|
-
f"`{self.probe_type}` is not a valid probe type for `{self.name}`"
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
def implement(self, target):
|
|
21
|
-
probe_args = ("where", "mechanism", "ion", "state")
|
|
22
|
-
kwargs = dict((k, getattr(self, k)) for k in probe_args if hasattr(self, k))
|
|
23
|
-
return [getattr(arbor, self.get_probe_name())(**kwargs)]
|
|
24
|
-
|
|
25
|
-
def prepare_samples(self, sim):
|
|
26
|
-
super().prepare_samples(sim)
|
|
27
|
-
for probe_id, handle in zip(self._probe_ids, self._handles):
|
|
28
|
-
self.adapter.result.add(ProbeRecorder(self, sim, probe_id, handle))
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class ProbeRecorder:
|
|
32
|
-
def __init__(self, device, sim, probe_id, handle):
|
|
33
|
-
self.path = ("recorders", device.name, *probe_id)
|
|
34
|
-
self.meta = device.get_meta()
|
|
35
|
-
self.meta["probe_id"] = probe_id
|
|
36
|
-
self._sim = sim
|
|
37
|
-
self._handle = handle
|
|
38
|
-
|
|
39
|
-
def samples(self):
|
|
40
|
-
return self._sim.samples(self._handle)
|
|
41
|
-
|
|
42
|
-
def multi_collect(self):
|
|
43
|
-
for i, sample in enumerate(self.samples()):
|
|
44
|
-
yield ProbeRecorderSample(self, i, sample)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
class ProbeRecorderSample:
|
|
48
|
-
def __init__(self, parent, i, sample):
|
|
49
|
-
self.path = tuple(list(parent.get_path()) + [i])
|
|
50
|
-
self.data = sample[0]
|
|
51
|
-
self.meta = parent.meta.copy()
|
|
52
|
-
self.meta["location"] = str(sample[1])
|
|
53
|
-
|
|
54
|
-
def get_data(self):
|
|
55
|
-
return self.data
|
|
1
|
+
import arbor
|
|
2
|
+
from bsb.exceptions import ConfigurationError
|
|
3
|
+
|
|
4
|
+
from ..device import ArborDevice
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Probe(ArborDevice):
|
|
8
|
+
required = ["targetting", "probe_type"]
|
|
9
|
+
|
|
10
|
+
def get_probe_name(self):
|
|
11
|
+
return f"cable_probe_{self.probe_type}"
|
|
12
|
+
|
|
13
|
+
def validate_specifics(self):
|
|
14
|
+
|
|
15
|
+
if self.get_probe_name() not in vars(arbor):
|
|
16
|
+
raise ConfigurationError(
|
|
17
|
+
f"`{self.probe_type}` is not a valid probe type for `{self.name}`"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
def implement(self, target):
|
|
21
|
+
probe_args = ("where", "mechanism", "ion", "state")
|
|
22
|
+
kwargs = dict((k, getattr(self, k)) for k in probe_args if hasattr(self, k))
|
|
23
|
+
return [getattr(arbor, self.get_probe_name())(**kwargs)]
|
|
24
|
+
|
|
25
|
+
def prepare_samples(self, sim):
|
|
26
|
+
super().prepare_samples(sim)
|
|
27
|
+
for probe_id, handle in zip(self._probe_ids, self._handles):
|
|
28
|
+
self.adapter.result.add(ProbeRecorder(self, sim, probe_id, handle))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ProbeRecorder:
|
|
32
|
+
def __init__(self, device, sim, probe_id, handle):
|
|
33
|
+
self.path = ("recorders", device.name, *probe_id)
|
|
34
|
+
self.meta = device.get_meta()
|
|
35
|
+
self.meta["probe_id"] = probe_id
|
|
36
|
+
self._sim = sim
|
|
37
|
+
self._handle = handle
|
|
38
|
+
|
|
39
|
+
def samples(self):
|
|
40
|
+
return self._sim.samples(self._handle)
|
|
41
|
+
|
|
42
|
+
def multi_collect(self):
|
|
43
|
+
for i, sample in enumerate(self.samples()):
|
|
44
|
+
yield ProbeRecorderSample(self, i, sample)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class ProbeRecorderSample:
|
|
48
|
+
def __init__(self, parent, i, sample):
|
|
49
|
+
self.path = tuple(list(parent.get_path()) + [i])
|
|
50
|
+
self.data = sample[0]
|
|
51
|
+
self.meta = parent.meta.copy()
|
|
52
|
+
self.meta["location"] = str(sample[1])
|
|
53
|
+
|
|
54
|
+
def get_data(self):
|
|
55
|
+
return self.data
|
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
import neo
|
|
2
|
-
from bsb import config
|
|
3
|
-
from bsb.services import MPI
|
|
4
|
-
|
|
5
|
-
from ..device import ArborDevice
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
@config.node
|
|
9
|
-
class SpikeRecorder(ArborDevice, classmap_entry="spike_recorder"):
|
|
10
|
-
def boot(self):
|
|
11
|
-
self._gids = set()
|
|
12
|
-
|
|
13
|
-
def prepare_samples(self, simdata):
|
|
14
|
-
super().prepare_samples(simdata)
|
|
15
|
-
if not MPI.get_rank():
|
|
16
|
-
|
|
17
|
-
def record_device_spikes(segment):
|
|
18
|
-
spiketrain = list()
|
|
19
|
-
senders = list()
|
|
20
|
-
for (gid, index), time in simdata.arbor_sim.spikes():
|
|
21
|
-
if index == 0 and gid in self._gids:
|
|
22
|
-
spiketrain.append(time)
|
|
23
|
-
senders.append(gid)
|
|
24
|
-
segment.spiketrains.append(
|
|
25
|
-
neo.SpikeTrain(
|
|
26
|
-
spiketrain,
|
|
27
|
-
units="ms",
|
|
28
|
-
senders=senders,
|
|
29
|
-
t_stop=self.simulation.duration,
|
|
30
|
-
device=self.name,
|
|
31
|
-
gids=list(self._gids),
|
|
32
|
-
pop_size=len(self._gids),
|
|
33
|
-
)
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
simdata.result.create_recorder(record_device_spikes)
|
|
37
|
-
|
|
38
|
-
def implement_probes(self, simdata, gid):
|
|
39
|
-
self._gids.add(gid)
|
|
40
|
-
return []
|
|
41
|
-
|
|
42
|
-
def implement_generators(self, simdata, gid):
|
|
43
|
-
return []
|
|
1
|
+
import neo
|
|
2
|
+
from bsb import config
|
|
3
|
+
from bsb.services import MPI
|
|
4
|
+
|
|
5
|
+
from ..device import ArborDevice
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@config.node
|
|
9
|
+
class SpikeRecorder(ArborDevice, classmap_entry="spike_recorder"):
|
|
10
|
+
def boot(self):
|
|
11
|
+
self._gids = set()
|
|
12
|
+
|
|
13
|
+
def prepare_samples(self, simdata):
|
|
14
|
+
super().prepare_samples(simdata)
|
|
15
|
+
if not MPI.get_rank():
|
|
16
|
+
|
|
17
|
+
def record_device_spikes(segment):
|
|
18
|
+
spiketrain = list()
|
|
19
|
+
senders = list()
|
|
20
|
+
for (gid, index), time in simdata.arbor_sim.spikes():
|
|
21
|
+
if index == 0 and gid in self._gids:
|
|
22
|
+
spiketrain.append(time)
|
|
23
|
+
senders.append(gid)
|
|
24
|
+
segment.spiketrains.append(
|
|
25
|
+
neo.SpikeTrain(
|
|
26
|
+
spiketrain,
|
|
27
|
+
units="ms",
|
|
28
|
+
senders=senders,
|
|
29
|
+
t_stop=self.simulation.duration,
|
|
30
|
+
device=self.name,
|
|
31
|
+
gids=list(self._gids),
|
|
32
|
+
pop_size=len(self._gids),
|
|
33
|
+
)
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
simdata.result.create_recorder(record_device_spikes)
|
|
37
|
+
|
|
38
|
+
def implement_probes(self, simdata, gid):
|
|
39
|
+
self._gids.add(gid)
|
|
40
|
+
return []
|
|
41
|
+
|
|
42
|
+
def implement_generators(self, simdata, gid):
|
|
43
|
+
return []
|