bluecellulab 2.4.0__py3-none-any.whl → 2.5.0__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 bluecellulab might be problematic. Click here for more details.

bluecellulab/__init__.py CHANGED
@@ -8,9 +8,9 @@ except ImportError:
8
8
  BLUEPY_AVAILABLE = False
9
9
 
10
10
  from .importer import * # NOQA
11
- from .tools import * # NOQA
12
11
  from .verbosity import *
13
12
  from .cell import Cell, create_ball_stick # NOQA
13
+ from .circuit import EmodelProperties
14
14
  from .connection import Connection # NOQA
15
15
  from .plotwindow import PlotWindow # NOQA
16
16
  from .dendrogram import Dendrogram # NOQA
@@ -19,3 +19,10 @@ from .psegment import PSegment # NOQA
19
19
  from .simulation import Simulation # NOQA
20
20
  from .rngsettings import RNGSettings # NOQA
21
21
  from .ssim import SSim # NOQA
22
+
23
+
24
+ from .simulation.neuron_globals import NeuronGlobals
25
+
26
+ logger.debug("Loading the hoc files.")
27
+ import_hoc(neuron)
28
+ _ = NeuronGlobals.get_instance() # initiate the singleton
File without changes
@@ -0,0 +1,130 @@
1
+ """Module for injecting a sequence of protocols to the cell."""
2
+ from __future__ import annotations
3
+ from enum import Enum, auto
4
+ from typing import NamedTuple, Sequence, Dict
5
+
6
+ import neuron
7
+ import numpy as np
8
+ from bluecellulab.cell.core import Cell
9
+ from bluecellulab.cell.template import TemplateParams
10
+ from bluecellulab.simulation.simulation import Simulation
11
+ from bluecellulab.stimulus.factory import Stimulus, StimulusFactory
12
+ from bluecellulab.utils import IsolatedProcess
13
+
14
+
15
+ class StimulusName(Enum):
16
+ """Allowed values for the StimulusName."""
17
+ AP_WAVEFORM = auto()
18
+ IDREST = auto()
19
+ IV = auto()
20
+ FIRE_PATTERN = auto()
21
+
22
+
23
+ class Recording(NamedTuple):
24
+ """A tuple of the current, voltage and time recordings."""
25
+ current: np.ndarray
26
+ voltage: np.ndarray
27
+ time: np.ndarray
28
+
29
+
30
+ StimulusRecordings = Dict[str, Recording]
31
+
32
+
33
+ def run_stimulus(
34
+ template_params: TemplateParams,
35
+ stimulus: Stimulus,
36
+ section: str,
37
+ segment: float,
38
+ duration: float,
39
+ ) -> Recording:
40
+ """Creates a cell and stimulates it with a given stimulus.
41
+
42
+ Args:
43
+ template_params: The parameters to create the cell from a template.
44
+ stimulus: The input stimulus to inject into the cell.
45
+ section: Name of the section of cell where the stimulus is to be injected.
46
+ segment: The segment of the section where the stimulus is to be injected.
47
+ duration: The duration for which the simulation is to be run.
48
+
49
+ Returns:
50
+ The voltage-time recording at the specified location.
51
+
52
+ Raises:
53
+ ValueError: If the time and voltage arrays are not the same length.
54
+ """
55
+ cell = Cell.from_template_parameters(template_params)
56
+ neuron_section = cell.sections[section]
57
+ cell.add_voltage_recording(neuron_section, segment)
58
+ iclamp, _ = cell.inject_current_waveform(
59
+ stimulus.time, stimulus.current, section=neuron_section, segx=segment
60
+ )
61
+ current_vector = neuron.h.Vector()
62
+ current_vector.record(iclamp._ref_i)
63
+ simulation = Simulation(cell)
64
+ simulation.run(duration)
65
+ current = np.array(current_vector.to_python())
66
+ voltage = cell.get_voltage_recording(neuron_section, segment)
67
+ time = cell.get_time()
68
+ if len(time) != len(voltage) or len(time) != len(current):
69
+ raise ValueError("Time, current and voltage arrays are not the same length")
70
+ return Recording(current, voltage, time)
71
+
72
+
73
+ def apply_multiple_step_stimuli(
74
+ cell: Cell,
75
+ stimulus_name: StimulusName,
76
+ amplitudes: Sequence[float],
77
+ duration: float,
78
+ section_name: str | None = None,
79
+ segment: float = 0.5,
80
+ n_processes: int | None = None,
81
+ ) -> StimulusRecordings:
82
+ """Apply multiple stimuli to the cell on isolated processes.
83
+
84
+ Args:
85
+ cell: The cell to which the stimuli are applied.
86
+ stimulus_name: The name of the stimulus to apply.
87
+ amplitudes: The amplitudes of the stimuli to apply.
88
+ duration: The duration for which each stimulus is applied.
89
+ section_name: Section name of the cell where the stimuli are applied.
90
+ If None, the stimuli are applied at the soma[0] of the cell.
91
+ segment: The segment of the section where the stimuli are applied.
92
+ n_processes: The number of processes to use for running the stimuli.
93
+
94
+ Returns:
95
+ A dictionary where the keys are the names of the stimuli and the values
96
+ are the recordings of the cell's response to each stimulus.
97
+
98
+ Raises:
99
+ ValueError: If the stimulus name is not recognized.
100
+ """
101
+ res: StimulusRecordings = {}
102
+ stim_factory = StimulusFactory(dt=1.0)
103
+ task_args = []
104
+ section_name = section_name if section_name is not None else "soma[0]"
105
+
106
+ # Prepare arguments for each stimulus
107
+ for amplitude in amplitudes:
108
+ if stimulus_name == StimulusName.AP_WAVEFORM:
109
+ stimulus = stim_factory.ap_waveform(threshold_current=cell.threshold, threshold_percentage=amplitude)
110
+ elif stimulus_name == StimulusName.IDREST:
111
+ stimulus = stim_factory.idrest(threshold_current=cell.threshold, threshold_percentage=amplitude)
112
+ elif stimulus_name == StimulusName.IV:
113
+ stimulus = stim_factory.iv(threshold_current=cell.threshold, threshold_percentage=amplitude)
114
+ elif stimulus_name == StimulusName.FIRE_PATTERN:
115
+ stimulus = stim_factory.fire_pattern(threshold_current=cell.threshold, threshold_percentage=amplitude)
116
+ else:
117
+ raise ValueError("Unknown stimulus name.")
118
+
119
+ task_args.append((cell.template_params, stimulus, section_name, segment, duration))
120
+
121
+ with IsolatedProcess(processes=n_processes) as pool:
122
+ # Map expects a function and a list of argument tuples
123
+ results = pool.starmap(run_stimulus, task_args)
124
+
125
+ # Associate each result with a key
126
+ for amplitude, result in zip(amplitudes, results):
127
+ key = f"{stimulus_name}_{amplitude}"
128
+ res[key] = result
129
+
130
+ return res
bluecellulab/cell/core.py CHANGED
@@ -27,24 +27,25 @@ import numpy as np
27
27
  import pandas as pd
28
28
 
29
29
  import bluecellulab
30
+ from bluecellulab.cell.recording import section_to_voltage_recording_str
30
31
  from bluecellulab.psection import PSection, init_psections
31
32
  from bluecellulab.cell.injector import InjectableMixin
32
33
  from bluecellulab.cell.plotting import PlottableMixin
33
34
  from bluecellulab.cell.section_distance import EuclideanSectionDistance
34
35
  from bluecellulab.cell.sonata_proxy import SonataProxy
35
- from bluecellulab.cell.template import NeuronTemplate, public_hoc_cell
36
+ from bluecellulab.cell.template import NeuronTemplate, TemplateParams, public_hoc_cell
36
37
  from bluecellulab.circuit.config.sections import Conditions
37
38
  from bluecellulab.circuit import EmodelProperties, SynapseProperty
38
39
  from bluecellulab.circuit.node_id import CellId
39
40
  from bluecellulab.circuit.simulation_access import get_synapse_replay_spikes
40
41
  from bluecellulab.exceptions import BluecellulabError
41
- from bluecellulab.importer import load_hoc_and_mod_files
42
+ from bluecellulab.importer import load_mod_files
42
43
  from bluecellulab.neuron_interpreter import eval_neuron
43
44
  from bluecellulab.rngsettings import RNGSettings
44
45
  from bluecellulab.stimulus.circuit_stimulus_definitions import SynapseReplay
45
46
  from bluecellulab.synapse import SynapseFactory, Synapse
46
47
  from bluecellulab.synapse.synapse_types import SynapseID
47
- from bluecellulab.type_aliases import HocObjectType, NeuronSection
48
+ from bluecellulab.type_aliases import HocObjectType, NeuronSection, SectionMapping
48
49
 
49
50
  logger = logging.getLogger(__name__)
50
51
 
@@ -54,7 +55,25 @@ class Cell(InjectableMixin, PlottableMixin):
54
55
 
55
56
  last_id = 0
56
57
 
57
- @load_hoc_and_mod_files
58
+ @classmethod
59
+ def from_template_parameters(
60
+ cls, template_params: TemplateParams, cell_id: Optional[CellId] = None,
61
+ record_dt: Optional[float] = None
62
+ ) -> Cell:
63
+ """Create a cell from a TemplateParams object.
64
+
65
+ Useful in isolating runs.
66
+ """
67
+ return cls(
68
+ template_path=template_params.template_filepath,
69
+ morphology_path=template_params.morph_filepath,
70
+ cell_id=cell_id,
71
+ record_dt=record_dt,
72
+ template_format=template_params.template_format,
73
+ emodel_properties=template_params.emodel_properties,
74
+ )
75
+
76
+ @load_mod_files
58
77
  def __init__(self,
59
78
  template_path: str | Path,
60
79
  morphology_path: str | Path,
@@ -73,6 +92,12 @@ class Cell(InjectableMixin, PlottableMixin):
73
92
  emodel_properties: Template specific emodel properties.
74
93
  """
75
94
  super().__init__()
95
+ self.template_params = TemplateParams(
96
+ template_filepath=template_path,
97
+ morph_filepath=morphology_path,
98
+ template_format=template_format,
99
+ emodel_properties=emodel_properties,
100
+ )
76
101
  if cell_id is None:
77
102
  cell_id = CellId("", Cell.last_id)
78
103
  Cell.last_id += 1
@@ -86,17 +111,16 @@ class Cell(InjectableMixin, PlottableMixin):
86
111
  if emodel_properties is None:
87
112
  raise BluecellulabError('EmodelProperties must be provided for v6 template')
88
113
  self.hypamp: float | None = emodel_properties.holding_current
89
- self.threshold: float | None = emodel_properties.threshold_current
114
+ self.threshold: float = emodel_properties.threshold_current
90
115
  else:
91
116
  try:
92
117
  self.hypamp = self.cell.getHypAmp()
93
118
  except AttributeError:
94
119
  self.hypamp = None
95
-
96
120
  try:
97
121
  self.threshold = self.cell.getThreshold()
98
122
  except AttributeError:
99
- self.threshold = None
123
+ self.threshold = 0.0
100
124
  self.soma = public_hoc_cell(self.cell).soma[0]
101
125
  # WARNING: this finitialize 'must' be here, otherwhise the
102
126
  # diameters of the loaded morph are wrong
@@ -131,6 +155,13 @@ class Cell(InjectableMixin, PlottableMixin):
131
155
  # as the object exists
132
156
  self.persistent: list[HocObjectType] = []
133
157
 
158
+ def _extract_sections(self, sections) -> SectionMapping:
159
+ res: SectionMapping = {}
160
+ for section in sections:
161
+ key_name = str(section).split(".")[-1]
162
+ res[key_name] = section
163
+ return res
164
+
134
165
  @property
135
166
  def somatic(self) -> list[NeuronSection]:
136
167
  return list(public_hoc_cell(self.cell).somatic)
@@ -148,8 +179,8 @@ class Cell(InjectableMixin, PlottableMixin):
148
179
  return list(public_hoc_cell(self.cell).axonal)
149
180
 
150
181
  @property
151
- def all(self) -> list[NeuronSection]:
152
- return list(public_hoc_cell(self.cell).all)
182
+ def sections(self) -> SectionMapping:
183
+ return self._extract_sections(public_hoc_cell(self.cell).all)
153
184
 
154
185
  def __repr__(self) -> str:
155
186
  base_info = f"Cell Object: {super().__repr__()}"
@@ -160,29 +191,10 @@ class Cell(InjectableMixin, PlottableMixin):
160
191
  """Connect this cell to a circuit via sonata proxy."""
161
192
  self.sonata_proxy = sonata_proxy
162
193
 
163
- def re_init_rng(self, use_random123_stochkv: bool = False) -> None:
194
+ def re_init_rng(self) -> None:
164
195
  """Reinitialize the random number generator for stochastic channels."""
165
-
166
196
  if not self.is_made_passive:
167
- if use_random123_stochkv:
168
- channel_id = 0
169
- for section in self.somatic:
170
- for seg in section:
171
- neuron.h.setdata_StochKv(seg.x, sec=section)
172
- neuron.h.setRNG_StochKv(channel_id, self.cell_id.id)
173
- channel_id += 1
174
- for section in self.basal:
175
- for seg in section:
176
- neuron.h.setdata_StochKv(seg.x, sec=section)
177
- neuron.h.setRNG_StochKv(channel_id, self.cell_id.id)
178
- channel_id += 1
179
- for section in self.apical:
180
- for seg in section:
181
- neuron.h.setdata_StochKv(seg.x, sec=section)
182
- neuron.h.setRNG_StochKv(channel_id, self.cell_id.id)
183
- channel_id += 1
184
- else:
185
- self.cell.re_init_rng()
197
+ self.cell.re_init_rng()
186
198
 
187
199
  def get_psection(self, section_id: int | str) -> PSection:
188
200
  """Return a python section with the specified section id."""
@@ -197,7 +209,7 @@ class Cell(InjectableMixin, PlottableMixin):
197
209
 
198
210
  def make_passive(self) -> None:
199
211
  """Make the cell passive by deactivating all the active channels."""
200
- for section in self.all:
212
+ for section in self.sections.values():
201
213
  mech_names = set()
202
214
  for seg in section:
203
215
  for mech in seg:
@@ -232,14 +244,14 @@ class Cell(InjectableMixin, PlottableMixin):
232
244
 
233
245
  def _default_enable_ttx(self) -> None:
234
246
  """Default enable_ttx implementation."""
235
- for section in self.all:
247
+ for section in self.sections.values():
236
248
  if not neuron.h.ismembrane("TTXDynamicsSwitch"):
237
249
  section.insert('TTXDynamicsSwitch')
238
250
  section.ttxo_level_TTXDynamicsSwitch = 1.0
239
251
 
240
252
  def _default_disable_ttx(self) -> None:
241
253
  """Default disable_ttx implementation."""
242
- for section in self.all:
254
+ for section in self.sections.values():
243
255
  if not neuron.h.ismembrane("TTXDynamicsSwitch"):
244
256
  section.insert('TTXDynamicsSwitch')
245
257
  section.ttxo_level_TTXDynamicsSwitch = 1e-14
@@ -247,7 +259,7 @@ class Cell(InjectableMixin, PlottableMixin):
247
259
  def area(self) -> float:
248
260
  """The total surface area of the cell."""
249
261
  area = 0.0
250
- for section in self.all:
262
+ for section in self.sections.values():
251
263
  x_s = np.arange(1.0 / (2 * section.nseg), 1.0,
252
264
  1.0 / (section.nseg))
253
265
  for x in x_s:
@@ -297,7 +309,7 @@ class Cell(InjectableMixin, PlottableMixin):
297
309
  self.add_recording("self.axonal[1](0.5)._ref_v", dt=dt)
298
310
 
299
311
  def add_voltage_recording(
300
- self, section: "neuron.h.Section", segx: float = 0.5, dt: Optional[float] = None
312
+ self, section: Optional[NeuronSection] = None, segx: float = 0.5, dt: Optional[float] = None
301
313
  ) -> None:
302
314
  """Add a voltage recording to a certain section at a given segment
303
315
  (segx).
@@ -309,11 +321,13 @@ class Cell(InjectableMixin, PlottableMixin):
309
321
  dt: Recording time step. If not provided, the recording step will
310
322
  default to the simulator's time step.
311
323
  """
312
- var_name = f"neuron.h.{section.name()}({segx})._ref_v"
324
+ if section is None:
325
+ section = self.soma
326
+ var_name = section_to_voltage_recording_str(section, segx)
313
327
  self.add_recording(var_name, dt)
314
328
 
315
329
  def get_voltage_recording(
316
- self, section: "neuron.h.Section", segx: float = 0.5
330
+ self, section: Optional[NeuronSection] = None, segx: float = 0.5
317
331
  ) -> np.ndarray:
318
332
  """Get a voltage recording for a certain section at a given segment
319
333
  (segx).
@@ -329,7 +343,9 @@ class Cell(InjectableMixin, PlottableMixin):
329
343
  Raises:
330
344
  BluecellulabError: If voltage recording was not added previously using add_voltage_recording.
331
345
  """
332
- recording_name = f"neuron.h.{section.name()}({segx})._ref_v"
346
+ if section is None:
347
+ section = self.soma
348
+ recording_name = section_to_voltage_recording_str(section, segx)
333
349
  if recording_name in self.recordings:
334
350
  return self.get_recording(recording_name)
335
351
  else:
@@ -340,15 +356,13 @@ class Cell(InjectableMixin, PlottableMixin):
340
356
 
341
357
  def add_allsections_voltagerecordings(self):
342
358
  """Add a voltage recording to every section of the cell."""
343
- all_sections = public_hoc_cell(self.cell).all
344
- for section in all_sections:
359
+ for section in self.sections.values():
345
360
  self.add_voltage_recording(section, dt=self.record_dt)
346
361
 
347
362
  def get_allsections_voltagerecordings(self) -> dict[str, np.ndarray]:
348
363
  """Get all the voltage recordings from all the sections."""
349
364
  all_section_voltages = {}
350
- all_sections = public_hoc_cell(self.cell).all
351
- for section in all_sections:
365
+ for section in self.sections.values():
352
366
  recording = self.get_voltage_recording(section)
353
367
  all_section_voltages[section.name()] = recording
354
368
  return all_section_voltages
@@ -426,10 +440,10 @@ class Cell(InjectableMixin, PlottableMixin):
426
440
  """
427
441
  if location == "soma":
428
442
  sec = public_hoc_cell(self.cell).soma[0]
429
- source = public_hoc_cell(self.cell).soma[0](1)._ref_v
443
+ source = sec(1)._ref_v
430
444
  elif location == "AIS":
431
445
  sec = public_hoc_cell(self.cell).axon[1]
432
- source = public_hoc_cell(self.cell).axon[1](0.5)._ref_v
446
+ source = sec(0.5)._ref_v
433
447
  else:
434
448
  raise ValueError("Spike detection location must be soma or AIS")
435
449
  netcon = neuron.h.NetCon(source, target, sec=sec)
@@ -682,9 +696,10 @@ class Cell(InjectableMixin, PlottableMixin):
682
696
  """Get a vector of AIS voltage."""
683
697
  return self.get_recording('self.axonal[1](0.5)._ref_v')
684
698
 
685
- def getNumberOfSegments(self) -> int:
699
+ @property
700
+ def n_segments(self) -> int:
686
701
  """Get the number of segments in the cell."""
687
- return sum(section.nseg for section in self.all)
702
+ return sum(section.nseg for section in self.sections.values())
688
703
 
689
704
  def add_synapse_replay(
690
705
  self, stimulus: SynapseReplay, spike_threshold: float, spike_location: str
@@ -443,14 +443,14 @@ class InjectableMixin:
443
443
  time_vector = neuron.h.Vector().from_python(t_content)
444
444
  current_vector = neuron.h.Vector().from_python(i_content)
445
445
 
446
- pulse = neuron.h.IClamp(segx, sec=section)
447
- self.persistent.extend([pulse, time_vector, current_vector])
446
+ iclamp = neuron.h.IClamp(segx, sec=section)
447
+ self.persistent.extend([iclamp, time_vector, current_vector])
448
448
 
449
- pulse.delay = t_content[0]
450
- pulse.dur = t_content[-1] - t_content[0]
451
- current_vector.play(pulse._ref_amp, time_vector)
449
+ iclamp.delay = t_content[0]
450
+ iclamp.dur = t_content[-1] - t_content[0]
451
+ current_vector.play(iclamp._ref_amp, time_vector)
452
452
 
453
- return current_vector
453
+ return iclamp, current_vector
454
454
 
455
455
  @deprecated("Use add_sin_current instead.")
456
456
  def addSineCurrentInject(self, start_time, stop_time, freq,
@@ -0,0 +1,8 @@
1
+ """Neuron recordings related functions."""
2
+ from __future__ import annotations
3
+ from bluecellulab.type_aliases import NeuronSection
4
+
5
+
6
+ def section_to_voltage_recording_str(section: NeuronSection, segment=0.5) -> str:
7
+ """Converts a section and segment to voltage recording string."""
8
+ return f"neuron.h.{section.name()}({segment})._ref_v"
@@ -20,7 +20,7 @@ import os
20
20
  from pathlib import Path
21
21
  import re
22
22
  import string
23
- from typing import Optional
23
+ from typing import NamedTuple, Optional
24
24
 
25
25
  import neuron
26
26
 
@@ -44,6 +44,13 @@ def public_hoc_cell(cell: HocObjectType) -> HocObjectType:
44
44
  from the hoc model. Either getCell() or CellRef needs to be provided""")
45
45
 
46
46
 
47
+ class TemplateParams(NamedTuple):
48
+ template_filepath: str | Path
49
+ morph_filepath: str | Path
50
+ template_format: str
51
+ emodel_properties: Optional[EmodelProperties]
52
+
53
+
47
54
  class NeuronTemplate:
48
55
  """NeuronTemplate representation."""
49
56
 
bluecellulab/importer.py CHANGED
@@ -52,8 +52,8 @@ def import_mod_lib(neuron: ModuleType) -> str:
52
52
  return res
53
53
 
54
54
 
55
- def import_neurodamus(neuron: ModuleType) -> None:
56
- """Import neurodamus."""
55
+ def import_hoc(neuron: ModuleType) -> None:
56
+ """Import hoc dependencies."""
57
57
  neuron.h.load_file("stdrun.hoc") # nrn
58
58
  hoc_files = [
59
59
  "Cell.hoc", # ND
@@ -75,17 +75,15 @@ def print_header(neuron: ModuleType, mod_lib_path: str) -> None:
75
75
 
76
76
 
77
77
  @run_once
78
- def _load_hoc_and_mod_files() -> None:
78
+ def _load_mod_files() -> None:
79
79
  """Import hoc and mod files."""
80
80
  logger.debug("Loading the mod files.")
81
81
  mod_lib_paths = import_mod_lib(neuron)
82
- logger.debug("Loading the hoc files.")
83
- import_neurodamus(neuron)
84
82
  print_header(neuron, mod_lib_paths)
85
83
 
86
84
 
87
- def load_hoc_and_mod_files(func):
85
+ def load_mod_files(func):
88
86
  def wrapper(*args, **kwargs):
89
- _load_hoc_and_mod_files()
87
+ _load_mod_files()
90
88
  return func(*args, **kwargs)
91
89
  return wrapper
@@ -20,7 +20,7 @@ from typing import Optional
20
20
  import neuron
21
21
  from bluecellulab.circuit.config.definition import SimulationConfig
22
22
  from bluecellulab.exceptions import UndefinedRNGException
23
- from bluecellulab.importer import load_hoc_and_mod_files
23
+ from bluecellulab.importer import load_mod_files
24
24
 
25
25
  logger = logging.getLogger(__name__)
26
26
 
@@ -37,7 +37,7 @@ class RNGSettings:
37
37
  cls._instance = cls()
38
38
  return cls._instance
39
39
 
40
- @load_hoc_and_mod_files
40
+ @load_mod_files
41
41
  def __init__(
42
42
  self,
43
43
  mode="Random123",
@@ -3,4 +3,3 @@
3
3
  from .simulation import Simulation
4
4
  from .neuron_globals import set_global_condition_parameters
5
5
  from .neuron_globals import set_minis_single_vesicle_values
6
- from .neuron_globals import set_tstop_value
@@ -62,6 +62,37 @@ def set_minis_single_vesicle_values(mech_conditions: MechanismConditions) -> Non
62
62
  )
63
63
 
64
64
 
65
- def set_tstop_value(tstop: float) -> None:
66
- """Set the tstop value required by Tstim noise stimuli."""
67
- neuron.h.tstop = tstop
65
+ class NeuronGlobals:
66
+ _instance = None
67
+
68
+ def __init__(self):
69
+ raise RuntimeError('Call get_instance() instead')
70
+
71
+ @classmethod
72
+ def get_instance(cls):
73
+ if cls._instance is None:
74
+ cls._instance = cls.__new__(cls)
75
+ # Initialize default values
76
+ cls._instance._temperature = 34.0 # Default temperature
77
+ cls._instance.v_init = neuron.h.v_init
78
+ # Set the default values in NEURON
79
+ neuron.h.celsius = cls._instance._temperature
80
+ return cls._instance
81
+
82
+ @property
83
+ def temperature(self):
84
+ return self._temperature
85
+
86
+ @temperature.setter
87
+ def temperature(self, value):
88
+ self._temperature = value
89
+ neuron.h.celsius = value
90
+
91
+ @property
92
+ def v_init(self):
93
+ return self._v_init
94
+
95
+ @v_init.setter
96
+ def v_init(self, value):
97
+ self._v_init = value
98
+ neuron.h.v_init = value
@@ -88,13 +88,11 @@ class Simulation:
88
88
  cvode=True,
89
89
  cvode_minstep=None,
90
90
  cvode_maxstep=None,
91
- celsius=34,
92
- v_init=-65,
93
91
  dt=0.025,
94
92
  forward_skip=None,
95
93
  forward_skip_value=False,
96
- show_progress=None,
97
- use_random123_stochkv=False):
94
+ show_progress=None
95
+ ):
98
96
  """Run the simulation."""
99
97
  # if maxtime <= neuron.h.t:
100
98
  # raise Exception("Simulation: need to provide a maxtime (=%f) "
@@ -108,7 +106,6 @@ class Simulation:
108
106
  self.progress_dt = maxtime / 100
109
107
  self.init_progress_callback()
110
108
 
111
- neuron.h.celsius = celsius
112
109
  neuron.h.tstop = maxtime
113
110
 
114
111
  cvode_old_status = neuron.h.cvode_active()
@@ -125,11 +122,9 @@ class Simulation:
125
122
  "was set")
126
123
  neuron.h.cvode_active(0)
127
124
 
128
- neuron.h.v_init = v_init
129
-
130
125
  for cell in self.cells:
131
126
  with contextlib.suppress(AttributeError):
132
- cell.re_init_rng(use_random123_stochkv=use_random123_stochkv)
127
+ cell.re_init_rng()
133
128
  neuron.h.dt = dt
134
129
  neuron.h.steps_per_ms = 1.0 / dt
135
130
 
@@ -176,6 +171,3 @@ class Simulation:
176
171
  neuron.h.cvode_active(cvode_old_status)
177
172
 
178
173
  logger.debug("Finished simulation.")
179
-
180
- def __del__(self):
181
- pass
bluecellulab/ssim.py CHANGED
@@ -39,14 +39,14 @@ from bluecellulab.circuit.config import SimulationConfig
39
39
  from bluecellulab.circuit.format import determine_circuit_format, CircuitFormat
40
40
  from bluecellulab.circuit.node_id import create_cell_id, create_cell_ids
41
41
  from bluecellulab.circuit.simulation_access import BluepySimulationAccess, SimulationAccess, SonataSimulationAccess, _sample_array
42
- from bluecellulab.importer import load_hoc_and_mod_files
42
+ from bluecellulab.importer import load_mod_files
43
43
  from bluecellulab.rngsettings import RNGSettings
44
+ from bluecellulab.simulation.neuron_globals import NeuronGlobals
44
45
  from bluecellulab.stimulus.circuit_stimulus_definitions import Noise, OrnsteinUhlenbeck, RelativeOrnsteinUhlenbeck, RelativeShotNoise, ShotNoise
45
46
  import bluecellulab.stimulus.circuit_stimulus_definitions as circuit_stimulus_definitions
46
47
  from bluecellulab.exceptions import BluecellulabError
47
48
  from bluecellulab.simulation import (
48
49
  set_global_condition_parameters,
49
- set_tstop_value
50
50
  )
51
51
  from bluecellulab.synapse.synapse_types import SynapseID
52
52
 
@@ -56,7 +56,7 @@ logger = logging.getLogger(__name__)
56
56
  class SSim:
57
57
  """Class that loads a circuit simulation to do cell simulations."""
58
58
 
59
- @load_hoc_and_mod_files
59
+ @load_mod_files
60
60
  def __init__(
61
61
  self,
62
62
  simulation_config: str | Path | SimulationConfig,
@@ -106,11 +106,6 @@ class SSim:
106
106
 
107
107
  self.gids_instantiated = False
108
108
 
109
- # Make sure tstop is set correctly, because it is used by the
110
- # TStim noise stimulus
111
- if self.circuit_access.config.duration is not None:
112
- set_tstop_value(self.circuit_access.config.duration)
113
-
114
109
  self.spike_threshold = self.circuit_access.config.spike_threshold
115
110
  self.spike_location = self.circuit_access.config.spike_location
116
111
 
@@ -596,8 +591,10 @@ class SSim:
596
591
  forward_skip_value = self.circuit_access.config.forward_skip
597
592
  if celsius is None:
598
593
  celsius = self.circuit_access.config.celsius
594
+ NeuronGlobals.get_instance().temperature = celsius
599
595
  if v_init is None:
600
596
  v_init = self.circuit_access.config.v_init
597
+ NeuronGlobals.get_instance().v_init = v_init
601
598
 
602
599
  sim = bluecellulab.Simulation(self.pc)
603
600
  for cell_id in self.cells:
@@ -612,8 +609,6 @@ class SSim:
612
609
  t_stop,
613
610
  cvode=cvode,
614
611
  dt=dt,
615
- celsius=celsius,
616
- v_init=v_init,
617
612
  forward_skip=forward_skip,
618
613
  forward_skip_value=forward_skip_value,
619
614
  show_progress=show_progress)
bluecellulab/tools.py CHANGED
@@ -60,6 +60,8 @@ def calculate_SS_voltage(
60
60
  template_format: str,
61
61
  emodel_properties: EmodelProperties | None,
62
62
  step_level: float,
63
+ check_for_spiking=False,
64
+ spike_threshold=-20.0,
63
65
  ) -> float:
64
66
  """Calculate the steady state voltage at a certain current step."""
65
67
  with IsolatedProcess() as runner:
@@ -71,6 +73,8 @@ def calculate_SS_voltage(
71
73
  template_format,
72
74
  emodel_properties,
73
75
  step_level,
76
+ check_for_spiking,
77
+ spike_threshold,
74
78
  ],
75
79
  )
76
80
  return SS_voltage
@@ -82,8 +86,8 @@ def calculate_SS_voltage_subprocess(
82
86
  template_format: str,
83
87
  emodel_properties: EmodelProperties | None,
84
88
  step_level: float,
85
- check_for_spiking=False,
86
- spike_threshold=-20.0,
89
+ check_for_spiking: bool,
90
+ spike_threshold: float,
87
91
  ) -> float:
88
92
  """Subprocess wrapper of calculate_SS_voltage.
89
93
 
@@ -1,5 +1,6 @@
1
1
  """Type aliases used within the package."""
2
-
2
+ from __future__ import annotations
3
+ from typing import Dict
3
4
  from typing_extensions import TypeAlias
4
5
  from neuron import h as hoc_type
5
6
 
@@ -8,3 +9,5 @@ NeuronRNG: TypeAlias = hoc_type
8
9
  NeuronVector: TypeAlias = hoc_type
9
10
  NeuronSection: TypeAlias = hoc_type
10
11
  TStim: TypeAlias = hoc_type
12
+
13
+ SectionMapping = Dict[str, NeuronSection]
bluecellulab/utils.py CHANGED
@@ -50,5 +50,11 @@ class IsolatedProcess(Pool):
50
50
  Use this when running isolated NEURON simulations. Running 2 NEURON
51
51
  simulations on a single process is to be avoided.
52
52
  """
53
- def __init__(self):
54
- super().__init__(processes=1, maxtasksperchild=1)
53
+ def __init__(self, processes: int | None = 1):
54
+ """Initialize the IsolatedProcess pool.
55
+
56
+ Args:
57
+ processes: The number of processes to use for running the stimuli.
58
+ If set to None, then the number returned by os.cpu_count() is used.
59
+ """
60
+ super().__init__(processes=processes, maxtasksperchild=1)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bluecellulab
3
- Version: 2.4.0
3
+ Version: 2.5.0
4
4
  Summary: The Pythonic Blue Brain simulator access
5
5
  Home-page: https://github.com/BlueBrain/BlueCelluLab
6
6
  Author: Blue Brain Project, EPFL
@@ -1,30 +1,33 @@
1
- bluecellulab/__init__.py,sha256=lYxUZtN_mLNUPJgBnKd4GbwDIVScDPD6ouC7OvWQxS0,645
1
+ bluecellulab/__init__.py,sha256=yC97iFnCVDtwqspxdpt4C-qq9vQF7AMJOWe1h_cB0Wc,827
2
2
  bluecellulab/connection.py,sha256=volV2YKtmqAF7MOEJar5ldF1ARAo7k2vF9MB1NXybUY,4640
3
3
  bluecellulab/dendrogram.py,sha256=w0vvv0Q169DolTX1j9dAZIvHIl4H258gAjQ1xQaNiGk,6427
4
4
  bluecellulab/exceptions.py,sha256=KIxF7s_7gPVJ07TiQ-Z1D8de7ylV74gNMhzl0339CVM,2379
5
5
  bluecellulab/graph.py,sha256=ODiQy4xjRVxtNITXeXpYnqHas0wR7gZ_aXuDAF7jMq4,3419
6
- bluecellulab/importer.py,sha256=l5nvD0y41-AheqoDNBGAX5qFTCG6_UFlLmqyFbUo77E,2998
6
+ bluecellulab/importer.py,sha256=zwVi1Nx2f8xzFfzxzYoXa7gfi7DQapqkRJII5sBbRyY,2900
7
7
  bluecellulab/neuron_interpreter.py,sha256=hXig_u3T6JmEHbkV8ZblEZtX0kY80ate4VpRtANNFrM,2185
8
8
  bluecellulab/plotwindow.py,sha256=UVHzml-BB83m5Qr-YGkjR9kB-vSW8mM0Owh2j95yIaU,2721
9
9
  bluecellulab/psection.py,sha256=EgAS8IS9DcYv2xOkNISgfg_CfRc0nDfRFjvgQhyi9eY,6328
10
10
  bluecellulab/psegment.py,sha256=rBryDYHC_uDK9itfXXrFZ0DL9F6WgRICL0j5EHN56QM,3125
11
- bluecellulab/rngsettings.py,sha256=qjwnzAEdbRt66DKd_NTD2OZnlu4hDH7UUOXxd0G9c_Q,4244
12
- bluecellulab/ssim.py,sha256=U8HFKso4lQkKowts_x2DQfG3ihR56KcN0ITeTlGu3hI,33533
13
- bluecellulab/tools.py,sha256=tS9a9VDMQOVw6zIllT3FxPIzQk4xheNlGf8lpIg01FY,10931
14
- bluecellulab/type_aliases.py,sha256=D-evdt299aK61rTh8YGCj-atcj_iFgZbqEoa2LcAiFw,340
15
- bluecellulab/utils.py,sha256=N9jOOcaxfa4DmG41d7N-M_ywtkAUrRh20llu0gOqXlQ,1743
11
+ bluecellulab/rngsettings.py,sha256=KACk4ujPXhlHL9iAoTdAjjLuFEcUoG6aes92ZClSoQQ,4228
12
+ bluecellulab/ssim.py,sha256=radFcT2lWRfb1C0zKlqw0JQ6JY4b9LJiDP9JDPeQIqs,33399
13
+ bluecellulab/tools.py,sha256=8QMNdmh9lRDOWT4kz9cI_MYNVh4ulxgY8CtHZbaMbkA,11056
14
+ bluecellulab/type_aliases.py,sha256=DvgjERv2Ztdw_sW63JrZTQGpJ0x5uMTFB5hcBHDb0WA,441
15
+ bluecellulab/utils.py,sha256=fgqjgy3xzyL0zu-qjCPJdHp6PEAHADCzlr2FqyBmzHI,2012
16
16
  bluecellulab/verbosity.py,sha256=T0IgX7DrRo19faxrT4Xzb27gqxzoILQ8FzYKxvUeaPM,1342
17
+ bluecellulab/analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ bluecellulab/analysis/inject_sequence.py,sha256=jfEESRAUKAWgjceNWfx3Rwe1gDNWhxwZL4PfnJZCzrg,4930
17
19
  bluecellulab/cell/__init__.py,sha256=Sbc0QOsJ8E7tSwf3q7fsXuE_SevBN6ZmoCVyyU5zfII,208
18
20
  bluecellulab/cell/cell_dict.py,sha256=PVmZsjhZ9jp3HC-8QmdFqp-crAcVMSVeLWujcOPLlpo,1346
19
- bluecellulab/cell/core.py,sha256=A-41oObOZKY5H9MkbYIPpQXAaGPeHtK3aAKWZlirjuw,30861
20
- bluecellulab/cell/injector.py,sha256=28R3MTcnqAB_GGz23BTyWqCurMMkDrrNorgzWDKEFRs,18078
21
+ bluecellulab/cell/core.py,sha256=uxAWAZ6NpODJ3O77p0JWL6AVey3lOyetU3SVZxP4a9Q,31201
22
+ bluecellulab/cell/injector.py,sha256=XC49VSHw78xCHzLJKO_-unnnVZAZXsYg5qbmZPx01AA,18091
21
23
  bluecellulab/cell/plotting.py,sha256=_hZs5oYG4vmJBVf05cJ2O_cVazi5Eap8OkL9BtIwjW8,4001
22
24
  bluecellulab/cell/random.py,sha256=FDby9BN4eJT27COwHP59bhDE2v-c6rdOKNFj3cYZTVY,1773
25
+ bluecellulab/cell/recording.py,sha256=dekJspPb_5yrS6WR3aXtvZ6KWwMNbyhe5aIOVtNDHpY,342
23
26
  bluecellulab/cell/section_distance.py,sha256=J8-oqgCHzRaJkpfjPUR6NFtXDhwbrXad9nDaTCKNkTU,3908
24
27
  bluecellulab/cell/serialized_sections.py,sha256=UQUecO07ChRZ7xHuDp-QAQRUpUiIwROzHxjZliP9gfQ,1614
25
28
  bluecellulab/cell/sonata_proxy.py,sha256=dLT9mLlGVpXxj2O2lXN0g7Sq4BwroPLVdPikR2yNMv4,1529
26
29
  bluecellulab/cell/stimuli_generator.py,sha256=cJwjNwsQeEBHLjuJIFv6VBSqd9IpmbR7CuSMyotCiWc,6320
27
- bluecellulab/cell/template.py,sha256=EW7-hSa_sfWwd2hH_w48sHAlrN9O7XJSmnPfoWFdz08,7374
30
+ bluecellulab/cell/template.py,sha256=K8Vp1-yE6-9wxjmhkLBhnjBhgciUixoMk8LU-GioTgM,7562
28
31
  bluecellulab/cell/ballstick/__init__.py,sha256=v1Z8tHFfbpWShxOBdShCUaE0utoz-7rZumuNBQtNOFI,439
29
32
  bluecellulab/cell/ballstick/emodel.hoc,sha256=7WcuepK-wB9bASRvNdCwO9Woc9-SpBCFqBqCXKgjsV8,1517
30
33
  bluecellulab/cell/ballstick/morphology.asc,sha256=EO0VIRilJAwpiDP2hIevwusfvYptNYhvsu1f5GgbSQo,190
@@ -49,18 +52,18 @@ bluecellulab/hoc/RNGSettings.hoc,sha256=okJBdqlPXET8BrpG1Q31GdaxHfpe3CE0L5P7MAhf
49
52
  bluecellulab/hoc/TDistFunc.hoc,sha256=WKX-anvL83xGuGPH9g1oIORB17UM4Pi3-iIXzKO-pUQ,2663
50
53
  bluecellulab/hoc/TStim.hoc,sha256=noBJbM_ZqF6T6MEgBeowNzz21I9QeYZ5brGgUvCSm4k,8473
51
54
  bluecellulab/hoc/fileUtils.hoc,sha256=LSM7BgyjYVqo2DGSOKvg4W8IIusbsL45JVYK0vgwitU,2539
52
- bluecellulab/simulation/__init__.py,sha256=G1md-6mqaYQkfZT8pmzqRi3WW1fMQCgkeaela2kX3OM,258
53
- bluecellulab/simulation/neuron_globals.py,sha256=PuAxrXbr734RP-5q6YkHpnOgzTVyo_8SYZux9HABlaI,3348
54
- bluecellulab/simulation/simulation.py,sha256=tM5Psl-w25CHA4hp2fqs3GcZ2HSjIbu_6iyOcs-1jd8,6439
55
+ bluecellulab/simulation/__init__.py,sha256=P2ebt0SFw-08J3ihN-LeRn95HeF79tzA-Q0ReLm32dM,214
56
+ bluecellulab/simulation/neuron_globals.py,sha256=uxgceZ7zzbVEtITrQv8oOK900zhh7w29cScFwjLWo4I,4134
57
+ bluecellulab/simulation/simulation.py,sha256=I__cZwV_A8I7XSefn6aJDBA_jXCI3E35-pCNCLUsnvo,6206
55
58
  bluecellulab/stimulus/__init__.py,sha256=DgIgVaSyR-URf3JZzvO6j-tjCerzvktuK-ep8pjMRPQ,37
56
59
  bluecellulab/stimulus/circuit_stimulus_definitions.py,sha256=uij_s44uNdmMwMLGmTHSRgmp9K9B_vvHHshX6YPJNJU,15686
57
60
  bluecellulab/stimulus/factory.py,sha256=AOby3Sp2g8BJsRccz3afazfCyysyWIgLtcliWlyeiu0,8097
58
61
  bluecellulab/synapse/__init__.py,sha256=RW8XoAMXOvK7OG1nHl_q8jSEKLj9ZN4oWf2nY9HAwuk,192
59
62
  bluecellulab/synapse/synapse_factory.py,sha256=YkvxbdGF-u-vxYdbRNTlX-9AtSC_3t_FQRFhybwzgrk,6805
60
63
  bluecellulab/synapse/synapse_types.py,sha256=4gne-hve2vq1Lau-LAVPsfLjffVYqAYBW3kCfC7_600,16871
61
- bluecellulab-2.4.0.dist-info/AUTHORS.txt,sha256=EDs3H-2HXBojbma10psixk3C2rFiOCTIREi2ZAbXYNQ,179
62
- bluecellulab-2.4.0.dist-info/LICENSE,sha256=xOouu1gC1GGklDxkITlaVl60I9Ab860O-nZsFbWydvU,11749
63
- bluecellulab-2.4.0.dist-info/METADATA,sha256=INJHNIWkhkP13SaZcuI50UsUJ8-hTjW35YS_YcAfGZA,6907
64
- bluecellulab-2.4.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
65
- bluecellulab-2.4.0.dist-info/top_level.txt,sha256=VSyEP8w9l3pXdRkyP_goeMwiNA8KWwitfAqUkveJkdQ,13
66
- bluecellulab-2.4.0.dist-info/RECORD,,
64
+ bluecellulab-2.5.0.dist-info/AUTHORS.txt,sha256=EDs3H-2HXBojbma10psixk3C2rFiOCTIREi2ZAbXYNQ,179
65
+ bluecellulab-2.5.0.dist-info/LICENSE,sha256=xOouu1gC1GGklDxkITlaVl60I9Ab860O-nZsFbWydvU,11749
66
+ bluecellulab-2.5.0.dist-info/METADATA,sha256=cZyD4VU0diQXkzIlXFVHT6UAbNb2tsEyD01w-6UICZY,6907
67
+ bluecellulab-2.5.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
68
+ bluecellulab-2.5.0.dist-info/top_level.txt,sha256=VSyEP8w9l3pXdRkyP_goeMwiNA8KWwitfAqUkveJkdQ,13
69
+ bluecellulab-2.5.0.dist-info/RECORD,,