bluecellulab 2.6.43__tar.gz → 2.6.45__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 bluecellulab might be problematic. Click here for more details.

Files changed (106) hide show
  1. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/PKG-INFO +1 -1
  2. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/cell/injector.py +36 -5
  3. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/circuit/circuit_access/sonata_circuit_access.py +2 -1
  4. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/circuit_simulation.py +29 -3
  5. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/stimulus/circuit_stimulus_definitions.py +37 -0
  6. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/stimulus/factory.py +67 -1
  7. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/stimulus/stimulus.py +103 -5
  8. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab.egg-info/PKG-INFO +1 -1
  9. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/.compile_mod.sh +0 -0
  10. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/.gitattributes +0 -0
  11. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/.github/dependabot.yml +0 -0
  12. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/.github/workflows/release.yml +0 -0
  13. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/.github/workflows/test.yml +0 -0
  14. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/.gitignore +0 -0
  15. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/.gitlab-ci.yml +0 -0
  16. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/.readthedocs.yml +0 -0
  17. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/.zenodo.json +0 -0
  18. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/AUTHORS.txt +0 -0
  19. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/CHANGELOG.rst +0 -0
  20. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/CITATION.cff +0 -0
  21. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/CONTRIBUTING.rst +0 -0
  22. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/LICENSE +0 -0
  23. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/MANIFEST.in +0 -0
  24. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/Makefile +0 -0
  25. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/README.rst +0 -0
  26. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/__init__.py +0 -0
  27. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/analysis/__init__.py +0 -0
  28. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/analysis/analysis.py +0 -0
  29. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/analysis/inject_sequence.py +0 -0
  30. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/analysis/plotting.py +0 -0
  31. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/cell/__init__.py +0 -0
  32. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/cell/ballstick/__init__.py +0 -0
  33. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/cell/ballstick/emodel.hoc +0 -0
  34. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/cell/ballstick/morphology.asc +0 -0
  35. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/cell/cell_dict.py +0 -0
  36. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/cell/core.py +0 -0
  37. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/cell/plotting.py +0 -0
  38. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/cell/random.py +0 -0
  39. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/cell/recording.py +0 -0
  40. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/cell/section_distance.py +0 -0
  41. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/cell/serialized_sections.py +0 -0
  42. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/cell/sonata_proxy.py +0 -0
  43. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/cell/stimuli_generator.py +0 -0
  44. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/cell/template.py +0 -0
  45. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/circuit/__init__.py +0 -0
  46. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/circuit/circuit_access/__init__.py +0 -0
  47. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/circuit/circuit_access/bluepy_circuit_access.py +0 -0
  48. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/circuit/circuit_access/definition.py +0 -0
  49. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/circuit/config/__init__.py +0 -0
  50. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/circuit/config/bluepy_simulation_config.py +0 -0
  51. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/circuit/config/definition.py +0 -0
  52. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/circuit/config/sections.py +0 -0
  53. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/circuit/config/sonata_simulation_config.py +0 -0
  54. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/circuit/format.py +0 -0
  55. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/circuit/iotools.py +0 -0
  56. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/circuit/node_id.py +0 -0
  57. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/circuit/simulation_access.py +0 -0
  58. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/circuit/synapse_properties.py +0 -0
  59. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/circuit/validate.py +0 -0
  60. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/connection.py +0 -0
  61. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/dendrogram.py +0 -0
  62. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/exceptions.py +0 -0
  63. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/graph.py +0 -0
  64. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/hoc/Cell.hoc +0 -0
  65. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/hoc/RNGSettings.hoc +0 -0
  66. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/hoc/TDistFunc.hoc +0 -0
  67. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/hoc/TStim.hoc +0 -0
  68. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/hoc/fileUtils.hoc +0 -0
  69. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/importer.py +0 -0
  70. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/neuron_interpreter.py +0 -0
  71. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/plotwindow.py +0 -0
  72. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/psection.py +0 -0
  73. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/psegment.py +0 -0
  74. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/rngsettings.py +0 -0
  75. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/simulation/__init__.py +0 -0
  76. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/simulation/neuron_globals.py +0 -0
  77. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/simulation/parallel.py +0 -0
  78. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/simulation/simulation.py +0 -0
  79. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/stimulus/__init__.py +0 -0
  80. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/synapse/__init__.py +0 -0
  81. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/synapse/synapse_factory.py +0 -0
  82. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/synapse/synapse_types.py +0 -0
  83. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/tools.py +0 -0
  84. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/type_aliases.py +0 -0
  85. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/utils.py +0 -0
  86. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab/verbosity.py +0 -0
  87. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab.egg-info/SOURCES.txt +0 -0
  88. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab.egg-info/dependency_links.txt +0 -0
  89. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab.egg-info/requires.txt +0 -0
  90. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/bluecellulab.egg-info/top_level.txt +0 -0
  91. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/docs/Makefile +0 -0
  92. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/docs/images/voltage-readme.png +0 -0
  93. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/docs/make.bat +0 -0
  94. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/docs/requirements_docs.txt +0 -0
  95. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/docs/source/_static/.gitkeep +0 -0
  96. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/docs/source/api.rst +0 -0
  97. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/docs/source/changelog.rst +0 -0
  98. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/docs/source/compiling-mechanisms.rst +0 -0
  99. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/docs/source/conf.py +0 -0
  100. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/docs/source/contributing.rst +0 -0
  101. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/docs/source/index.rst +0 -0
  102. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/docs/source/list_of_stim.rst +0 -0
  103. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/docs/source/logo/BlueCelluLabBanner.jpg +0 -0
  104. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/pyproject.toml +0 -0
  105. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/setup.cfg +0 -0
  106. {bluecellulab-2.6.43 → bluecellulab-2.6.45}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: bluecellulab
3
- Version: 2.6.43
3
+ Version: 2.6.45
4
4
  Summary: Biologically detailed neural network simulations and analysis.
5
5
  Author: Blue Brain Project, EPFL
6
6
  License: Apache2.0
@@ -30,6 +30,8 @@ from bluecellulab.exceptions import BluecellulabError
30
30
  from bluecellulab.rngsettings import RNGSettings
31
31
  from bluecellulab.stimulus.circuit_stimulus_definitions import (
32
32
  ClampMode,
33
+ Linear,
34
+ RelativeLinear,
33
35
  Hyperpolarizing,
34
36
  Noise,
35
37
  OrnsteinUhlenbeck,
@@ -259,12 +261,32 @@ class InjectableMixin:
259
261
  self.persistent.append(tstim) # type: ignore
260
262
  return tstim
261
263
 
262
- def add_replay_relativelinear(self, stimulus):
264
+ def add_replay_linear(self, stimulus: Linear):
265
+ """Add a linear stimulus."""
266
+
267
+ return self.add_ramp(
268
+ stimulus.delay,
269
+ stimulus.delay + stimulus.duration,
270
+ stimulus.amp_start,
271
+ stimulus.amp_end
272
+ )
273
+
274
+ def add_replay_relativelinear(self, stimulus: RelativeLinear):
263
275
  """Add a relative linear stimulus."""
264
- tstim = neuron.h.TStim(0.5, sec=self.soma)
265
- amp = stimulus.percent_start / 100.0 * self.threshold
266
- tstim.pulse(stimulus.delay, stimulus.duration, amp)
267
- self.persistent.append(tstim)
276
+ tstim = neuron.h.TStim(0.5, sec=self.soma) # type: ignore
277
+ amp_start = stimulus.percent_start / 100.0 * self.threshold # type: ignore
278
+ amp_end = stimulus.percent_end / 100.0 * self.threshold # type: ignore
279
+
280
+ tstim.ramp(
281
+ 0.0,
282
+ stimulus.delay, # Time when the ramp starts
283
+ amp_start, # Initial amplitude (amp_start)
284
+ amp_end, # Final amplitude (amp_end)
285
+ stimulus.duration, # Duration of the ramp
286
+ 0.0,
287
+ 0.0
288
+ )
289
+ self.persistent.append(tstim) # type: ignore
268
290
 
269
291
  return tstim
270
292
 
@@ -493,3 +515,12 @@ class InjectableMixin:
493
515
  syn.e = e
494
516
  self.persistent.append(syn) # type: ignore
495
517
  return syn
518
+
519
+ def add_sinusoidal(self, stimulus) -> TStim:
520
+ """Inject sinusoidal stimulus for replay."""
521
+ return self.add_sin_current(
522
+ stimulus.amp_start,
523
+ stimulus.delay,
524
+ stimulus.duration,
525
+ stimulus.frequency,
526
+ )
@@ -152,8 +152,9 @@ class SonataCircuitAccess:
152
152
 
153
153
  # make multiindex
154
154
  synapses = synapses.reset_index(drop=True)
155
+ synapse_ids = list(synapses.index)
155
156
  synapses.index = pd.MultiIndex.from_tuples(
156
- zip([edge_population_name] * len(synapses), synapses.index),
157
+ [(edge_population_name, syn_id) for syn_id in synapse_ids],
157
158
  names=["edge_name", "synapse_id"],
158
159
  )
159
160
 
@@ -139,6 +139,8 @@ class CircuitSimulation:
139
139
  pre_spike_trains: None | dict[tuple[str, int], Iterable] | dict[int, Iterable] = None,
140
140
  add_shotnoise_stimuli: bool = False,
141
141
  add_ornstein_uhlenbeck_stimuli: bool = False,
142
+ add_sinusoidal_stimuli: bool = False,
143
+ add_linear_stimuli: bool = False,
142
144
  ):
143
145
  """Instantiate a list of cells.
144
146
 
@@ -209,6 +211,16 @@ class CircuitSimulation:
209
211
  of the simulation config,
210
212
  Setting add_stimuli=True,
211
213
  will automatically set this option to True.
214
+ add_sinusoidal_stimuli : Process the 'sinusoidal' stimuli
215
+ blocks of the simulation config.
216
+ Setting add_stimuli=True,
217
+ will automatically set this option to
218
+ True.
219
+ add_linear_stimuli : Process the 'linear' stimuli
220
+ blocks of the simulation config.
221
+ Setting add_stimuli=True,
222
+ will automatically set this option to
223
+ True.
212
224
  """
213
225
  if not isinstance(cells, Iterable) or isinstance(cells, tuple):
214
226
  cells = [cells]
@@ -265,22 +277,28 @@ class CircuitSimulation:
265
277
  add_hyperpolarizing_stimuli = True
266
278
  add_relativelinear_stimuli = True
267
279
  add_pulse_stimuli = True
280
+ add_sinusoidal_stimuli = True
268
281
  add_shotnoise_stimuli = True
269
282
  add_ornstein_uhlenbeck_stimuli = True
283
+ add_linear_stimuli = True
270
284
 
271
285
  if add_noise_stimuli or \
272
286
  add_hyperpolarizing_stimuli or \
273
287
  add_pulse_stimuli or \
274
288
  add_relativelinear_stimuli or \
275
289
  add_shotnoise_stimuli or \
276
- add_ornstein_uhlenbeck_stimuli:
290
+ add_ornstein_uhlenbeck_stimuli or \
291
+ add_sinusoidal_stimuli or \
292
+ add_linear_stimuli:
277
293
  self._add_stimuli(
278
294
  add_noise_stimuli=add_noise_stimuli,
279
295
  add_hyperpolarizing_stimuli=add_hyperpolarizing_stimuli,
280
296
  add_relativelinear_stimuli=add_relativelinear_stimuli,
281
297
  add_pulse_stimuli=add_pulse_stimuli,
282
298
  add_shotnoise_stimuli=add_shotnoise_stimuli,
283
- add_ornstein_uhlenbeck_stimuli=add_ornstein_uhlenbeck_stimuli
299
+ add_ornstein_uhlenbeck_stimuli=add_ornstein_uhlenbeck_stimuli,
300
+ add_sinusoidal_stimuli=add_sinusoidal_stimuli,
301
+ add_linear_stimuli=add_linear_stimuli
284
302
  )
285
303
 
286
304
  def _add_stimuli(self, add_noise_stimuli=False,
@@ -288,7 +306,9 @@ class CircuitSimulation:
288
306
  add_relativelinear_stimuli=False,
289
307
  add_pulse_stimuli=False,
290
308
  add_shotnoise_stimuli=False,
291
- add_ornstein_uhlenbeck_stimuli=False
309
+ add_ornstein_uhlenbeck_stimuli=False,
310
+ add_sinusoidal_stimuli=False,
311
+ add_linear_stimuli=False
292
312
  ):
293
313
  """Instantiate all the stimuli."""
294
314
  stimuli_entries = self.circuit_access.config.get_all_stimuli_entries()
@@ -316,6 +336,9 @@ class CircuitSimulation:
316
336
  elif isinstance(stimulus, circuit_stimulus_definitions.Pulse):
317
337
  if add_pulse_stimuli:
318
338
  self.cells[cell_id].add_pulse(stimulus)
339
+ elif isinstance(stimulus, circuit_stimulus_definitions.Linear):
340
+ if add_linear_stimuli:
341
+ self.cells[cell_id].add_replay_linear(stimulus)
319
342
  elif isinstance(stimulus, circuit_stimulus_definitions.RelativeLinear):
320
343
  if add_relativelinear_stimuli:
321
344
  self.cells[cell_id].add_replay_relativelinear(stimulus)
@@ -339,6 +362,9 @@ class CircuitSimulation:
339
362
  self.cells[cell_id].add_relative_ornstein_uhlenbeck(
340
363
  self.cells[cell_id].soma, 0.5, stimulus,
341
364
  stim_count=ornstein_uhlenbeck_stim_count)
365
+ elif isinstance(stimulus, circuit_stimulus_definitions.Sinusoidal):
366
+ if add_sinusoidal_stimuli:
367
+ self.cells[cell_id].add_sinusoidal(stimulus)
342
368
  elif isinstance(stimulus, circuit_stimulus_definitions.SynapseReplay): # sonata only
343
369
  if self.circuit_access.target_contains_cell(
344
370
  stimulus.target, cell_id
@@ -42,12 +42,14 @@ class Pattern(Enum):
42
42
  NOISE = "noise"
43
43
  HYPERPOLARIZING = "hyperpolarizing"
44
44
  PULSE = "pulse"
45
+ LINEAR = "linear"
45
46
  RELATIVE_LINEAR = "relative_linear"
46
47
  SYNAPSE_REPLAY = "synapse_replay"
47
48
  SHOT_NOISE = "shot_noise"
48
49
  RELATIVE_SHOT_NOISE = "relative_shot_noise"
49
50
  ORNSTEIN_UHLENBECK = "ornstein_uhlenbeck"
50
51
  RELATIVE_ORNSTEIN_UHLENBECK = "relative_ornstein_uhlenbeck"
52
+ SINUSOIDAL = "sinusoidal"
51
53
 
52
54
  @classmethod
53
55
  def from_blueconfig(cls, pattern: str) -> Pattern:
@@ -80,6 +82,8 @@ class Pattern(Enum):
80
82
  return Pattern.HYPERPOLARIZING
81
83
  elif pattern == "pulse":
82
84
  return Pattern.PULSE
85
+ elif pattern == "linear":
86
+ return Pattern.LINEAR
83
87
  elif pattern == "relative_linear":
84
88
  return Pattern.RELATIVE_LINEAR
85
89
  elif pattern == "synapse_replay":
@@ -92,6 +96,8 @@ class Pattern(Enum):
92
96
  return Pattern.ORNSTEIN_UHLENBECK
93
97
  elif pattern == "relative_ornstein_uhlenbeck":
94
98
  return Pattern.RELATIVE_ORNSTEIN_UHLENBECK
99
+ elif pattern == "sinusoidal":
100
+ return Pattern.SINUSOIDAL
95
101
  else:
96
102
  raise ValueError(f"Unknown pattern {pattern}")
97
103
 
@@ -141,6 +147,7 @@ class Stimulus:
141
147
  delay=stimulus_entry["Delay"],
142
148
  duration=stimulus_entry["Duration"],
143
149
  percent_start=stimulus_entry["PercentStart"],
150
+ percent_end=stimulus_entry["PercentEnd"],
144
151
  )
145
152
  elif pattern == Pattern.SYNAPSE_REPLAY:
146
153
  warnings.warn("Ignoring syanpse replay stimulus as it is not supported")
@@ -230,12 +237,21 @@ class Stimulus:
230
237
  width=stimulus_entry["width"],
231
238
  frequency=stimulus_entry["frequency"],
232
239
  )
240
+ elif pattern == Pattern.LINEAR:
241
+ return Linear(
242
+ target=stimulus_entry["node_set"],
243
+ delay=stimulus_entry["delay"],
244
+ duration=stimulus_entry["duration"],
245
+ amp_start=stimulus_entry["amp_start"],
246
+ amp_end=stimulus_entry["amp_end"],
247
+ )
233
248
  elif pattern == Pattern.RELATIVE_LINEAR:
234
249
  return RelativeLinear(
235
250
  target=stimulus_entry["node_set"],
236
251
  delay=stimulus_entry["delay"],
237
252
  duration=stimulus_entry["duration"],
238
253
  percent_start=stimulus_entry["percent_start"],
254
+ percent_end=stimulus_entry["percent_end"],
239
255
  )
240
256
  elif pattern == Pattern.SYNAPSE_REPLAY:
241
257
  return SynapseReplay(
@@ -300,6 +316,14 @@ class Stimulus:
300
316
  mode=ClampMode(stimulus_entry.get("input_type", "current_clamp").lower()),
301
317
  reversal=stimulus_entry.get("reversal", 0.0)
302
318
  )
319
+ elif pattern == Pattern.SINUSOIDAL:
320
+ return Sinusoidal(
321
+ target=stimulus_entry["node_set"],
322
+ delay=stimulus_entry["delay"],
323
+ duration=stimulus_entry["duration"],
324
+ amp_start=stimulus_entry["amp_start"],
325
+ frequency=stimulus_entry["frequency"],
326
+ )
303
327
  else:
304
328
  raise ValueError(f"Unknown pattern {pattern}")
305
329
 
@@ -322,9 +346,16 @@ class Pulse(Stimulus):
322
346
  frequency: float
323
347
 
324
348
 
349
+ @dataclass(frozen=True, config=dict(extra="forbid"))
350
+ class Linear(Stimulus):
351
+ amp_start: float
352
+ amp_end: float
353
+
354
+
325
355
  @dataclass(frozen=True, config=dict(extra="forbid"))
326
356
  class RelativeLinear(Stimulus):
327
357
  percent_start: float
358
+ percent_end: float
328
359
 
329
360
 
330
361
  @dataclass(frozen=True, config=dict(extra="forbid"))
@@ -416,3 +447,9 @@ class RelativeOrnsteinUhlenbeck(Stimulus):
416
447
  seed: Optional[int] = None
417
448
  mode: ClampMode = ClampMode.CURRENT
418
449
  reversal: float = 0.0
450
+
451
+
452
+ @dataclass(frozen=True, config=dict(extra="forbid"))
453
+ class Sinusoidal(Stimulus):
454
+ amp_start: float
455
+ frequency: float
@@ -16,7 +16,7 @@
16
16
  from __future__ import annotations
17
17
  from typing import Optional
18
18
  import logging
19
- from bluecellulab.stimulus.stimulus import DelayedZap, Empty, Ramp, Slope, Step, StepNoise, Stimulus, OrnsteinUhlenbeck, ShotNoise
19
+ from bluecellulab.stimulus.stimulus import DelayedZap, Empty, Ramp, Slope, Step, StepNoise, Stimulus, OrnsteinUhlenbeck, ShotNoise, Sinusoidal
20
20
  from bluecellulab.stimulus.circuit_stimulus_definitions import Stimulus as CircuitStimulus
21
21
 
22
22
  logger = logging.getLogger(__name__)
@@ -376,6 +376,72 @@ class StimulusFactory:
376
376
 
377
377
  raise TypeError("You have to give either threshold_current or amplitude")
378
378
 
379
+ def sinusoidal(
380
+ self,
381
+ pre_delay: float,
382
+ post_delay: float,
383
+ duration: float,
384
+ frequency: float,
385
+ amplitude: Optional[float] = None,
386
+ amplitude_percent: Optional[float] = None,
387
+ threshold_current: Optional[float] = None,
388
+ dt: float = 0.025,
389
+ ) -> Stimulus:
390
+ """Creates a Sinusoidal stimulus (factory-compatible).
391
+
392
+ Args:
393
+ pre_delay: Delay before the sinusoidal stimulus starts (ms).
394
+ post_delay: Delay after the stimulus ends (ms).
395
+ duration: Duration of the stimulus (ms).
396
+ frequency: Frequency of oscillation (Hz).
397
+ amplitude: Absolute amplitude (nA). Used if provided.
398
+ amplitude_percent: Amplitude as a percentage of threshold current.
399
+ threshold_current: Reference threshold current for percentage-based calculation.
400
+ dt: Time step of the stimulus (ms).
401
+
402
+ Returns:
403
+ A `Stimulus` object (Sinusoidal) that can be plotted and injected.
404
+
405
+ Notes:
406
+ - If `amplitude` is provided, `amplitude_percent` is ignored.
407
+ - If `threshold_current` is not provided, threshold-based parameters cannot be used.
408
+ """
409
+ is_amplitude_based = amplitude is not None
410
+ is_threshold_based = (
411
+ threshold_current is not None
412
+ and threshold_current != 0
413
+ and amplitude_percent is not None
414
+ )
415
+
416
+ if is_amplitude_based:
417
+ if is_threshold_based:
418
+ logger.info(
419
+ "amplitude, threshold_current, and amplitude_percent are all set in Sinusoidal."
420
+ " Using absolute amplitude and ignoring threshold-based parameters."
421
+ )
422
+
423
+ return Sinusoidal.amplitude_based(
424
+ dt=dt,
425
+ pre_delay=pre_delay,
426
+ post_delay=post_delay,
427
+ duration=duration,
428
+ frequency=frequency,
429
+ amplitude=amplitude, # type: ignore[arg-type]
430
+ )
431
+
432
+ if is_threshold_based:
433
+ return Sinusoidal.threshold_based(
434
+ dt=dt,
435
+ pre_delay=pre_delay,
436
+ post_delay=post_delay,
437
+ duration=duration,
438
+ frequency=frequency,
439
+ amplitude_percent=amplitude_percent, # type: ignore[arg-type]
440
+ threshold_current=threshold_current, # type: ignore[arg-type]
441
+ )
442
+
443
+ raise TypeError("You have to provide either `amplitude` or `threshold_current` with `amplitude_percent`.")
444
+
379
445
  def ornstein_uhlenbeck(
380
446
  self,
381
447
  pre_delay: float,
@@ -18,6 +18,7 @@ from abc import ABC, abstractmethod
18
18
  from typing import Optional
19
19
  import logging
20
20
  import matplotlib.pyplot as plt
21
+ import neuron
21
22
  import numpy as np
22
23
  from bluecellulab.cell.stimuli_generator import get_relative_shotnoise_params
23
24
  from bluecellulab.exceptions import BluecellulabError
@@ -57,7 +58,6 @@ class Stimulus(ABC):
57
58
  ax.plot(self.time, self.current, **kwargs)
58
59
  ax.set_xlabel("Time (ms)")
59
60
  ax.set_ylabel("Current (nA)")
60
- ax.set_title(self.__class__.__name__)
61
61
  return ax
62
62
 
63
63
  def __add__(self, other: Stimulus) -> CombinedStimulus:
@@ -203,7 +203,6 @@ class OUProcess(Stimulus):
203
203
  """Generates an Ornstein-Uhlenbeck noise signal."""
204
204
  from bluecellulab.cell.stimuli_generator import gen_ornstein_uhlenbeck
205
205
  from bluecellulab.rngsettings import RNGSettings
206
- import neuron
207
206
 
208
207
  rng_settings = RNGSettings.get_instance()
209
208
  rng = neuron.h.Random()
@@ -251,7 +250,6 @@ class ShotNoiseProcess(Stimulus):
251
250
  """Generates the shot noise time and current vectors."""
252
251
  from bluecellulab.cell.stimuli_generator import gen_shotnoise_signal
253
252
  from bluecellulab.rngsettings import RNGSettings
254
- import neuron
255
253
 
256
254
  rng_settings = RNGSettings.get_instance()
257
255
  rng = neuron.h.Random()
@@ -310,12 +308,11 @@ class StepNoiseProcess(Stimulus):
310
308
  def _generate_step_noise(self):
311
309
  """Generates the step noise time and current vectors using NEURON’s
312
310
  random generator."""
313
- from neuron import h
314
311
  from bluecellulab.rngsettings import RNGSettings
315
312
 
316
313
  # Get NEURON RNG settings
317
314
  rng_settings = RNGSettings.get_instance()
318
- rng = h.Random()
315
+ rng = neuron.h.Random()
319
316
 
320
317
  if rng_settings.mode == "Random123":
321
318
  seed1, seed2, seed3 = 2997, 19216, self.seed if self.seed else 123
@@ -341,6 +338,37 @@ class StepNoiseProcess(Stimulus):
341
338
  return np.array(time_values), np.array(current_values)
342
339
 
343
340
 
341
+ class SinusoidalWave(Stimulus):
342
+ """Generates a sinusoidal current wave."""
343
+
344
+ def __init__(self, dt: float, duration: float, amplitude: float, frequency: float):
345
+ super().__init__(dt)
346
+ self.duration = duration
347
+ self.amplitude = amplitude
348
+ self.frequency = frequency
349
+
350
+ self._time, self._current = self._generate_sinusoidal_signal()
351
+
352
+ @property
353
+ def time(self) -> np.ndarray:
354
+ return self._time
355
+
356
+ @property
357
+ def current(self) -> np.ndarray:
358
+ return self._current
359
+
360
+ def _generate_sinusoidal_signal(self):
361
+ """Generate the sinusoidal waveform."""
362
+ tvec = neuron.h.Vector()
363
+ tvec.indgen(0.0, self.duration, self.dt) # Time points using NEURON
364
+
365
+ stim = neuron.h.Vector(len(tvec))
366
+ stim.sin(self.frequency, 0.0, self.dt) # Generate sinusoidal wave using NEURON
367
+ stim.mul(self.amplitude) # Scale by amplitude
368
+
369
+ return np.array(tvec.to_python()), np.array(stim.to_python())
370
+
371
+
344
372
  class Step(Stimulus):
345
373
 
346
374
  def __init__(self):
@@ -780,3 +808,73 @@ class StepNoise(Stimulus):
780
808
  sigma=sigma,
781
809
  seed=seed,
782
810
  )
811
+
812
+
813
+ class Sinusoidal(Stimulus):
814
+ """Factory-compatible Sinusoidal Stimulus."""
815
+
816
+ def __init__(self):
817
+ """Prevents direct instantiation."""
818
+ raise NotImplementedError(
819
+ "This class cannot be instantiated directly. "
820
+ "Please use 'amplitude_based' or 'threshold_based' methods."
821
+ )
822
+
823
+ @classmethod
824
+ def amplitude_based(
825
+ cls,
826
+ dt: float,
827
+ pre_delay: float,
828
+ duration: float,
829
+ post_delay: float,
830
+ amplitude: float,
831
+ frequency: float,
832
+ ) -> CombinedStimulus:
833
+ """Creates a sinusoidal stimulus with a specified amplitude.
834
+
835
+ Args:
836
+ dt: Time step of the stimulus.
837
+ pre_delay: Delay before the sinusoidal wave starts.
838
+ duration: Duration of the sinusoidal signal.
839
+ post_delay: Delay after the wave ends.
840
+ amplitude: Amplitude of the sinusoidal wave.
841
+ frequency: Frequency of the wave in Hz.
842
+ """
843
+ return (
844
+ Empty(dt, duration=pre_delay)
845
+ + SinusoidalWave(dt, duration, amplitude, frequency)
846
+ + Empty(dt, duration=post_delay)
847
+ )
848
+
849
+ @classmethod
850
+ def threshold_based(
851
+ cls,
852
+ dt: float,
853
+ pre_delay: float,
854
+ duration: float,
855
+ post_delay: float,
856
+ frequency: float,
857
+ threshold_current: float,
858
+ amplitude_percent: float,
859
+ ) -> CombinedStimulus:
860
+ """Creates a sinusoidal stimulus relative to the threshold current.
861
+
862
+ Args:
863
+ dt: Time step of the stimulus.
864
+ pre_delay: Delay before the sinusoidal wave starts.
865
+ duration: Duration of the sinusoidal signal.
866
+ post_delay: Delay after the wave ends.
867
+ frequency: Frequency of the wave in Hz.
868
+ threshold_current: Baseline threshold current.
869
+ amplitude_percent: Amplitude as a percentage of the threshold current.
870
+ """
871
+ amplitude = (amplitude_percent / 100) * threshold_current
872
+
873
+ return cls.amplitude_based(
874
+ dt,
875
+ pre_delay=pre_delay,
876
+ duration=duration,
877
+ post_delay=post_delay,
878
+ amplitude=amplitude,
879
+ frequency=frequency,
880
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: bluecellulab
3
- Version: 2.6.43
3
+ Version: 2.6.45
4
4
  Summary: Biologically detailed neural network simulations and analysis.
5
5
  Author: Blue Brain Project, EPFL
6
6
  License: Apache2.0
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes