bsb-arbor 4.0.0__py2.py3-none-any.whl → 4.1.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/cell.py CHANGED
@@ -1,81 +1,81 @@
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()
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 * getattr(cell, k).units)
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,67 +1,67 @@
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)
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,45 +1,45 @@
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
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
@@ -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,26 @@
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 arbor import units as U
3
+ from bsb import config
4
+
5
+ from ..connection import Receiver
6
+ from ..device import ArborDevice
7
+
8
+
9
+ @config.node
10
+ class PoissonGenerator(ArborDevice, classmap_entry="poisson_generator"):
11
+ record = config.attr(type=bool, default=True)
12
+ rate = config.attr(type=float, required=True)
13
+ weight = config.attr(type=float, required=True)
14
+ delay = config.attr(type=float, required=True)
15
+
16
+ def implement_probes(self, simdata, gid):
17
+ return []
18
+
19
+ def implement_generators(self, simdata, gid):
20
+ target = Receiver(self, None, [-1, -1], [-1, -1], 0).on()
21
+ gen = arbor.event_generator(
22
+ target,
23
+ self.weight,
24
+ arbor.poisson_schedule(tstart=0 * U.ms, freq=self.rate * U.Hz, seed=gid),
25
+ )
26
+ return [gen]
@@ -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 []