bsb-nest 6.0.3__tar.gz → 7.0.2__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.
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bsb-nest
3
- Version: 6.0.3
3
+ Version: 7.0.2
4
4
  Summary: NEST simulation adapter for the BSB framework.
5
5
  Author-email: Robin De Schepper <robin@alexandria.sc>, Dimitri Rodarie <dimitri.rodarie@unipv.it>
6
6
  Requires-Python: >=3.10,<4
7
7
  Description-Content-Type: text/markdown
8
8
  Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
9
9
  License-File: LICENSE
10
- Requires-Dist: bsb-core~=6.0
10
+ Requires-Dist: bsb-core~=7.0
11
11
  Requires-Dist: bsb-core[parallel] ; extra == "parallel"
12
12
  Provides-Extra: parallel
13
13
 
@@ -5,10 +5,10 @@ import typing
5
5
  import nest
6
6
  from bsb import (
7
7
  AdapterError,
8
- AdapterProgress,
9
8
  SimulationData,
10
9
  SimulationResult,
11
10
  SimulatorAdapter,
11
+ options,
12
12
  report,
13
13
  warn,
14
14
  )
@@ -17,11 +17,13 @@ from tqdm import tqdm
17
17
 
18
18
  from .exceptions import KernelWarning, NestConnectError, NestModelError, NestModuleError
19
19
 
20
- if typing.TYPE_CHECKING:
20
+ if typing.TYPE_CHECKING: # pragma: nocover
21
21
  from .simulation import NestSimulation
22
22
 
23
23
 
24
24
  class NestResult(SimulationResult):
25
+ # It seems that the record method is not used,
26
+ # probably we will have to uniform the behavior with NeuronResult
25
27
  def record(self, nc, **annotations):
26
28
  recorder = nest.Create("spike_recorder", params={"record_to": "memory"})
27
29
  nest.Connect(nc, recorder)
@@ -38,6 +40,7 @@ class NestResult(SimulationResult):
38
40
  **annotations,
39
41
  )
40
42
  )
43
+ # Free the Memory -> not possible to free the memory while sim is running
41
44
 
42
45
  self.create_recorder(flush)
43
46
 
@@ -46,6 +49,7 @@ class NestAdapter(SimulatorAdapter):
46
49
  def __init__(self, comm=None):
47
50
  super().__init__(comm=comm)
48
51
  self.loaded_modules = set()
52
+ self._prev_chkpoint = 0
49
53
 
50
54
  def simulate(self, *simulations, post_prepare=None):
51
55
  try:
@@ -87,7 +91,8 @@ class NestAdapter(SimulatorAdapter):
87
91
  report("Creating connections...", level=2)
88
92
  self.connect_neurons(simulation)
89
93
  report("Creating devices...", level=2)
90
- self.create_devices(simulation)
94
+ self.implement_components(simulation)
95
+ self.load_controllers(simulation)
91
96
  return self.simdata[simulation]
92
97
  except Exception:
93
98
  del self.simdata[simulation]
@@ -104,18 +109,21 @@ class NestAdapter(SimulatorAdapter):
104
109
  if unprepared:
105
110
  raise AdapterError(f"Unprepared for simulations: {', '.join(unprepared)}")
106
111
  report("Simulating...", level=2)
107
- duration = max(sim.duration for sim in simulations)
108
- progress = AdapterProgress(duration)
112
+ self._duration = max(sim.duration for sim in simulations)
113
+
109
114
  try:
115
+ results = [self.simdata[sim].result for sim in simulations]
110
116
  with nest.RunManager():
111
- for oi, i in progress.steps(step=1):
112
- nest.Run(i - oi)
113
- progress.tick(i)
117
+ for t, checkpoint_controllers in self.get_next_checkpoint():
118
+ nest.Run(t - self._prev_chkpoint)
119
+ self.execute_checkpoints(checkpoint_controllers)
120
+ self._prev_chkpoint = t
121
+
114
122
  finally:
115
123
  results = [self.simdata[sim].result for sim in simulations]
116
124
  for sim in simulations:
117
125
  del self.simdata[sim]
118
- progress.complete()
126
+
119
127
  report("Simulation done.", level=2)
120
128
  return results
121
129
 
@@ -156,7 +164,7 @@ class NestAdapter(SimulatorAdapter):
156
164
  simdata = self.simdata[simulation]
157
165
  iter = simulation.connection_models.values()
158
166
  if self.comm.get_rank() == 0:
159
- iter = tqdm(iter, desc="", file=sys.stdout)
167
+ iter = tqdm(iter, desc="", file=sys.stdout, disable=options.verbosity < 2)
160
168
  for connection_model in iter:
161
169
  with contextlib.suppress(AttributeError):
162
170
  # Only rank 0 should report progress bar
@@ -178,15 +186,8 @@ class NestAdapter(SimulatorAdapter):
178
186
  simdata, pre_nodes, post_nodes, cs, self.comm
179
187
  )
180
188
  )
181
- except Exception:
182
- raise NestConnectError(
183
- f"{connection_model} error during connect."
184
- ) from None
185
-
186
- def create_devices(self, simulation):
187
- simdata = self.simdata[simulation]
188
- for device_model in simulation.devices.values():
189
- device_model.implement(self, simulation, simdata)
189
+ except Exception as e:
190
+ raise NestConnectError(f"{connection_model} error during connect.") from e
190
191
 
191
192
  def set_settings(self, simulation: "NestSimulation"):
192
193
  nest.set_verbosity(simulation.verbosity)
@@ -4,11 +4,18 @@ import sys
4
4
  import nest
5
5
  import numpy as np
6
6
  import psutil
7
- from bsb import ConnectionModel, compose_nodes, config, types
7
+ from bsb import ConfigurationError, ConnectionModel, compose_nodes, config, options, types
8
8
  from tqdm import tqdm
9
9
 
10
10
  from .distributions import nest_parameter
11
- from .exceptions import NestConnectError
11
+
12
+
13
+ def _is_delay_required(node):
14
+ model = node.get("model", NestSynapseSettings.model.default)
15
+ if model not in nest.Models(mtype="synapses"):
16
+ raise ConfigurationError(f"Unknown synapse model '{model}'.")
17
+ else:
18
+ return nest.GetDefaults(model)["has_delay"]
12
19
 
13
20
 
14
21
  @config.node
@@ -21,7 +28,7 @@ class NestSynapseSettings:
21
28
  """Importable reference to the NEST model describing the synapse type."""
22
29
  weight = config.attr(type=float, required=True)
23
30
  """Weight of the connection between the presynaptic and the postsynaptic cells."""
24
- delay = config.attr(type=float, required=True)
31
+ delay = config.attr(type=float, required=_is_delay_required, default=None)
25
32
  """Delay of the transmission between the presynaptic and the postsynaptic cells."""
26
33
  receptor_type = config.attr(type=int)
27
34
  """Index of the postsynaptic receptor to target."""
@@ -36,7 +43,7 @@ class NestConnectionSettings:
36
43
  """
37
44
 
38
45
  rule = config.attr(type=str)
39
- """Importable reference to the Nest connection rule used to connect the cells."""
46
+ """Importable reference to the NEST connection rule used to connect the cells."""
40
47
  constants = config.catch_all(type=types.any_())
41
48
  """Dictionary of parameters to assign to the connection rule."""
42
49
 
@@ -76,19 +83,20 @@ class NestConnection(compose_nodes(NestConnectionSettings, ConnectionModel)):
76
83
  management.
77
84
  """
78
85
 
79
- synapse = config.attr(type=NestSynapseSettings, required=True)
80
- """Nest synapse model with its parameters."""
86
+ synapses = config.list(type=NestSynapseSettings, required=True)
87
+ """List of synapse models to use for a connection."""
81
88
 
82
89
  def create_connections(self, simdata, pre_nodes, post_nodes, cs, comm):
83
90
  import nest
84
91
 
85
- syn_spec = self.get_syn_spec()
86
- if syn_spec["synapse_model"] not in nest.Models(mtype="synapses"):
87
- raise NestConnectError(
88
- f"Unknown synapse model '{syn_spec['synapse_model']}'."
89
- )
92
+ syn_specs = self.get_syn_specs()
90
93
  if self.rule is not None:
91
- nest.Connect(pre_nodes, post_nodes, self.get_conn_spec(), syn_spec)
94
+ nest.Connect(
95
+ pre_nodes,
96
+ post_nodes,
97
+ self.get_conn_spec(),
98
+ nest.CollocatedSynapses(*syn_specs),
99
+ )
92
100
  else:
93
101
  comm.barrier()
94
102
  for pre_locs, post_locs in self.predict_mem_iterator(
@@ -104,17 +112,21 @@ class NestConnection(compose_nodes(NestConnectionSettings, ConnectionModel)):
104
112
  )
105
113
  prel = pre_nodes.tolist()
106
114
  postl = post_nodes.tolist()
107
- ssw = {**syn_spec}
108
- bw = syn_spec["weight"]
109
- ssw["weight"] = [bw * m for m in multiplicity]
110
- ssw["delay"] = [syn_spec["delay"]] * len(ssw["weight"])
111
- nest.Connect(
112
- [prel[x] for x in cell_pairs[:, 0]],
113
- [postl[x] for x in cell_pairs[:, 1]],
114
- "one_to_one",
115
- ssw,
116
- return_synapsecollection=False,
117
- )
115
+ # cannot use CollocatedSynapses with a list of weight and delay
116
+ # so loop over the syn_specs
117
+ for syn_spec in syn_specs:
118
+ ssw = {**syn_spec}
119
+ bw = syn_spec["weight"]
120
+ ssw["weight"] = [bw * m for m in multiplicity]
121
+ if "delay" in syn_spec:
122
+ ssw["delay"] = [syn_spec["delay"]] * len(ssw["weight"])
123
+ nest.Connect(
124
+ [prel[x] for x in cell_pairs[:, 0]],
125
+ [postl[x] for x in cell_pairs[:, 1]],
126
+ "one_to_one",
127
+ ssw,
128
+ return_synapsecollection=False,
129
+ )
118
130
  comm.barrier()
119
131
  return LazySynapseCollection(pre_nodes, post_nodes)
120
132
 
@@ -141,7 +153,12 @@ class NestConnection(compose_nodes(NestConnectionSettings, ConnectionModel)):
141
153
  def block_iter():
142
154
  iter = locals
143
155
  if comm.get_rank() == 0:
144
- iter = tqdm(iter, desc="hyperblocks", file=sys.stdout)
156
+ iter = tqdm(
157
+ iter,
158
+ desc="hyperblocks",
159
+ file=sys.stdout,
160
+ disable=options.verbosity < 2,
161
+ )
145
162
  for local in iter:
146
163
  inner_iter = cs.load_connections().as_globals().from_(local)
147
164
  if comm.get_rank() == 0:
@@ -160,7 +177,9 @@ class NestConnection(compose_nodes(NestConnectionSettings, ConnectionModel)):
160
177
  def local_iterator(self, cs, comm):
161
178
  iter = cs.get_local_chunks("out")
162
179
  if comm.get_rank() == 0:
163
- iter = tqdm(iter, desc="hyperblocks", file=sys.stdout)
180
+ iter = tqdm(
181
+ iter, desc="hyperblocks", file=sys.stdout, disable=options.verbosity < 2
182
+ )
164
183
  yield from (
165
184
  cs.load_connections().as_globals().from_(local).all() for local in iter
166
185
  )
@@ -177,17 +196,20 @@ class NestConnection(compose_nodes(NestConnectionSettings, ConnectionModel)):
177
196
  **self.constants,
178
197
  }
179
198
 
180
- def get_syn_spec(self):
181
- return {
182
- **{
183
- label: value
184
- for attr, label in (
185
- ("model", "synapse_model"),
186
- ["weight"] * 2,
187
- ["delay"] * 2,
188
- ["receptor_type"] * 2,
189
- )
190
- if (value := getattr(self.synapse, attr)) is not None
191
- },
192
- **self.synapse.constants,
193
- }
199
+ def get_syn_specs(self):
200
+ return [
201
+ {
202
+ **{
203
+ label: value
204
+ for attr, label in (
205
+ ("model", "synapse_model"),
206
+ ["weight"] * 2,
207
+ ["delay"] * 2,
208
+ ["receptor_type"] * 2,
209
+ )
210
+ if (value := getattr(synapse, attr)) is not None
211
+ },
212
+ **synapse.constants,
213
+ }
214
+ for synapse in self.synapses
215
+ ]
@@ -119,7 +119,7 @@ class NestDevice(DeviceModel):
119
119
  adapter,
120
120
  simulation,
121
121
  simdata,
122
- ):
122
+ ): # pragma: nocover
123
123
  """
124
124
  Create, connect and register the Nest device.
125
125
 
@@ -6,14 +6,14 @@ build-backend = "flit_core.buildapi"
6
6
 
7
7
  [project]
8
8
  name = "bsb-nest"
9
- version = "6.0.3"
9
+ version = "7.0.2"
10
10
  readme = "README.md"
11
11
  requires-python = ">=3.10,<4"
12
12
  dynamic = [ "description" ]
13
13
  classifiers = [
14
14
  "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)"
15
15
  ]
16
- dependencies = [ "bsb-core~=6.0" ]
16
+ dependencies = [ "bsb-core~=7.0" ]
17
17
 
18
18
  [[project.authors]]
19
19
  name = "Robin De Schepper"
@@ -44,7 +44,7 @@ branch = true
44
44
  source = [ "bsb_nest" ]
45
45
 
46
46
  [tool.coverage.report]
47
- exclude_lines = [ "if TYPE_CHECKING:" ]
47
+ exclude_lines = [ "if typing.TYPE_CHECKING:", "pragma: nocover" ]
48
48
  show_missing = true
49
49
 
50
50
  [tool.ruff]
File without changes
File without changes
File without changes
File without changes