bluecellulab 2.3.7__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,8 +8,9 @@ except ImportError:
8
8
  BLUEPY_AVAILABLE = False
9
9
 
10
10
  from .importer import * # NOQA
11
- from .tools import * # NOQA
11
+ from .verbosity import *
12
12
  from .cell import Cell, create_ball_stick # NOQA
13
+ from .circuit import EmodelProperties
13
14
  from .connection import Connection # NOQA
14
15
  from .plotwindow import PlotWindow # NOQA
15
16
  from .dendrogram import Dendrogram # NOQA
@@ -18,3 +19,10 @@ from .psegment import PSegment # NOQA
18
19
  from .simulation import Simulation # NOQA
19
20
  from .rngsettings import RNGSettings # NOQA
20
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,55 +55,77 @@ 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,
61
80
  cell_id: Optional[CellId] = None,
62
81
  record_dt: Optional[float] = None,
63
82
  template_format: str = "v5",
64
- emodel_properties: Optional[EmodelProperties] = None,
65
- rng_settings: Optional[RNGSettings] = None) -> None:
83
+ emodel_properties: Optional[EmodelProperties] = None) -> None:
66
84
  """Initializes a Cell object.
67
85
 
68
86
  Args:
69
- template_path: Full path to hoc template file.
87
+ template_path: Path to hoc template file.
70
88
  morphology_path: Path to morphology file.
71
- gid: ID of the cell, used in RNG seeds. Defaults to 0.
89
+ cell_id: ID of the cell, used in RNG seeds.
72
90
  record_dt: Timestep for the recordings.
73
- If not provided, a default is used. Defaults to None.
74
- template_format: Cell template format such as 'v5'
75
- or 'v6_air_scaler'. Defaults to "v5".
76
- emodel_properties: Properties such as
77
- threshold_current, holding_current. Defaults to None.
78
- rng_settings: Random number generation setting
79
- object used by the Cell. Defaults to None.
91
+ template_format: Cell template format such as 'v5' or 'v6_air_scaler'.
92
+ emodel_properties: Template specific emodel properties.
80
93
  """
81
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
+ )
82
101
  if cell_id is None:
83
102
  cell_id = CellId("", Cell.last_id)
84
103
  Cell.last_id += 1
85
104
  self.cell_id = cell_id
86
- # Persistent objects, like clamps, that exist as long
87
- # as the object exists
88
- self.persistent: list[HocObjectType] = []
89
-
90
- self.morphology_path = morphology_path
91
105
 
92
106
  # Load the template
93
- neuron_template = NeuronTemplate(template_path, morphology_path)
107
+ neuron_template = NeuronTemplate(template_path, morphology_path, template_format, emodel_properties)
94
108
  self.template_id = neuron_template.template_name # useful to map NEURON and python objects
95
- self.cell = neuron_template.get_cell(template_format, self.cell_id.id, emodel_properties)
109
+ self.cell = neuron_template.get_cell(self.cell_id.id)
110
+ if template_format == 'v6':
111
+ if emodel_properties is None:
112
+ raise BluecellulabError('EmodelProperties must be provided for v6 template')
113
+ self.hypamp: float | None = emodel_properties.holding_current
114
+ self.threshold: float = emodel_properties.threshold_current
115
+ else:
116
+ try:
117
+ self.hypamp = self.cell.getHypAmp()
118
+ except AttributeError:
119
+ self.hypamp = None
120
+ try:
121
+ self.threshold = self.cell.getThreshold()
122
+ except AttributeError:
123
+ self.threshold = 0.0
96
124
  self.soma = public_hoc_cell(self.cell).soma[0]
97
125
  # WARNING: this finitialize 'must' be here, otherwhise the
98
126
  # diameters of the loaded morph are wrong
99
127
  neuron.h.finitialize()
100
128
 
101
- if rng_settings is None:
102
- self.rng_settings = RNGSettings("Random123") # SONATA value
103
- else:
104
- self.rng_settings = rng_settings
105
-
106
129
  self.recordings: dict[str, HocObjectType] = {}
107
130
  self.synapses: dict[SynapseID, Synapse] = {}
108
131
  self.connections: dict[SynapseID, bluecellulab.Connection] = {}
@@ -121,23 +144,6 @@ class Cell(InjectableMixin, PlottableMixin):
121
144
  self.delayed_weights = queue.PriorityQueue() # type: ignore
122
145
  self.psections, self.secname_to_psection = init_psections(public_hoc_cell(self.cell))
123
146
 
124
- self.emodel_properties = emodel_properties
125
- if template_format == 'v6':
126
- if self.emodel_properties is None:
127
- raise BluecellulabError('EmodelProperties must be provided for v6 template')
128
- self.hypamp: float | None = self.emodel_properties.holding_current
129
- self.threshold: float | None = self.emodel_properties.threshold_current
130
- else:
131
- try:
132
- self.hypamp = self.cell.getHypAmp()
133
- except AttributeError:
134
- self.hypamp = None
135
-
136
- try:
137
- self.threshold = self.cell.getThreshold()
138
- except AttributeError:
139
- self.threshold = None
140
-
141
147
  # Keep track of when a cell is made passive by make_passive()
142
148
  # Used to know when re_init_rng() can be executed
143
149
  self.is_made_passive = False
@@ -145,6 +151,17 @@ class Cell(InjectableMixin, PlottableMixin):
145
151
  neuron.h.pop_section() # Undoing soma push
146
152
  self.sonata_proxy: Optional[SonataProxy] = None
147
153
 
154
+ # Persistent objects, like clamps, that exist as long
155
+ # as the object exists
156
+ self.persistent: list[HocObjectType] = []
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
+
148
165
  @property
149
166
  def somatic(self) -> list[NeuronSection]:
150
167
  return list(public_hoc_cell(self.cell).somatic)
@@ -162,8 +179,8 @@ class Cell(InjectableMixin, PlottableMixin):
162
179
  return list(public_hoc_cell(self.cell).axonal)
163
180
 
164
181
  @property
165
- def all(self) -> list[NeuronSection]:
166
- return list(public_hoc_cell(self.cell).all)
182
+ def sections(self) -> SectionMapping:
183
+ return self._extract_sections(public_hoc_cell(self.cell).all)
167
184
 
168
185
  def __repr__(self) -> str:
169
186
  base_info = f"Cell Object: {super().__repr__()}"
@@ -174,29 +191,10 @@ class Cell(InjectableMixin, PlottableMixin):
174
191
  """Connect this cell to a circuit via sonata proxy."""
175
192
  self.sonata_proxy = sonata_proxy
176
193
 
177
- def re_init_rng(self, use_random123_stochkv: bool = False) -> None:
194
+ def re_init_rng(self) -> None:
178
195
  """Reinitialize the random number generator for stochastic channels."""
179
-
180
196
  if not self.is_made_passive:
181
- if use_random123_stochkv:
182
- channel_id = 0
183
- for section in self.somatic:
184
- for seg in section:
185
- neuron.h.setdata_StochKv(seg.x, sec=section)
186
- neuron.h.setRNG_StochKv(channel_id, self.cell_id.id)
187
- channel_id += 1
188
- for section in self.basal:
189
- for seg in section:
190
- neuron.h.setdata_StochKv(seg.x, sec=section)
191
- neuron.h.setRNG_StochKv(channel_id, self.cell_id.id)
192
- channel_id += 1
193
- for section in self.apical:
194
- for seg in section:
195
- neuron.h.setdata_StochKv(seg.x, sec=section)
196
- neuron.h.setRNG_StochKv(channel_id, self.cell_id.id)
197
- channel_id += 1
198
- else:
199
- self.cell.re_init_rng()
197
+ self.cell.re_init_rng()
200
198
 
201
199
  def get_psection(self, section_id: int | str) -> PSection:
202
200
  """Return a python section with the specified section id."""
@@ -211,7 +209,7 @@ class Cell(InjectableMixin, PlottableMixin):
211
209
 
212
210
  def make_passive(self) -> None:
213
211
  """Make the cell passive by deactivating all the active channels."""
214
- for section in self.all:
212
+ for section in self.sections.values():
215
213
  mech_names = set()
216
214
  for seg in section:
217
215
  for mech in seg:
@@ -246,14 +244,14 @@ class Cell(InjectableMixin, PlottableMixin):
246
244
 
247
245
  def _default_enable_ttx(self) -> None:
248
246
  """Default enable_ttx implementation."""
249
- for section in self.all:
247
+ for section in self.sections.values():
250
248
  if not neuron.h.ismembrane("TTXDynamicsSwitch"):
251
249
  section.insert('TTXDynamicsSwitch')
252
250
  section.ttxo_level_TTXDynamicsSwitch = 1.0
253
251
 
254
252
  def _default_disable_ttx(self) -> None:
255
253
  """Default disable_ttx implementation."""
256
- for section in self.all:
254
+ for section in self.sections.values():
257
255
  if not neuron.h.ismembrane("TTXDynamicsSwitch"):
258
256
  section.insert('TTXDynamicsSwitch')
259
257
  section.ttxo_level_TTXDynamicsSwitch = 1e-14
@@ -261,7 +259,7 @@ class Cell(InjectableMixin, PlottableMixin):
261
259
  def area(self) -> float:
262
260
  """The total surface area of the cell."""
263
261
  area = 0.0
264
- for section in self.all:
262
+ for section in self.sections.values():
265
263
  x_s = np.arange(1.0 / (2 * section.nseg), 1.0,
266
264
  1.0 / (section.nseg))
267
265
  for x in x_s:
@@ -311,7 +309,7 @@ class Cell(InjectableMixin, PlottableMixin):
311
309
  self.add_recording("self.axonal[1](0.5)._ref_v", dt=dt)
312
310
 
313
311
  def add_voltage_recording(
314
- 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
315
313
  ) -> None:
316
314
  """Add a voltage recording to a certain section at a given segment
317
315
  (segx).
@@ -323,11 +321,13 @@ class Cell(InjectableMixin, PlottableMixin):
323
321
  dt: Recording time step. If not provided, the recording step will
324
322
  default to the simulator's time step.
325
323
  """
326
- 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)
327
327
  self.add_recording(var_name, dt)
328
328
 
329
329
  def get_voltage_recording(
330
- self, section: "neuron.h.Section", segx: float = 0.5
330
+ self, section: Optional[NeuronSection] = None, segx: float = 0.5
331
331
  ) -> np.ndarray:
332
332
  """Get a voltage recording for a certain section at a given segment
333
333
  (segx).
@@ -343,7 +343,9 @@ class Cell(InjectableMixin, PlottableMixin):
343
343
  Raises:
344
344
  BluecellulabError: If voltage recording was not added previously using add_voltage_recording.
345
345
  """
346
- 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)
347
349
  if recording_name in self.recordings:
348
350
  return self.get_recording(recording_name)
349
351
  else:
@@ -354,15 +356,13 @@ class Cell(InjectableMixin, PlottableMixin):
354
356
 
355
357
  def add_allsections_voltagerecordings(self):
356
358
  """Add a voltage recording to every section of the cell."""
357
- all_sections = public_hoc_cell(self.cell).all
358
- for section in all_sections:
359
+ for section in self.sections.values():
359
360
  self.add_voltage_recording(section, dt=self.record_dt)
360
361
 
361
362
  def get_allsections_voltagerecordings(self) -> dict[str, np.ndarray]:
362
363
  """Get all the voltage recordings from all the sections."""
363
364
  all_section_voltages = {}
364
- all_sections = public_hoc_cell(self.cell).all
365
- for section in all_sections:
365
+ for section in self.sections.values():
366
366
  recording = self.get_voltage_recording(section)
367
367
  all_section_voltages[section.name()] = recording
368
368
  return all_section_voltages
@@ -440,10 +440,10 @@ class Cell(InjectableMixin, PlottableMixin):
440
440
  """
441
441
  if location == "soma":
442
442
  sec = public_hoc_cell(self.cell).soma[0]
443
- source = public_hoc_cell(self.cell).soma[0](1)._ref_v
443
+ source = sec(1)._ref_v
444
444
  elif location == "AIS":
445
445
  sec = public_hoc_cell(self.cell).axon[1]
446
- source = public_hoc_cell(self.cell).axon[1](0.5)._ref_v
446
+ source = sec(0.5)._ref_v
447
447
  else:
448
448
  raise ValueError("Spike detection location must be soma or AIS")
449
449
  netcon = neuron.h.NetCon(source, target, sec=sec)
@@ -486,7 +486,6 @@ class Cell(InjectableMixin, PlottableMixin):
486
486
 
487
487
  sid = synapse_id[1]
488
488
 
489
- base_seed = self.rng_settings.base_seed
490
489
  weight = syn_description[SynapseProperty.G_SYNX]
491
490
  # numpy int to int
492
491
  post_sec_id = int(syn_description[SynapseProperty.POST_SECTION_ID])
@@ -526,9 +525,10 @@ class Cell(InjectableMixin, PlottableMixin):
526
525
  # NC_SPONTMINI
527
526
  self.syn_mini_netcons[synapse_id].weight[nc_type_param] = 1
528
527
 
529
- if self.rng_settings.mode == 'Random123':
528
+ rng_settings = RNGSettings.get_instance()
529
+ if rng_settings.mode == 'Random123':
530
530
  seed2 = source_popid * 65536 + target_popid \
531
- + self.rng_settings.minis_seed
531
+ + rng_settings.minis_seed
532
532
  self.ips[synapse_id].setRNGs(
533
533
  sid + 200,
534
534
  self.cell_id.id + 250,
@@ -543,25 +543,26 @@ class Cell(InjectableMixin, PlottableMixin):
543
543
  uniformrng = neuron.h.Random()
544
544
  self.persistent.append(uniformrng)
545
545
 
546
- if self.rng_settings.mode == 'Compatibility':
546
+ base_seed = rng_settings.base_seed
547
+ if rng_settings.mode == 'Compatibility':
547
548
  exp_seed1 = sid * 100000 + 200
548
549
  exp_seed2 = self.cell_id.id + 250 + base_seed + \
549
- self.rng_settings.minis_seed
550
+ rng_settings.minis_seed
550
551
  uniform_seed1 = sid * 100000 + 300
551
552
  uniform_seed2 = self.cell_id.id + 250 + base_seed + \
552
- self.rng_settings.minis_seed
553
- elif self.rng_settings.mode == "UpdatedMCell":
553
+ rng_settings.minis_seed
554
+ elif rng_settings.mode == "UpdatedMCell":
554
555
  exp_seed1 = sid * 1000 + 200
555
556
  exp_seed2 = source_popid * 16777216 + self.cell_id.id + 250 + \
556
557
  base_seed + \
557
- self.rng_settings.minis_seed
558
+ rng_settings.minis_seed
558
559
  uniform_seed1 = sid * 1000 + 300
559
560
  uniform_seed2 = source_popid * 16777216 + self.cell_id.id + 250 \
560
561
  + base_seed + \
561
- self.rng_settings.minis_seed
562
+ rng_settings.minis_seed
562
563
  else:
563
564
  raise ValueError(
564
- f"Cell: Unknown rng mode: {self.rng_settings.mode}")
565
+ f"Cell: Unknown rng mode: {rng_settings.mode}")
565
566
 
566
567
  exprng.MCellRan4(exp_seed1, exp_seed2)
567
568
  exprng.negexp(1.0)
@@ -695,9 +696,10 @@ class Cell(InjectableMixin, PlottableMixin):
695
696
  """Get a vector of AIS voltage."""
696
697
  return self.get_recording('self.axonal[1](0.5)._ref_v')
697
698
 
698
- def getNumberOfSegments(self) -> int:
699
+ @property
700
+ def n_segments(self) -> int:
699
701
  """Get the number of segments in the cell."""
700
- return sum(section.nseg for section in self.all)
702
+ return sum(section.nseg for section in self.sections.values())
701
703
 
702
704
  def add_synapse_replay(
703
705
  self, stimulus: SynapseReplay, spike_threshold: float, spike_location: str
@@ -27,6 +27,7 @@ from bluecellulab.cell.stimuli_generator import (
27
27
  get_relative_shotnoise_params,
28
28
  )
29
29
  from bluecellulab.exceptions import BluecellulabError
30
+ from bluecellulab.rngsettings import RNGSettings
30
31
  from bluecellulab.stimulus.circuit_stimulus_definitions import (
31
32
  ClampMode,
32
33
  Hyperpolarizing,
@@ -191,20 +192,21 @@ class InjectableMixin:
191
192
 
192
193
  def _get_noise_step_rand(self, noisestim_count):
193
194
  """Return rng for noise step stimulus."""
194
- if self.rng_settings.mode == "Compatibility":
195
+ rng_settings = RNGSettings.get_instance()
196
+ if rng_settings.mode == "Compatibility":
195
197
  rng = neuron.h.Random(self.cell_id.id + noisestim_count)
196
- elif self.rng_settings.mode == "UpdatedMCell":
198
+ elif rng_settings.mode == "UpdatedMCell":
197
199
  rng = neuron.h.Random()
198
200
  rng.MCellRan4(
199
201
  noisestim_count * 10000 + 100,
200
- self.rng_settings.base_seed +
201
- self.rng_settings.stimulus_seed +
202
+ rng_settings.base_seed +
203
+ rng_settings.stimulus_seed +
202
204
  self.cell_id.id * 1000)
203
- elif self.rng_settings.mode == "Random123":
205
+ elif rng_settings.mode == "Random123":
204
206
  rng = neuron.h.Random()
205
207
  rng.Random123(
206
208
  noisestim_count + 100,
207
- self.rng_settings.stimulus_seed + 500,
209
+ rng_settings.stimulus_seed + 500,
208
210
  self.cell_id.id + 300)
209
211
 
210
212
  self.persistent.append(rng)
@@ -268,9 +270,10 @@ class InjectableMixin:
268
270
 
269
271
  def _get_ornstein_uhlenbeck_rand(self, stim_count, seed):
270
272
  """Return rng for ornstein_uhlenbeck simulation."""
271
- if self.rng_settings.mode == "Random123":
273
+ rng_settings = RNGSettings.get_instance()
274
+ if rng_settings.mode == "Random123":
272
275
  seed1 = stim_count + 2997 # stimulus block
273
- seed2 = self.rng_settings.stimulus_seed + 291204 # stimulus type
276
+ seed2 = rng_settings.stimulus_seed + 291204 # stimulus type
274
277
  seed3 = self.cell_id.id + 123 if seed is None else seed # GID
275
278
  logger.debug("Using ornstein_uhlenbeck process seeds %d %d %d" %
276
279
  (seed1, seed2, seed3))
@@ -284,9 +287,10 @@ class InjectableMixin:
284
287
 
285
288
  def _get_shotnoise_step_rand(self, shotnoise_stim_count, seed=None):
286
289
  """Return rng for shot noise step stimulus."""
287
- if self.rng_settings.mode == "Random123":
290
+ rng_settings = RNGSettings.get_instance()
291
+ if rng_settings.mode == "Random123":
288
292
  seed1 = shotnoise_stim_count + 2997
289
- seed2 = self.rng_settings.stimulus_seed + 19216
293
+ seed2 = rng_settings.stimulus_seed + 19216
290
294
  seed3 = self.cell_id.id + 123 if seed is None else seed
291
295
  logger.debug("Using shot noise seeds %d %d %d" %
292
296
  (seed1, seed2, seed3))
@@ -439,14 +443,14 @@ class InjectableMixin:
439
443
  time_vector = neuron.h.Vector().from_python(t_content)
440
444
  current_vector = neuron.h.Vector().from_python(i_content)
441
445
 
442
- pulse = neuron.h.IClamp(segx, sec=section)
443
- 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])
444
448
 
445
- pulse.delay = t_content[0]
446
- pulse.dur = t_content[-1] - t_content[0]
447
- 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)
448
452
 
449
- return current_vector
453
+ return iclamp, current_vector
450
454
 
451
455
  @deprecated("Use add_sin_current instead.")
452
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"