bluecellulab 2.3.7__py3-none-any.whl → 2.4.1__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
@@ -9,6 +9,7 @@ except ImportError:
9
9
 
10
10
  from .importer import * # NOQA
11
11
  from .tools import * # NOQA
12
+ from .verbosity import *
12
13
  from .cell import Cell, create_ball_stick # NOQA
13
14
  from .connection import Connection # NOQA
14
15
  from .plotwindow import PlotWindow # NOQA
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,12 +27,13 @@ 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
@@ -44,7 +45,7 @@ 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,6 +55,24 @@ class Cell(InjectableMixin, PlottableMixin):
54
55
 
55
56
  last_id = 0
56
57
 
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
+
57
76
  @load_hoc_and_mod_files
58
77
  def __init__(self,
59
78
  template_path: str | Path,
@@ -61,48 +80,52 @@ class Cell(InjectableMixin, PlottableMixin):
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__()}"
@@ -211,7 +228,7 @@ class Cell(InjectableMixin, PlottableMixin):
211
228
 
212
229
  def make_passive(self) -> None:
213
230
  """Make the cell passive by deactivating all the active channels."""
214
- for section in self.all:
231
+ for section in self.sections.values():
215
232
  mech_names = set()
216
233
  for seg in section:
217
234
  for mech in seg:
@@ -246,14 +263,14 @@ class Cell(InjectableMixin, PlottableMixin):
246
263
 
247
264
  def _default_enable_ttx(self) -> None:
248
265
  """Default enable_ttx implementation."""
249
- for section in self.all:
266
+ for section in self.sections.values():
250
267
  if not neuron.h.ismembrane("TTXDynamicsSwitch"):
251
268
  section.insert('TTXDynamicsSwitch')
252
269
  section.ttxo_level_TTXDynamicsSwitch = 1.0
253
270
 
254
271
  def _default_disable_ttx(self) -> None:
255
272
  """Default disable_ttx implementation."""
256
- for section in self.all:
273
+ for section in self.sections.values():
257
274
  if not neuron.h.ismembrane("TTXDynamicsSwitch"):
258
275
  section.insert('TTXDynamicsSwitch')
259
276
  section.ttxo_level_TTXDynamicsSwitch = 1e-14
@@ -261,7 +278,7 @@ class Cell(InjectableMixin, PlottableMixin):
261
278
  def area(self) -> float:
262
279
  """The total surface area of the cell."""
263
280
  area = 0.0
264
- for section in self.all:
281
+ for section in self.sections.values():
265
282
  x_s = np.arange(1.0 / (2 * section.nseg), 1.0,
266
283
  1.0 / (section.nseg))
267
284
  for x in x_s:
@@ -311,7 +328,7 @@ class Cell(InjectableMixin, PlottableMixin):
311
328
  self.add_recording("self.axonal[1](0.5)._ref_v", dt=dt)
312
329
 
313
330
  def add_voltage_recording(
314
- self, section: "neuron.h.Section", segx: float = 0.5, dt: Optional[float] = None
331
+ self, section: Optional[NeuronSection] = None, segx: float = 0.5, dt: Optional[float] = None
315
332
  ) -> None:
316
333
  """Add a voltage recording to a certain section at a given segment
317
334
  (segx).
@@ -323,11 +340,13 @@ class Cell(InjectableMixin, PlottableMixin):
323
340
  dt: Recording time step. If not provided, the recording step will
324
341
  default to the simulator's time step.
325
342
  """
326
- var_name = f"neuron.h.{section.name()}({segx})._ref_v"
343
+ if section is None:
344
+ section = self.soma
345
+ var_name = section_to_voltage_recording_str(section, segx)
327
346
  self.add_recording(var_name, dt)
328
347
 
329
348
  def get_voltage_recording(
330
- self, section: "neuron.h.Section", segx: float = 0.5
349
+ self, section: Optional[NeuronSection] = None, segx: float = 0.5
331
350
  ) -> np.ndarray:
332
351
  """Get a voltage recording for a certain section at a given segment
333
352
  (segx).
@@ -343,7 +362,9 @@ class Cell(InjectableMixin, PlottableMixin):
343
362
  Raises:
344
363
  BluecellulabError: If voltage recording was not added previously using add_voltage_recording.
345
364
  """
346
- recording_name = f"neuron.h.{section.name()}({segx})._ref_v"
365
+ if section is None:
366
+ section = self.soma
367
+ recording_name = section_to_voltage_recording_str(section, segx)
347
368
  if recording_name in self.recordings:
348
369
  return self.get_recording(recording_name)
349
370
  else:
@@ -354,15 +375,13 @@ class Cell(InjectableMixin, PlottableMixin):
354
375
 
355
376
  def add_allsections_voltagerecordings(self):
356
377
  """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:
378
+ for section in self.sections.values():
359
379
  self.add_voltage_recording(section, dt=self.record_dt)
360
380
 
361
381
  def get_allsections_voltagerecordings(self) -> dict[str, np.ndarray]:
362
382
  """Get all the voltage recordings from all the sections."""
363
383
  all_section_voltages = {}
364
- all_sections = public_hoc_cell(self.cell).all
365
- for section in all_sections:
384
+ for section in self.sections.values():
366
385
  recording = self.get_voltage_recording(section)
367
386
  all_section_voltages[section.name()] = recording
368
387
  return all_section_voltages
@@ -440,10 +459,10 @@ class Cell(InjectableMixin, PlottableMixin):
440
459
  """
441
460
  if location == "soma":
442
461
  sec = public_hoc_cell(self.cell).soma[0]
443
- source = public_hoc_cell(self.cell).soma[0](1)._ref_v
462
+ source = sec(1)._ref_v
444
463
  elif location == "AIS":
445
464
  sec = public_hoc_cell(self.cell).axon[1]
446
- source = public_hoc_cell(self.cell).axon[1](0.5)._ref_v
465
+ source = sec(0.5)._ref_v
447
466
  else:
448
467
  raise ValueError("Spike detection location must be soma or AIS")
449
468
  netcon = neuron.h.NetCon(source, target, sec=sec)
@@ -486,7 +505,6 @@ class Cell(InjectableMixin, PlottableMixin):
486
505
 
487
506
  sid = synapse_id[1]
488
507
 
489
- base_seed = self.rng_settings.base_seed
490
508
  weight = syn_description[SynapseProperty.G_SYNX]
491
509
  # numpy int to int
492
510
  post_sec_id = int(syn_description[SynapseProperty.POST_SECTION_ID])
@@ -526,9 +544,10 @@ class Cell(InjectableMixin, PlottableMixin):
526
544
  # NC_SPONTMINI
527
545
  self.syn_mini_netcons[synapse_id].weight[nc_type_param] = 1
528
546
 
529
- if self.rng_settings.mode == 'Random123':
547
+ rng_settings = RNGSettings.get_instance()
548
+ if rng_settings.mode == 'Random123':
530
549
  seed2 = source_popid * 65536 + target_popid \
531
- + self.rng_settings.minis_seed
550
+ + rng_settings.minis_seed
532
551
  self.ips[synapse_id].setRNGs(
533
552
  sid + 200,
534
553
  self.cell_id.id + 250,
@@ -543,25 +562,26 @@ class Cell(InjectableMixin, PlottableMixin):
543
562
  uniformrng = neuron.h.Random()
544
563
  self.persistent.append(uniformrng)
545
564
 
546
- if self.rng_settings.mode == 'Compatibility':
565
+ base_seed = rng_settings.base_seed
566
+ if rng_settings.mode == 'Compatibility':
547
567
  exp_seed1 = sid * 100000 + 200
548
568
  exp_seed2 = self.cell_id.id + 250 + base_seed + \
549
- self.rng_settings.minis_seed
569
+ rng_settings.minis_seed
550
570
  uniform_seed1 = sid * 100000 + 300
551
571
  uniform_seed2 = self.cell_id.id + 250 + base_seed + \
552
- self.rng_settings.minis_seed
553
- elif self.rng_settings.mode == "UpdatedMCell":
572
+ rng_settings.minis_seed
573
+ elif rng_settings.mode == "UpdatedMCell":
554
574
  exp_seed1 = sid * 1000 + 200
555
575
  exp_seed2 = source_popid * 16777216 + self.cell_id.id + 250 + \
556
576
  base_seed + \
557
- self.rng_settings.minis_seed
577
+ rng_settings.minis_seed
558
578
  uniform_seed1 = sid * 1000 + 300
559
579
  uniform_seed2 = source_popid * 16777216 + self.cell_id.id + 250 \
560
580
  + base_seed + \
561
- self.rng_settings.minis_seed
581
+ rng_settings.minis_seed
562
582
  else:
563
583
  raise ValueError(
564
- f"Cell: Unknown rng mode: {self.rng_settings.mode}")
584
+ f"Cell: Unknown rng mode: {rng_settings.mode}")
565
585
 
566
586
  exprng.MCellRan4(exp_seed1, exp_seed2)
567
587
  exprng.negexp(1.0)
@@ -695,9 +715,10 @@ class Cell(InjectableMixin, PlottableMixin):
695
715
  """Get a vector of AIS voltage."""
696
716
  return self.get_recording('self.axonal[1](0.5)._ref_v')
697
717
 
698
- def getNumberOfSegments(self) -> int:
718
+ @property
719
+ def n_segments(self) -> int:
699
720
  """Get the number of segments in the cell."""
700
- return sum(section.nseg for section in self.all)
721
+ return sum(section.nseg for section in self.sections.values())
701
722
 
702
723
  def add_synapse_replay(
703
724
  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"