bsb-nest 4.2.1__tar.gz → 4.3.1__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 bsb-nest might be problematic. Click here for more details.
- {bsb_nest-4.2.1 → bsb_nest-4.3.1}/PKG-INFO +3 -3
- {bsb_nest-4.2.1 → bsb_nest-4.3.1}/README.md +1 -1
- {bsb_nest-4.2.1 → bsb_nest-4.3.1}/bsb_nest/__init__.py +1 -1
- bsb_nest-4.3.1/bsb_nest/device.py +122 -0
- {bsb_nest-4.2.1 → bsb_nest-4.3.1}/bsb_nest/devices/__init__.py +1 -0
- {bsb_nest-4.2.1 → bsb_nest-4.3.1}/bsb_nest/devices/multimeter.py +18 -10
- {bsb_nest-4.2.1 → bsb_nest-4.3.1}/bsb_nest/devices/poisson_generator.py +1 -0
- bsb_nest-4.3.1/bsb_nest/devices/sinusoidal_poisson_generator.py +63 -0
- {bsb_nest-4.2.1 → bsb_nest-4.3.1}/pyproject.toml +1 -1
- bsb_nest-4.2.1/bsb_nest/device.py +0 -72
- {bsb_nest-4.2.1 → bsb_nest-4.3.1}/LICENSE +0 -0
- {bsb_nest-4.2.1 → bsb_nest-4.3.1}/bsb_nest/adapter.py +0 -0
- {bsb_nest-4.2.1 → bsb_nest-4.3.1}/bsb_nest/cell.py +0 -0
- {bsb_nest-4.2.1 → bsb_nest-4.3.1}/bsb_nest/connection.py +0 -0
- {bsb_nest-4.2.1 → bsb_nest-4.3.1}/bsb_nest/devices/dc_generator.py +0 -0
- {bsb_nest-4.2.1 → bsb_nest-4.3.1}/bsb_nest/devices/spike_recorder.py +0 -0
- {bsb_nest-4.2.1 → bsb_nest-4.3.1}/bsb_nest/distributions.py +0 -0
- {bsb_nest-4.2.1 → bsb_nest-4.3.1}/bsb_nest/exceptions.py +0 -0
- {bsb_nest-4.2.1 → bsb_nest-4.3.1}/bsb_nest/simulation.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: bsb-nest
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.3.1
|
|
4
4
|
Summary: NEST simulation adapter for the BSB framework.
|
|
5
5
|
Author-email: Robin De Schepper <robingilbert.deschepper@unipv.it>
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -24,7 +24,7 @@ Provides-Extra: dev
|
|
|
24
24
|
Provides-Extra: parallel
|
|
25
25
|
Provides-Extra: test
|
|
26
26
|
|
|
27
|
-
[](https://github.com/dbbs-lab/bsb-nest/actions/workflows/main.yml)
|
|
28
28
|
[](https://github.com/psf/black)
|
|
29
29
|
|
|
30
30
|
# bsb-nest
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[](https://github.com/dbbs-lab/bsb-nest/actions/workflows/main.yml)
|
|
2
2
|
[](https://github.com/psf/black)
|
|
3
3
|
|
|
4
4
|
# bsb-nest
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
import warnings
|
|
3
|
+
|
|
4
|
+
import nest
|
|
5
|
+
from bsb import DeviceModel, SimulationData, Targetting, config, refs, types
|
|
6
|
+
|
|
7
|
+
if typing.TYPE_CHECKING:
|
|
8
|
+
from .adapter import NestAdapter
|
|
9
|
+
from .simulation import NestSimulation
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@config.node
|
|
13
|
+
class NestRule:
|
|
14
|
+
rule = config.attr(type=str, required=True)
|
|
15
|
+
constants = config.catch_all(type=types.any_())
|
|
16
|
+
cell_models = config.reflist(refs.sim_cell_model_ref)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@config.dynamic(attr_name="device", auto_classmap=True, default="external")
|
|
20
|
+
class NestDevice(DeviceModel):
|
|
21
|
+
weight = config.attr(type=float, required=True)
|
|
22
|
+
"""weight of the connection between the device and its target"""
|
|
23
|
+
delay = config.attr(type=float, required=True)
|
|
24
|
+
"""delay of the transmission between the device and its target"""
|
|
25
|
+
targetting = config.attr(
|
|
26
|
+
type=types.or_(Targetting, NestRule), default=dict, call_default=True
|
|
27
|
+
)
|
|
28
|
+
"""Targets of the device, which should be either a population or a nest rule"""
|
|
29
|
+
receptor_type = config.attr(type=int, required=False, default=0)
|
|
30
|
+
"""Integer ID of the postsynaptic target receptor"""
|
|
31
|
+
|
|
32
|
+
def get_dict_targets(
|
|
33
|
+
self,
|
|
34
|
+
adapter: "NestAdapter",
|
|
35
|
+
simulation: "NestSimulation",
|
|
36
|
+
simdata: "SimulationData",
|
|
37
|
+
) -> dict:
|
|
38
|
+
"""
|
|
39
|
+
Get a dictionary from a target group to its NEST Collection
|
|
40
|
+
for each target group of the device.
|
|
41
|
+
|
|
42
|
+
:param bsb_nest.NestAdapter adapter:
|
|
43
|
+
:param bsb_nest.NestSimulation simulation: Nest simulation instance
|
|
44
|
+
:param bsb.SimulationData simdata: Simulation data instance
|
|
45
|
+
:return: dictionary of device target group to NEST Collection
|
|
46
|
+
:rtype: dict
|
|
47
|
+
"""
|
|
48
|
+
if isinstance(self.targetting, Targetting):
|
|
49
|
+
node_collector = self.targetting.get_targets(adapter, simulation, simdata)
|
|
50
|
+
else:
|
|
51
|
+
node_collector = {
|
|
52
|
+
model: simdata.populations[model][targets]
|
|
53
|
+
for model, targets in simdata.populations.items()
|
|
54
|
+
if not self.targetting.cell_models or model in self.targetting.cell_models
|
|
55
|
+
}
|
|
56
|
+
return node_collector
|
|
57
|
+
|
|
58
|
+
@staticmethod
|
|
59
|
+
def _flatten_nodes_ids(dict_targets):
|
|
60
|
+
return sum(dict_targets.values(), start=nest.NodeCollection())
|
|
61
|
+
|
|
62
|
+
@staticmethod
|
|
63
|
+
def _invert_targets_dict(dict_targets):
|
|
64
|
+
return {elem: k.name for k, v in dict_targets.items() for elem in v.tolist()}
|
|
65
|
+
|
|
66
|
+
def get_target_nodes(
|
|
67
|
+
self,
|
|
68
|
+
adapter: "NestAdapter",
|
|
69
|
+
simulation: "NestSimulation",
|
|
70
|
+
simdata: "SimulationData",
|
|
71
|
+
):
|
|
72
|
+
"""
|
|
73
|
+
Get the NEST Collection of the targets of the device.
|
|
74
|
+
|
|
75
|
+
:param bsb_nest.NestAdapter adapter:
|
|
76
|
+
:param bsb_nest.NestSimulation simulation: Nest simulation instance
|
|
77
|
+
:param bsb.SimulationData simdata: Simulation data instance
|
|
78
|
+
:return: Flattened NEST collection with all the targets of the device
|
|
79
|
+
"""
|
|
80
|
+
targets_dict = self.get_dict_targets(adapter, simulation, simdata)
|
|
81
|
+
return self._flatten_nodes_ids(targets_dict)
|
|
82
|
+
|
|
83
|
+
def connect_to_nodes(self, device, nodes):
|
|
84
|
+
if len(nodes) == 0:
|
|
85
|
+
warnings.warn(f"{self.name} has no targets")
|
|
86
|
+
else:
|
|
87
|
+
try:
|
|
88
|
+
nest.Connect(
|
|
89
|
+
device,
|
|
90
|
+
nodes,
|
|
91
|
+
syn_spec={
|
|
92
|
+
"weight": self.weight,
|
|
93
|
+
"delay": self.delay,
|
|
94
|
+
"receptor_type": self.receptor_type,
|
|
95
|
+
},
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
except Exception as e:
|
|
99
|
+
if "does not send output" not in str(e):
|
|
100
|
+
raise
|
|
101
|
+
nest.Connect(
|
|
102
|
+
nodes,
|
|
103
|
+
device,
|
|
104
|
+
syn_spec={"weight": self.weight, "delay": self.delay},
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
def register_device(self, simdata, device):
|
|
108
|
+
simdata.devices[self] = device
|
|
109
|
+
return device
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@config.node
|
|
113
|
+
class ExtNestDevice(NestDevice, classmap_entry="external"):
|
|
114
|
+
nest_model = config.attr(type=str, required=True)
|
|
115
|
+
constants = config.dict(type=types.or_(types.number(), str))
|
|
116
|
+
|
|
117
|
+
def implement(self, adapter, simulation, simdata):
|
|
118
|
+
simdata.devices[self] = device = nest.Create(
|
|
119
|
+
self.nest_model, params=self.constants
|
|
120
|
+
)
|
|
121
|
+
nodes = self.get_target_nodes(adapter, simulation, simdata)
|
|
122
|
+
self.connect_to_nodes(device, nodes)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import nest
|
|
2
|
+
import numpy as np
|
|
2
3
|
import quantities as pq
|
|
3
4
|
from bsb import ConfigurationError, _util, config, types
|
|
4
5
|
from neo import AnalogSignal
|
|
@@ -24,7 +25,9 @@ class Multimeter(NestDevice, classmap_entry="multimeter"):
|
|
|
24
25
|
|
|
25
26
|
def implement(self, adapter, simulation, simdata):
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
targets_dict = self.get_dict_targets(adapter, simulation, simdata)
|
|
29
|
+
nodes = self._flatten_nodes_ids(targets_dict)
|
|
30
|
+
inv_targets = self._invert_targets_dict(targets_dict)
|
|
28
31
|
device = self.register_device(
|
|
29
32
|
simdata,
|
|
30
33
|
nest.Create(
|
|
@@ -38,15 +41,20 @@ class Multimeter(NestDevice, classmap_entry="multimeter"):
|
|
|
38
41
|
self.connect_to_nodes(device, nodes)
|
|
39
42
|
|
|
40
43
|
def recorder(segment):
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
senders = device.events["senders"]
|
|
45
|
+
for sender in np.unique(senders):
|
|
46
|
+
sender_filter = senders == sender
|
|
47
|
+
for prop, unit in zip(self.properties, self.units):
|
|
48
|
+
segment.analogsignals.append(
|
|
49
|
+
AnalogSignal(
|
|
50
|
+
device.events[prop][sender_filter],
|
|
51
|
+
units=pq.units.__dict__[unit],
|
|
52
|
+
sampling_period=self.simulation.resolution * pq.ms,
|
|
53
|
+
name=self.name,
|
|
54
|
+
cell_type=inv_targets[sender],
|
|
55
|
+
cell_id=sender,
|
|
56
|
+
prop_recorded=prop,
|
|
57
|
+
)
|
|
49
58
|
)
|
|
50
|
-
)
|
|
51
59
|
|
|
52
60
|
simdata.result.create_recorder(recorder)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import nest
|
|
2
|
+
from bsb import ConfigurationError, config
|
|
3
|
+
from neo import SpikeTrain
|
|
4
|
+
|
|
5
|
+
from ..device import NestDevice
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@config.node
|
|
9
|
+
class SinusoidalPoissonGenerator(
|
|
10
|
+
NestDevice, classmap_entry="sinusoidal_poisson_generator"
|
|
11
|
+
):
|
|
12
|
+
rate = config.attr(type=float, required=True)
|
|
13
|
+
"""Rate of the poisson generator"""
|
|
14
|
+
amplitude = config.attr(type=float, required=True)
|
|
15
|
+
"""Amplitude of the sinusoidal signal"""
|
|
16
|
+
frequency = config.attr(type=float, required=True)
|
|
17
|
+
"""Frequency of the sinusoidal signal"""
|
|
18
|
+
phase = config.attr(type=float, required=False, default=0.0)
|
|
19
|
+
"""Phase of the sinusoidal signal"""
|
|
20
|
+
start = config.attr(type=float, required=False, default=0.0)
|
|
21
|
+
"""Activation time in ms"""
|
|
22
|
+
stop = config.attr(type=float, required=False, default=None)
|
|
23
|
+
"""Deactivation time in ms.
|
|
24
|
+
If not specified, generator will last until the end of the simulation."""
|
|
25
|
+
|
|
26
|
+
def boot(self):
|
|
27
|
+
if self.stop is not None:
|
|
28
|
+
if self.stop <= self.start:
|
|
29
|
+
raise ConfigurationError(
|
|
30
|
+
f"Stop time (given: {self.stop}) must be greater than start time (given: {self.start})."
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
def implement(self, adapter, simulation, simdata):
|
|
34
|
+
nodes = self.get_target_nodes(adapter, simulation, simdata)
|
|
35
|
+
params = {
|
|
36
|
+
"rate": self.rate,
|
|
37
|
+
"start": self.start,
|
|
38
|
+
"amplitude": self.amplitude,
|
|
39
|
+
"frequency": self.frequency,
|
|
40
|
+
"phase": self.phase,
|
|
41
|
+
}
|
|
42
|
+
if self.stop is not None:
|
|
43
|
+
params["stop"] = self.stop
|
|
44
|
+
device = self.register_device(
|
|
45
|
+
simdata, nest.Create("sinusoidal_poisson_generator", params=params)
|
|
46
|
+
)
|
|
47
|
+
sr = nest.Create("spike_recorder")
|
|
48
|
+
nest.Connect(device, sr)
|
|
49
|
+
self.connect_to_nodes(device, nodes)
|
|
50
|
+
|
|
51
|
+
def recorder(segment):
|
|
52
|
+
segment.spiketrains.append(
|
|
53
|
+
SpikeTrain(
|
|
54
|
+
sr.events["times"],
|
|
55
|
+
units="ms",
|
|
56
|
+
senders=sr.events["senders"],
|
|
57
|
+
t_stop=simulation.duration,
|
|
58
|
+
device=self.name,
|
|
59
|
+
pop_size=len(nodes),
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
simdata.result.create_recorder(recorder)
|
|
@@ -46,7 +46,7 @@ profile = "black"
|
|
|
46
46
|
known_third_party = ["nest"]
|
|
47
47
|
|
|
48
48
|
[tool.bumpversion]
|
|
49
|
-
current_version = "4.
|
|
49
|
+
current_version = "4.3.1"
|
|
50
50
|
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
|
|
51
51
|
serialize = ["{major}.{minor}.{patch}"]
|
|
52
52
|
search = "{current_version}"
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import warnings
|
|
2
|
-
|
|
3
|
-
import nest
|
|
4
|
-
from bsb import DeviceModel, Targetting, config, refs, types
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
@config.node
|
|
8
|
-
class NestRule:
|
|
9
|
-
rule = config.attr(type=str, required=True)
|
|
10
|
-
constants = config.catch_all(type=types.any_())
|
|
11
|
-
cell_models = config.reflist(refs.sim_cell_model_ref)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@config.dynamic(attr_name="device", auto_classmap=True, default="external")
|
|
15
|
-
class NestDevice(DeviceModel):
|
|
16
|
-
weight = config.attr(type=float, required=True)
|
|
17
|
-
"""weight of the connection between the device and its target"""
|
|
18
|
-
delay = config.attr(type=float, required=True)
|
|
19
|
-
"""delay of the transmission between the device and its target"""
|
|
20
|
-
targetting = config.attr(
|
|
21
|
-
type=types.or_(Targetting, NestRule), default=dict, call_default=True
|
|
22
|
-
)
|
|
23
|
-
"""Targets of the device, which should be either a population or a nest rule"""
|
|
24
|
-
|
|
25
|
-
def get_target_nodes(self, adapter, simulation, simdata):
|
|
26
|
-
if isinstance(self.targetting, Targetting):
|
|
27
|
-
node_collector = self.targetting.get_targets(
|
|
28
|
-
adapter, simulation, simdata
|
|
29
|
-
).values()
|
|
30
|
-
else:
|
|
31
|
-
node_collector = (
|
|
32
|
-
simdata.populations[model][targets]
|
|
33
|
-
for model, targets in simdata.populations.items()
|
|
34
|
-
if not self.targetting.cell_models or model in self.targetting.cell_models
|
|
35
|
-
)
|
|
36
|
-
return sum(node_collector, start=nest.NodeCollection())
|
|
37
|
-
|
|
38
|
-
def connect_to_nodes(self, device, nodes):
|
|
39
|
-
if len(nodes) == 0:
|
|
40
|
-
warnings.warn(f"{self.name} has no targets")
|
|
41
|
-
else:
|
|
42
|
-
try:
|
|
43
|
-
nest.Connect(
|
|
44
|
-
device,
|
|
45
|
-
nodes,
|
|
46
|
-
syn_spec={"weight": self.weight, "delay": self.delay},
|
|
47
|
-
)
|
|
48
|
-
except Exception as e:
|
|
49
|
-
if "does not send output" not in str(e):
|
|
50
|
-
raise
|
|
51
|
-
nest.Connect(
|
|
52
|
-
nodes,
|
|
53
|
-
device,
|
|
54
|
-
syn_spec={"weight": self.weight, "delay": self.delay},
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
def register_device(self, simdata, device):
|
|
58
|
-
simdata.devices[self] = device
|
|
59
|
-
return device
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
@config.node
|
|
63
|
-
class ExtNestDevice(NestDevice, classmap_entry="external"):
|
|
64
|
-
nest_model = config.attr(type=str, required=True)
|
|
65
|
-
constants = config.dict(type=types.or_(types.number(), str))
|
|
66
|
-
|
|
67
|
-
def implement(self, adapter, simulation, simdata):
|
|
68
|
-
simdata.devices[self] = device = nest.Create(
|
|
69
|
-
self.nest_model, params=self.constants
|
|
70
|
-
)
|
|
71
|
-
nodes = self.get_target_nodes(adapter, simdata)
|
|
72
|
-
self.connect_to_nodes(device, nodes)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|