bsb-arbor 4.1.1__tar.gz → 6.0.0__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-arbor might be problematic. Click here for more details.

@@ -0,0 +1,23 @@
1
+ Metadata-Version: 2.4
2
+ Name: bsb-arbor
3
+ Version: 6.0.0
4
+ Summary: Arbor simulation adapter for the BSB framework.
5
+ Author-email: Robin De Schepper <robin@alexandria.sc>, Dimitri Rodarie <dimitri.rodarie@unipv.it>
6
+ Requires-Python: >=3.10,<4
7
+ Description-Content-Type: text/markdown
8
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
9
+ License-File: LICENSE
10
+ Requires-Dist: numpy~=1.21
11
+ Requires-Dist: bsb-core~=6.0
12
+ Requires-Dist: arborize~=6.0
13
+ Requires-Dist: arbor~=0.10; sys_platform != 'win32'
14
+
15
+ [![Build Status](https://github.com/dbbs-lab/bsb-arbor/actions/workflows/main.yml/badge.svg)](https://github.com/dbbs-lab/bsb-arbor/actions/workflows/main.yml)
16
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
17
+
18
+ # bsb-arbor
19
+
20
+ bsb-arbor is a plugin of the [BSB](https://github.com/dbbs-lab/bsb) (see also
21
+ [bsb-core](https://github.com/dbbs-lab/bsb-core)).
22
+ It contains the interfaces and tools to simulate BSB circuit with the
23
+ [Arbor simulator](https://arbor-sim.org/).
@@ -3,7 +3,7 @@
3
3
 
4
4
  # bsb-arbor
5
5
 
6
- bsb-nest is a plugin of the [BSB](https://github.com/dbbs-lab/bsb) (see also
6
+ bsb-arbor is a plugin of the [BSB](https://github.com/dbbs-lab/bsb) (see also
7
7
  [bsb-core](https://github.com/dbbs-lab/bsb-core)).
8
8
  It contains the interfaces and tools to simulate BSB circuit with the
9
9
  [Arbor simulator](https://arbor-sim.org/).
@@ -0,0 +1,20 @@
1
+ """
2
+ Arbor simulation adapter for the BSB framework.
3
+ """
4
+
5
+ from bsb import SimulationBackendPlugin
6
+
7
+ from .adapter import ArborAdapter
8
+ from .devices import PoissonGenerator, Probe, SpikeRecorder
9
+ from .simulation import ArborSimulation
10
+
11
+ __plugin__ = SimulationBackendPlugin(Simulation=ArborSimulation, Adapter=ArborAdapter)
12
+
13
+
14
+ __all__ = [
15
+ "PoissonGenerator",
16
+ "Probe",
17
+ "SpikeRecorder",
18
+ "ArborAdapter",
19
+ "ArborSimulation",
20
+ ]
@@ -7,7 +7,6 @@ import arbor
7
7
  import numpy as np
8
8
  from arbor import units as U
9
9
  from bsb import (
10
- MPI,
11
10
  AdapterError,
12
11
  Chunk,
13
12
  SimulationData,
@@ -22,9 +21,16 @@ if typing.TYPE_CHECKING:
22
21
 
23
22
 
24
23
  class ArborSimulationData(SimulationData):
24
+ """
25
+ Container class for simulation data.
26
+ """
27
+
25
28
  def __init__(self, simulation):
29
+ """
30
+ Container class for simulation data.
31
+ """
26
32
  super().__init__(simulation)
27
- self.arbor_sim: "arbor.simulation" = None
33
+ self.arbor_sim: arbor.simulation = None
28
34
 
29
35
 
30
36
  class ReceiverCollection(list):
@@ -47,7 +53,8 @@ class ReceiverCollection(list):
47
53
 
48
54
  class SingleReceiverCollection(list):
49
55
  """
50
- The single receiver collection redirects all incoming connections to the same receiver
56
+ The single receiver collection redirects all incoming connections to the same
57
+ receiver.
51
58
  """
52
59
 
53
60
  def append(self, rcv):
@@ -56,7 +63,20 @@ class SingleReceiverCollection(list):
56
63
 
57
64
 
58
65
  class Population:
66
+ """
67
+ Represents a population of cells for the Arbor simulator.
68
+
69
+ This class manages a collection of cells from a specific cell model, handling their
70
+ GID ranges and providing methods to access and manipulate subsets of the population.
71
+ """
59
72
  def __init__(self, simdata, cell_model, offset):
73
+ """
74
+ Initialize a population of cells.
75
+
76
+ :param simdata: The simulation data container
77
+ :param cell_model: The cell model for this population
78
+ :param offset: The GID offset for this population
79
+ """
60
80
  self._model = cell_model
61
81
  self._simdata = simdata
62
82
  ps = cell_model.get_placement_set(simdata.chunks)
@@ -65,30 +85,70 @@ class Population:
65
85
 
66
86
  @property
67
87
  def model(self):
88
+ """
89
+ Get the cell model associated with this population.
90
+
91
+ :return: The cell model object
92
+ """
68
93
  return self._model
69
94
 
70
95
  @property
71
96
  def offset(self):
97
+ """
98
+ Get the GID offset for this population.
99
+
100
+ :return: The GID offset value
101
+ """
72
102
  return self._offset
73
103
 
74
104
  def __len__(self):
105
+ """
106
+ Get the total number of cells in this population.
107
+
108
+ :return: The number of cells
109
+ """
75
110
  return sum(stop - start for start, stop in self._ranges)
76
111
 
77
112
  def __contains__(self, i):
113
+ """
114
+ Check if a GID is part of this population.
115
+
116
+ :param i: The GID to check
117
+ :return: True if the GID is in this population, False otherwise
118
+ """
78
119
  return any(start <= i < stop for start, stop in self._ranges)
79
120
 
80
121
  def copy(self):
122
+ """
123
+ Create a copy of this population.
124
+
125
+ :return: A new Population instance with the same properties
126
+ """
81
127
  return Population(self._simdata, self._model, self._offset)
82
128
 
83
129
  def __getitem__(self, item):
130
+ """
131
+ Get a subset of the population based on the provided index or mask.
132
+
133
+ Supports various indexing methods:
134
+ - Boolean masking: Select cells based on a boolean mask
135
+ - Integer indexing: Select specific cells by their indices
136
+ - Slicing: Select a range of cells
137
+
138
+ :param item: The index, slice, or mask to use for selection
139
+ :return: A new Population instance containing the selected cells
140
+ :raises ValueError: If the dimensions of the mask don't match the population
141
+ :raises IndexError: If an index is out of bounds
142
+ """
84
143
  # Boolean masking, kind of
85
- if getattr(item, "dtype", None) == bool or _all_bools(item):
144
+ if getattr(item, "dtype", None) == bool or _all_bools(item): # noqa: E721
86
145
  if len(item) != len(self):
87
146
  raise ValueError(
88
- f"Dimension mismatch between population ({len(self)}) and mask ({len(item)})"
147
+ f"Dimension mismatch between population ({len(self)}) "
148
+ f"and mask ({len(item)})"
89
149
  )
90
150
  return self._subpop_np(np.array(self)[item])
91
- elif getattr(item, "dtype", None) == int or _all_ints(item):
151
+ elif getattr(item, "dtype", None) == int or _all_ints(item): # noqa: E721
92
152
  if getattr(item, "ndim", None) == 0:
93
153
  return self._subpop_one(item)
94
154
  return self._subpop_np(np.array(self)[item])
@@ -98,6 +158,14 @@ class Population:
98
158
  return self._subpop_one(item)
99
159
 
100
160
  def _get_ranges(self, chunks, ps, offset):
161
+ """
162
+ Calculate the GID ranges for this population based on chunk statistics.
163
+
164
+ :param chunks: The simulation chunks to include
165
+ :param ps: The placement set for the cell model
166
+ :param offset: The starting GID offset
167
+ :return: A list of (start, stop) tuples representing GID ranges
168
+ """
101
169
  stats = ps.get_chunk_stats()
102
170
  ranges = []
103
171
  for chunk, len_ in sorted(
@@ -109,6 +177,15 @@ class Population:
109
177
  return ranges
110
178
 
111
179
  def _subpop_np(self, arr):
180
+ """
181
+ Create a subpopulation from a numpy array of indices.
182
+
183
+ This method handles array-based indexing, including boolean masks,
184
+ integer arrays, and slices.
185
+
186
+ :param arr: A numpy array of indices to include in the subpopulation
187
+ :return: A new Population instance containing only the selected cells
188
+ """
112
189
  pop = self.copy()
113
190
  if not len(pop):
114
191
  return pop
@@ -130,6 +207,13 @@ class Population:
130
207
  return pop
131
208
 
132
209
  def _subpop_one(self, item):
210
+ """
211
+ Create a subpopulation containing a single cell.
212
+
213
+ :param item: The index of the cell to include
214
+ :return: A new Population instance containing only the selected cell
215
+ :raises IndexError: If the index is out of bounds
216
+ """
133
217
  if item >= len(self):
134
218
  raise IndexError(f"Index {item} out of bounds for size {len(self)}")
135
219
  pop = self.copy()
@@ -142,9 +226,12 @@ class Population:
142
226
  ptr += stop - start
143
227
 
144
228
  def __iter__(self):
145
- yield from itertools.chain.from_iterable(
146
- range(r[0], r[1]) for r in self._ranges
147
- )
229
+ """
230
+ Iterate over all GIDs in this population.
231
+
232
+ :yield: Each GID in the population's ranges
233
+ """
234
+ yield from itertools.chain.from_iterable(range(r[0], r[1]) for r in self._ranges)
148
235
 
149
236
 
150
237
  class GIDManager:
@@ -281,36 +368,27 @@ class ArborRecipe(arbor.recipe):
281
368
 
282
369
 
283
370
  class ArborAdapter(SimulatorAdapter):
284
- def __init__(self):
285
- super().__init__()
286
- self.simdata: typing.Dict["ArborSimulation", "SimulationData"] = {}
287
-
288
- def get_rank(self):
289
- return MPI.get_rank()
290
-
291
- def get_size(self):
292
- return MPI.get_size()
293
-
294
- def broadcast(self, data, root=0):
295
- return MPI.bcast(data, root)
296
-
297
- def barrier(self):
298
- return MPI.barrier()
299
-
300
- def prepare(self, simulation: "ArborSimulation", comm=None):
371
+ def __init__(self, comm=None):
372
+ super().__init__(comm)
373
+ self.simdata: dict[ArborSimulation, ArborSimulationData] = {}
374
+
375
+ def prepare(self, simulation: "ArborSimulation") -> ArborSimulationData:
376
+ """
377
+ Prepares the arbor simulation engine with the given simulation.
378
+ """
301
379
  simdata = self._create_simdata(simulation)
302
380
  try:
303
381
  context = arbor.context(arbor.proc_allocation(threads=simulation.threads))
304
- if MPI.get_size() > 1:
382
+ if self.comm.get_size() > 1:
305
383
  if not arbor.config()["mpi4py"]:
306
384
  warn(
307
385
  f"Arbor does not seem to be built with MPI support, running"
308
- "duplicate simulations on {MPI.get_size()} nodes."
386
+ f"duplicate simulations on {self.comm.get_size()} nodes."
309
387
  )
310
388
  else:
311
389
  context = arbor.context(
312
390
  arbor.proc_allocation(threads=simulation.threads),
313
- mpi=comm or MPI.get_communicator(),
391
+ mpi=self.comm.get_communicator(),
314
392
  )
315
393
  if simulation.profiling:
316
394
  if arbor.config()["profiling"]:
@@ -318,7 +396,8 @@ class ArborAdapter(SimulatorAdapter):
318
396
  arbor.profiler_initialize(context)
319
397
  else:
320
398
  raise RuntimeError(
321
- "Arbor must be built with profiling support to use the `profiling` flag."
399
+ "Arbor must be built with profiling support to use the "
400
+ "`profiling` flag."
322
401
  )
323
402
  simdata.gid_manager = self.get_gid_manager(simulation, simdata)
324
403
  simdata.populations = simdata.gid_manager.get_populations()
@@ -342,12 +421,13 @@ class ArborAdapter(SimulatorAdapter):
342
421
 
343
422
  def prepare_samples(self, simulation, simdata):
344
423
  for device in simulation.devices.values():
345
- device.prepare_samples(simdata)
424
+ device.prepare_samples(simdata, comm=self.comm)
346
425
 
347
426
  def run(self, *simulations):
348
427
  if len(simulations) != 1:
349
428
  raise RuntimeError(
350
- "Can not run multiple simultaneous simulations. Composition not implemented."
429
+ "Can not run multiple simultaneous simulations. Composition not "
430
+ "implemented."
351
431
  )
352
432
  simulation = simulations[0]
353
433
  try:
@@ -358,7 +438,7 @@ class ArborAdapter(SimulatorAdapter):
358
438
  f"Can't run unprepared simulation '{simulation.name}'"
359
439
  ) from None
360
440
  try:
361
- if not MPI.get_rank():
441
+ if not self.comm.get_rank():
362
442
  arbor_sim.record(arbor.spike_recording.all)
363
443
 
364
444
  start = time.time()
@@ -381,7 +461,7 @@ class ArborAdapter(SimulatorAdapter):
381
461
  return ArborRecipe(simulation, simdata)
382
462
 
383
463
  def _create_simdata(self, simulation):
384
- self.simdata[simulation] = simdata = SimulationData(simulation)
464
+ self.simdata[simulation] = simdata = ArborSimulationData(simulation)
385
465
  self._assign_chunks(simulation, simdata)
386
466
  return simdata
387
467
 
@@ -431,14 +511,14 @@ class ArborAdapter(SimulatorAdapter):
431
511
 
432
512
  def _assign_chunks(self, simulation, simdata):
433
513
  chunk_stats = simulation.scaffold.storage.get_chunk_stats()
434
- size = MPI.get_size()
435
- all_chunks = [Chunk.from_id(int(chunk), None) for chunk in chunk_stats.keys()]
514
+ size = self.comm.get_size()
515
+ all_chunks = [Chunk.from_id(int(chunk), None) for chunk in chunk_stats]
436
516
  simdata.node_chunk_alloc = [all_chunks[rank::size] for rank in range(0, size)]
437
517
  simdata.chunk_node_map = {}
438
518
  for node, chunks in enumerate(simdata.node_chunk_alloc):
439
519
  for chunk in chunks:
440
520
  simdata.chunk_node_map[chunk] = node
441
- simdata.chunks = simdata.node_chunk_alloc[MPI.get_rank()]
521
+ simdata.chunks = simdata.node_chunk_alloc[self.comm.get_rank()]
442
522
 
443
523
 
444
524
  def _all_bools(arr):
@@ -1,14 +1,10 @@
1
1
  import abc
2
- import typing
3
2
 
4
3
  import arbor
5
- from bsb import CellModel, ConfigurationError, config, types
4
+ from bsb import CellModel, ConfigurationError, PlacementSet, config, types
6
5
 
7
6
  from .adapter import SingleReceiverCollection
8
7
 
9
- if typing.TYPE_CHECKING:
10
- from bsb import PlacementSet
11
-
12
8
 
13
9
  @config.dynamic(
14
10
  attr_name="model_strategy",
@@ -17,11 +13,18 @@ if typing.TYPE_CHECKING:
17
13
  classmap_entry=None,
18
14
  )
19
15
  class ArborCell(CellModel):
16
+ model_strategy: config.ConfigurationAttribute
17
+ """
18
+ Optional importable reference to a different modelling strategy than the default
19
+ Arborize strategy.
20
+ """
20
21
  gap = config.attr(type=bool, default=False)
22
+ """Is this synapse a gap junction?"""
21
23
  model = config.attr(type=types.class_(), required=True)
24
+ """Importable reference to the arborize model describing the cell type."""
22
25
 
23
26
  @abc.abstractmethod
24
- def cache_population_data(self, simdata, ps: "PlacementSet"):
27
+ def cache_population_data(self, simdata, ps: PlacementSet):
25
28
  pass
26
29
 
27
30
  @abc.abstractmethod
@@ -51,9 +54,11 @@ class ArborCell(CellModel):
51
54
  @config.node
52
55
  class LIFCell(ArborCell, classmap_entry="lif"):
53
56
  model = config.unset()
57
+ """Importable reference to the arborize model describing the cell type."""
54
58
  constants = config.dict(type=types.any_())
59
+ """Dictionary linking the parameters' name to its value."""
55
60
 
56
- def cache_population_data(self, simdata, ps: "PlacementSet"):
61
+ def cache_population_data(self, simdata, ps: PlacementSet):
57
62
  pass
58
63
 
59
64
  def discard_population_data(self):
@@ -66,7 +71,7 @@ class LIFCell(ArborCell, classmap_entry="lif"):
66
71
  return arbor.cell_kind.lif
67
72
 
68
73
  def get_description(self, gid):
69
- cell = arbor.lif_cell(f"-1_-1", f"-1_-1_0")
74
+ cell = arbor.lif_cell("-1_-1", "-1_-1_0")
70
75
  try:
71
76
  for k, v in self.constants.items():
72
77
  setattr(cell, k, v * getattr(cell, k).units)
@@ -41,8 +41,11 @@ class Connection:
41
41
  @config.node
42
42
  class ArborConnection(ConnectionModel):
43
43
  gap = config.attr(type=bool, default=False)
44
+ """Is this synapce a gap junction?"""
44
45
  weight = config.attr(type=float, required=True)
46
+ """Weight of the connection between the presynaptic and the postsynaptic cells."""
45
47
  delay = config.attr(type=float, required=True)
48
+ """Delay of the transmission between the presynaptic and the postsynaptic cells."""
46
49
 
47
50
  def create_gap_junctions_on(self, gj_on_gid, conns):
48
51
  for pre_loc, post_loc in conns:
@@ -56,12 +59,10 @@ class ArborConnection(ConnectionModel):
56
59
  )
57
60
 
58
61
  def create_connections_from(self, conns_from_gid, conns, pop_pre, pop_post):
59
- for pre_loc, post_loc in conns:
62
+ for pre_loc, _post_loc in conns:
60
63
  conns_from_gid[int(pre_loc[0] + pop_pre.offset)].append(pre_loc[1:])
61
64
 
62
65
  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)
66
+ l_ = arbor.cell_local_label(f"gap_{conn.to_compartment.id}")
67
+ g = arbor.cell_global_label(int(conn.from_id), f"gap_{conn.from_compartment.id}")
68
+ return arbor.gap_junction_connection(g, l_, self.weight)
@@ -6,9 +6,14 @@ from bsb import DeviceModel, Targetting, config, types
6
6
 
7
7
  @config.dynamic(attr_name="device", auto_classmap=True, classmap_entry=None)
8
8
  class ArborDevice(DeviceModel):
9
+ device: config.ConfigurationAttribute
10
+ """Optional importable reference to the device strategy."""
9
11
  targetting = config.attr(type=Targetting, required=True)
12
+ """Targets of the device, which should be either a population or a nest rule."""
10
13
  resolution = config.attr(type=float)
14
+ """Time resolution of the device."""
11
15
  sampling_policy = config.attr(type=types.in_(["exact"]))
16
+ """Policy used to sample simulation data from the device."""
12
17
 
13
18
  def __init__(self, **kwargs):
14
19
  self._probe_ids = []
@@ -19,7 +24,7 @@ class ArborDevice(DeviceModel):
19
24
  def register_probe_id(self, gid, tag):
20
25
  self._probe_ids.append((gid, tag))
21
26
 
22
- def prepare_samples(self, simdata):
27
+ def prepare_samples(self, simdata, comm):
23
28
  self._handles = [
24
29
  self.sample(simdata.arbor_sim, probe_id) for probe_id in self._probe_ids
25
30
  ]
@@ -34,7 +39,7 @@ class ArborDevice(DeviceModel):
34
39
 
35
40
  def get_meta(self):
36
41
  attrs = ("name", "sampling_policy", "resolution")
37
- return dict(zip(attrs, (getattr(self, attr) for attr in attrs)))
42
+ return dict(zip(attrs, (getattr(self, attr) for attr in attrs), strict=False))
38
43
 
39
44
  @abc.abstractmethod
40
45
  def implement_probes(self, simdata, target):
@@ -1,3 +1,9 @@
1
1
  from .poisson_generator import PoissonGenerator
2
2
  from .probe import Probe
3
3
  from .spike_recorder import SpikeRecorder
4
+
5
+ __all__ = [
6
+ "PoissonGenerator",
7
+ "Probe",
8
+ "SpikeRecorder",
9
+ ]
@@ -9,9 +9,13 @@ from ..device import ArborDevice
9
9
  @config.node
10
10
  class PoissonGenerator(ArborDevice, classmap_entry="poisson_generator"):
11
11
  record = config.attr(type=bool, default=True)
12
+ """Flag to save the spikes generated to file."""
12
13
  rate = config.attr(type=float, required=True)
14
+ """Frequency of the poisson generator."""
13
15
  weight = config.attr(type=float, required=True)
16
+ """Weight of the connection between the device and its target."""
14
17
  delay = config.attr(type=float, required=True)
18
+ """Delay of the transmission between the device and its target."""
15
19
 
16
20
  def implement_probes(self, simdata, gid):
17
21
  return []
@@ -11,7 +11,6 @@ class Probe(ArborDevice):
11
11
  return f"cable_probe_{self.probe_type}"
12
12
 
13
13
  def validate_specifics(self):
14
-
15
14
  if self.get_probe_name() not in vars(arbor):
16
15
  raise ConfigurationError(
17
16
  f"`{self.probe_type}` is not a valid probe type for `{self.name}`"
@@ -22,9 +21,9 @@ class Probe(ArborDevice):
22
21
  kwargs = dict((k, getattr(self, k)) for k in probe_args if hasattr(self, k))
23
22
  return [getattr(arbor, self.get_probe_name())(**kwargs)]
24
23
 
25
- def prepare_samples(self, sim):
26
- super().prepare_samples(sim)
27
- for probe_id, handle in zip(self._probe_ids, self._handles):
24
+ def prepare_samples(self, sim, comm):
25
+ super().prepare_samples(sim, comm)
26
+ for probe_id, handle in zip(self._probe_ids, self._handles, strict=False):
28
27
  self.adapter.result.add(ProbeRecorder(self, sim, probe_id, handle))
29
28
 
30
29
 
@@ -1,6 +1,5 @@
1
1
  import neo
2
2
  from bsb import config
3
- from bsb.services import MPI
4
3
 
5
4
  from ..device import ArborDevice
6
5
 
@@ -10,9 +9,9 @@ class SpikeRecorder(ArborDevice, classmap_entry="spike_recorder"):
10
9
  def boot(self):
11
10
  self._gids = set()
12
11
 
13
- def prepare_samples(self, simdata):
14
- super().prepare_samples(simdata)
15
- if not MPI.get_rank():
12
+ def prepare_samples(self, simdata, comm):
13
+ super().prepare_samples(simdata, comm)
14
+ if not comm.get_rank():
16
15
 
17
16
  def record_device_spikes(segment):
18
17
  spiketrain = list()
@@ -25,7 +24,7 @@ class SpikeRecorder(ArborDevice, classmap_entry="spike_recorder"):
25
24
  neo.SpikeTrain(
26
25
  spiketrain,
27
26
  units="ms",
28
- senders=senders,
27
+ array_annotations={"senders": senders},
29
28
  t_stop=self.simulation.duration,
30
29
  device=self.name,
31
30
  gids=list(self._gids),
@@ -0,0 +1,38 @@
1
+ import psutil
2
+ from bsb import Simulation, config, types
3
+
4
+ from .cell import ArborCell
5
+ from .connection import ArborConnection
6
+ from .device import ArborDevice
7
+
8
+
9
+ @config.node
10
+ class ArborSimulation(Simulation):
11
+ """
12
+ Interface between the scaffold model and the Arbor simulator.
13
+ """
14
+
15
+ resolution = config.attr(type=types.float(min=0.0), default=0.1)
16
+ """Simulation time step size in milliseconds."""
17
+ profiling = config.attr(type=bool)
18
+ """Flag to perform profiling during the simulation."""
19
+ cell_models: config._attrs.cfgdict[ArborCell] = config.dict(
20
+ type=ArborCell, required=True
21
+ )
22
+ """Dictionary of cell models in the simulation."""
23
+ connection_models: config._attrs.cfgdict[ArborConnection] = config.dict(
24
+ type=ArborConnection, required=True
25
+ )
26
+ """Dictionary of connection models in the simulation."""
27
+ devices: config._attrs.cfgdict[ArborDevice] = config.dict(
28
+ type=ArborDevice, required=True
29
+ )
30
+ """Dictionary of devices in the simulation."""
31
+
32
+ @config.property(default=1)
33
+ def threads(self):
34
+ return self._threads
35
+
36
+ @threads.setter
37
+ def threads(self, value):
38
+ self._threads = value if value != "all" else psutil.cpu_count(logical=False)
@@ -0,0 +1,69 @@
1
+ dependency-groups = { }
2
+
3
+ [build-system]
4
+ requires = [ "flit_core >=3.2,<4" ]
5
+ build-backend = "flit_core.buildapi"
6
+
7
+ [project]
8
+ name = "bsb-arbor"
9
+ version = "6.0.0"
10
+ readme = "README.md"
11
+ requires-python = ">=3.10,<4"
12
+ dynamic = [ "description" ]
13
+ classifiers = [
14
+ "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)"
15
+ ]
16
+ dependencies = [
17
+ "numpy~=1.21",
18
+ "bsb-core~=6.0",
19
+ "arborize~=6.0",
20
+ "arbor~=0.10; sys_platform != 'win32'"
21
+ ]
22
+
23
+ [[project.authors]]
24
+ name = "Robin De Schepper"
25
+ email = "robin@alexandria.sc"
26
+
27
+ [[project.authors]]
28
+ name = "Dimitri Rodarie"
29
+ email = "dimitri.rodarie@unipv.it"
30
+
31
+ [project.license]
32
+ file = "LICENSE"
33
+
34
+ [project.entry-points."bsb.simulation_backends"]
35
+ arbor = "bsb_arbor"
36
+
37
+ [tool.uv]
38
+ default-groups = [ "dev", "docs", "test" ]
39
+ sources = { }
40
+
41
+ [tool.flit.module]
42
+ name = "bsb_arbor"
43
+
44
+ [tool.coverage.run]
45
+ branch = true
46
+ source = [ "bsb_arbor" ]
47
+
48
+ [tool.coverage.report]
49
+ exclude_lines = [ "if TYPE_CHECKING:" ]
50
+ show_missing = true
51
+
52
+ [tool.ruff]
53
+ exclude = [ ".ruff_cache", ".svn", ".tox", ".venv", "dist" ]
54
+ line-length = 90
55
+ indent-width = 4
56
+
57
+ [tool.ruff.format]
58
+ quote-style = "double"
59
+ indent-style = "space"
60
+ skip-magic-trailing-comma = false
61
+ line-ending = "auto"
62
+ docstring-code-format = true
63
+ docstring-code-line-length = 90
64
+
65
+ [tool.ruff.lint]
66
+ select = [ "E", "F", "UP", "B", "SIM", "I" ]
67
+ ignore = [ ]
68
+ fixable = [ "ALL" ]
69
+ unfixable = [ ]
bsb_arbor-4.1.1/PKG-INFO DELETED
@@ -1,37 +0,0 @@
1
- Metadata-Version: 2.3
2
- Name: bsb-arbor
3
- Version: 4.1.1
4
- Summary: Arbor simulation adapter for the BSB framework
5
- Author-email: Robin De Schepper <robingilbert.deschepper@unipv.it>
6
- Description-Content-Type: text/markdown
7
- Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
8
- Requires-Dist: numpy~=1.21
9
- Requires-Dist: bsb-core~=5.0
10
- Requires-Dist: arbor~=0.10
11
- Requires-Dist: arborize[arbor]~=4.0
12
- Requires-Dist: bsb-arbor[test] ; extra == "dev"
13
- Requires-Dist: build~=1.0 ; extra == "dev"
14
- Requires-Dist: twine~=4.0 ; extra == "dev"
15
- Requires-Dist: pre-commit~=3.5 ; extra == "dev"
16
- Requires-Dist: black~=24.1.1 ; extra == "dev"
17
- Requires-Dist: isort~=5.12 ; extra == "dev"
18
- Requires-Dist: snakeviz~=2.1 ; extra == "dev"
19
- Requires-Dist: bump-my-version~=0.24 ; extra == "dev"
20
- Requires-Dist: bsb-core[parallel] ; extra == "parallel"
21
- Requires-Dist: bsb-core[parallel] ; extra == "test"
22
- Requires-Dist: bsb-hdf5~=5.0 ; extra == "test"
23
- Requires-Dist: bsb-test~=4.0 ; extra == "test"
24
- Requires-Dist: coverage~=7.0 ; extra == "test"
25
- Provides-Extra: dev
26
- Provides-Extra: parallel
27
- Provides-Extra: test
28
-
29
- [![Build Status](https://github.com/dbbs-lab/bsb-arbor/actions/workflows/main.yml/badge.svg)](https://github.com/dbbs-lab/bsb-arbor/actions/workflows/main.yml)
30
- [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
31
-
32
- # bsb-arbor
33
-
34
- bsb-nest is a plugin of the [BSB](https://github.com/dbbs-lab/bsb) (see also
35
- [bsb-core](https://github.com/dbbs-lab/bsb-core)).
36
- It contains the interfaces and tools to simulate BSB circuit with the
37
- [Arbor simulator](https://arbor-sim.org/).
@@ -1,12 +0,0 @@
1
- """
2
- Arbor simulation adapter for the BSB framework
3
- """
4
-
5
- from bsb import SimulationBackendPlugin
6
-
7
- from . import devices
8
- from .adapter import ArborAdapter
9
- from .simulation import ArborSimulation
10
-
11
- __version__ = "4.1.1"
12
- __plugin__ = SimulationBackendPlugin(Simulation=ArborSimulation, Adapter=ArborAdapter)
@@ -1,23 +0,0 @@
1
- import psutil
2
- from bsb import Simulation, config, types
3
-
4
- from .cell import ArborCell
5
- from .connection import ArborConnection
6
- from .device import ArborDevice
7
-
8
-
9
- @config.node
10
- class ArborSimulation(Simulation):
11
- resolution = config.attr(type=types.float(min=0.0), default=0.1)
12
- profiling = config.attr(type=bool)
13
- cell_models = config.dict(type=ArborCell, required=True)
14
- connection_models = config.dict(type=ArborConnection, required=True)
15
- devices = config.dict(type=ArborDevice, required=True)
16
-
17
- @config.property(default=1)
18
- def threads(self):
19
- return self._threads
20
-
21
- @threads.setter
22
- def threads(self, value):
23
- self._threads = value if value != "all" else psutil.cpu_count(logical=False)
@@ -1,69 +0,0 @@
1
- [build-system]
2
- requires = ["flit_core >=3.2,<4"]
3
- build-backend = "flit_core.buildapi"
4
-
5
- [project]
6
- name = "bsb-arbor"
7
- authors = [{name = "Robin De Schepper", email = "robingilbert.deschepper@unipv.it"}]
8
- readme = "README.md"
9
- license = {file = "LICENSE"}
10
- classifiers = ["License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)"]
11
- dynamic = ["version", "description"]
12
- dependencies = [
13
- "numpy~=1.21",
14
- "bsb-core~=5.0",
15
- "arbor~=0.10",
16
- "arborize[arbor]~=4.0"
17
- ]
18
-
19
- [project.entry-points."bsb.simulation_backends"]
20
- arbor = "bsb_arbor"
21
-
22
- [tool.flit.module]
23
- name = "bsb_arbor"
24
-
25
- [project.optional-dependencies]
26
- parallel = ["bsb-core[parallel]"]
27
- test = [
28
- "bsb-core[parallel]",
29
- "bsb-hdf5~=5.0",
30
- "bsb-test~=4.0",
31
- "coverage~=7.0"
32
- ]
33
- dev = [
34
- "bsb-arbor[test]",
35
- "build~=1.0",
36
- "twine~=4.0",
37
- "pre-commit~=3.5",
38
- "black~=24.1.1",
39
- "isort~=5.12",
40
- "snakeviz~=2.1",
41
- "bump-my-version~=0.24"
42
- ]
43
-
44
- [tool.isort]
45
- profile = "black"
46
-
47
- [tool.bumpversion]
48
- current_version = "4.1.1"
49
- parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
50
- serialize = ["{major}.{minor}.{patch}"]
51
- search = "{current_version}"
52
- replace = "{new_version}"
53
- regex = false
54
- ignore_missing_version = false
55
- tag = true
56
- sign_tags = false
57
- tag_name = "v{new_version}"
58
- tag_message = "Bump version: {current_version} → {new_version}"
59
- allow_dirty = false
60
- commit = true
61
- message = "Bump version: {current_version} → {new_version}"
62
- commit_args = "--no-verify"
63
-
64
- [tool.bumpversion.parts.pre_l]
65
- values = ["dev", "a", "b", "rc", "final"]
66
- optional_value = "final"
67
-
68
- [[tool.bumpversion.files]]
69
- filename = "bsb_arbor/__init__.py"
File without changes