bmtool 0.6.9.1__py3-none-any.whl → 0.6.9.2__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.
bmtool/singlecell.py CHANGED
@@ -11,6 +11,16 @@ import pandas as pd
11
11
 
12
12
 
13
13
  def load_biophys1():
14
+ """
15
+ Load the Biophys1 template from BMTK if it hasn't been loaded yet.
16
+
17
+ This function checks if the Biophys1 object exists in NEURON's h namespace.
18
+ If not, it loads the necessary HOC files for Allen Cell Types Database models.
19
+
20
+ Notes:
21
+ ------
22
+ This is primarily used for working with cell models from the Allen Cell Types Database.
23
+ """
14
24
  if not hasattr(h, 'Biophys1'):
15
25
  from bmtk import utils
16
26
  module_dir = os.path.dirname(os.path.abspath(utils.__file__))
@@ -20,11 +30,29 @@ def load_biophys1():
20
30
 
21
31
 
22
32
  def load_allen_database_cells(morphology, dynamic_params, model_processing='aibs_perisomatic'):
23
- """Create Allen cell model
24
- morphology: morphology file path
25
- dynamic_params: dynamic_params file path
26
- model_processing: model processing type by AllenCellType database
27
- Return: a function that creates and returns a cell object
33
+ """
34
+ Create a cell model from the Allen Cell Types Database.
35
+
36
+ Parameters:
37
+ -----------
38
+ morphology : str
39
+ Path to the morphology file (SWC or ASC format).
40
+ dynamic_params : str
41
+ Path to the JSON file containing biophysical parameters.
42
+ model_processing : str, optional
43
+ Model processing type from the AllenCellType database.
44
+ Default is 'aibs_perisomatic'.
45
+
46
+ Returns:
47
+ --------
48
+ callable
49
+ A function that, when called, creates and returns a NEURON cell object
50
+ with the specified morphology and biophysical properties.
51
+
52
+ Notes:
53
+ ------
54
+ This function creates a closure that loads and returns a cell when called.
55
+ The cell is created using the Allen Institute's modeling framework.
28
56
  """
29
57
  from bmtk.simulator.bionet.default_setters import cell_models
30
58
  load_biophys1()
@@ -39,6 +67,34 @@ def load_allen_database_cells(morphology, dynamic_params, model_processing='aibs
39
67
 
40
68
 
41
69
  def get_target_site(cell, sec=('soma', 0), loc=0.5, site=''):
70
+ """
71
+ Get a segment and its section from a cell model using flexible section specification.
72
+
73
+ Parameters:
74
+ -----------
75
+ cell : NEURON cell object
76
+ The cell object to access sections from.
77
+ sec : str, int, or tuple, optional
78
+ Section specification, which can be:
79
+ - str: Section name (defaults to index 0 if multiple sections)
80
+ - int: Index into the 'all' section list
81
+ - tuple: (section_name, index) for accessing indexed sections
82
+ Default is ('soma', 0).
83
+ loc : float, optional
84
+ Location along the section (0-1), default is 0.5 (middle of section).
85
+ site : str, optional
86
+ Name of the site for error messages (e.g., 'injection', 'recording').
87
+
88
+ Returns:
89
+ --------
90
+ tuple
91
+ (segment, section) at the specified location
92
+
93
+ Raises:
94
+ -------
95
+ ValueError
96
+ If the section cannot be found or accessed.
97
+ """
42
98
  if isinstance(sec, str):
43
99
  sec = (sec, 0)
44
100
  elif isinstance(sec, int):
@@ -64,19 +120,38 @@ class CurrentClamp(object):
64
120
  def __init__(self, template_name, post_init_function=None, record_sec='soma', record_loc=0.5, threshold=None,
65
121
  inj_sec='soma', inj_loc=0.5, inj_amp=100., inj_delay=100., inj_dur=1000., tstop=1000.):
66
122
  """
67
- template_name: str, name of the cell template located in hoc
68
- or callable, a function that creates and returns a cell object
69
- post_init_function: str, function of the cell to be called after the cell has been initialized
70
- record_sec: tuple, (section list name, index) to access a section in a hoc template
71
- If a string of section name is specified, index default to 0
72
- If an index is specified, section list name default to `all`
73
- record_loc: float, location within [0, 1] of a segment in a section to record from
74
- threshold: Optional float, spike threshold (mV), if specified, record and count spikes times
75
- inj_sec, inj_loc: current injection site, same format as record site
76
- tstop: time for simulation (ms)
77
- inj_delay: current injection start time (ms)
78
- inj_dur: current injection duration (ms)
79
- inj_amp: current injection amplitude (pA)
123
+ Initialize a current clamp simulation environment.
124
+
125
+ Parameters:
126
+ -----------
127
+ template_name : str or callable
128
+ Either the name of the cell template located in HOC or
129
+ a function that creates and returns a cell object.
130
+ post_init_function : str, optional
131
+ Function of the cell to be called after initialization.
132
+ record_sec : str, int, or tuple, optional
133
+ Section to record from. Can be:
134
+ - str: Section name (defaults to index 0 if multiple sections)
135
+ - int: Index into the 'all' section list
136
+ - tuple: (section_name, index) for accessing indexed sections
137
+ Default is 'soma'.
138
+ record_loc : float, optional
139
+ Location (0-1) within section to record from. Default is 0.5.
140
+ threshold : float, optional
141
+ Spike threshold (mV). If specified, spikes are detected and counted.
142
+ inj_sec : str, int, or tuple, optional
143
+ Section for current injection. Same format as record_sec. Default is 'soma'.
144
+ inj_loc : float, optional
145
+ Location (0-1) within section for current injection. Default is 0.5.
146
+ inj_amp : float, optional
147
+ Current injection amplitude (pA). Default is 100.0.
148
+ inj_delay : float, optional
149
+ Start time for current injection (ms). Default is 100.0.
150
+ inj_dur : float, optional
151
+ Duration of current injection (ms). Default is 1000.0.
152
+ tstop : float, optional
153
+ Total simulation time (ms). Default is 1000.0.
154
+ Will be extended if necessary to include the full current injection.
80
155
  """
81
156
  self.create_cell = getattr(h, template_name) if isinstance(template_name, str) else template_name
82
157
  self.record_sec = record_sec
@@ -92,7 +167,7 @@ class CurrentClamp(object):
92
167
 
93
168
  # sometimes people may put a hoc object in for the template name
94
169
  if callable(template_name):
95
- self.cell = template_name
170
+ self.cell = template_name()
96
171
  else:
97
172
  self.cell = self.create_cell()
98
173
  if post_init_function:
@@ -101,6 +176,18 @@ class CurrentClamp(object):
101
176
  self.setup()
102
177
 
103
178
  def setup(self):
179
+ """
180
+ Set up the simulation environment for current clamp experiments.
181
+
182
+ This method:
183
+ 1. Creates the current clamp stimulus at the specified injection site
184
+ 2. Sets up voltage recording at the specified recording site
185
+ 3. Creates vectors to store time and voltage data
186
+
187
+ Notes:
188
+ ------
189
+ Sets self.cell_src as the current clamp object that can be accessed later.
190
+ """
104
191
  inj_seg, _ = get_target_site(self.cell, self.inj_sec, self.inj_loc, 'injection')
105
192
  self.cell_src = h.IClamp(inj_seg)
106
193
  self.cell_src.delay = self.inj_delay
@@ -124,6 +211,21 @@ class CurrentClamp(object):
124
211
  print(f'Recording: {rec_seg}._ref_v')
125
212
 
126
213
  def execute(self) -> Tuple[list, list]:
214
+ """
215
+ Run the current clamp simulation and return recorded data.
216
+
217
+ This method:
218
+ 1. Sets up the simulation duration
219
+ 2. Initializes and runs the NEURON simulation
220
+ 3. Converts recorded vectors to Python lists
221
+
222
+ Returns:
223
+ --------
224
+ tuple
225
+ (time_vector, voltage_vector) where:
226
+ - time_vector: List of time points (ms)
227
+ - voltage_vector: List of membrane potentials (mV) at those time points
228
+ """
127
229
  print("Current clamp simulation running...")
128
230
  h.tstop = self.tstop
129
231
  h.stdinit()
@@ -141,11 +243,39 @@ class Passive(CurrentClamp):
141
243
  def __init__(self, template_name, inj_amp=-100., inj_delay=200., inj_dur=1000.,
142
244
  tstop=1200., method=None, **kwargs):
143
245
  """
144
- method: {'simple', 'exp2', 'exp'}, optional.
145
- Method to estimate membrane time constant. Default is 'simple'
146
- that find the time to reach 0.632 of change. 'exp2' fits a double
147
- exponential curve to the membrane potential response. 'exp' fits
148
- a single exponential curve.
246
+ Initialize a passive membrane property simulation environment.
247
+
248
+ Parameters:
249
+ -----------
250
+ template_name : str or callable
251
+ Either the name of the cell template located in HOC or
252
+ a function that creates and returns a cell object.
253
+ inj_amp : float, optional
254
+ Current injection amplitude (pA). Default is -100.0 (negative to measure passive properties).
255
+ inj_delay : float, optional
256
+ Start time for current injection (ms). Default is 200.0.
257
+ inj_dur : float, optional
258
+ Duration of current injection (ms). Default is 1000.0.
259
+ tstop : float, optional
260
+ Total simulation time (ms). Default is 1200.0.
261
+ method : str, optional
262
+ Method to estimate membrane time constant:
263
+ - 'simple': Find the time to reach 0.632 of voltage change
264
+ - 'exp': Fit a single exponential curve
265
+ - 'exp2': Fit a double exponential curve
266
+ Default is None, which uses 'simple' when calculations are performed.
267
+ **kwargs :
268
+ Additional keyword arguments to pass to the parent CurrentClamp constructor.
269
+
270
+ Notes:
271
+ ------
272
+ This class is designed for measuring passive membrane properties including
273
+ input resistance and membrane time constant.
274
+
275
+ Raises:
276
+ -------
277
+ AssertionError
278
+ If inj_amp is zero (must be non-zero to measure passive properties).
149
279
  """
150
280
  assert(inj_amp != 0)
151
281
  super().__init__(template_name=template_name, tstop=tstop,
@@ -155,6 +285,23 @@ class Passive(CurrentClamp):
155
285
  self.tau_methods = {'simple': self.tau_simple, 'exp2': self.tau_double_exponential, 'exp': self.tau_single_exponential}
156
286
 
157
287
  def tau_simple(self):
288
+ """
289
+ Calculate membrane time constant using the simple 0.632 criterion method.
290
+
291
+ This method calculates the membrane time constant by finding the time it takes
292
+ for the membrane potential to reach 63.2% (1-1/e) of its final value after
293
+ a step current injection.
294
+
295
+ Returns:
296
+ --------
297
+ callable
298
+ A function that prints the calculation details when called.
299
+
300
+ Notes:
301
+ ------
302
+ Sets the following attributes:
303
+ - tau: The calculated membrane time constant in ms
304
+ """
158
305
  v_t_const = self.cell_v_final - self.v_diff / np.e
159
306
  index_v_tau = next(x for x, val in enumerate(self.v_vec_inj) if val <= v_t_const)
160
307
  self.tau = self.t_vec[self.index_v_rest + index_v_tau] - self.v_rest_time # ms
@@ -171,9 +318,53 @@ class Passive(CurrentClamp):
171
318
 
172
319
  @staticmethod
173
320
  def single_exponential(t, a0, a, tau):
321
+ """
322
+ Single exponential function for fitting membrane potential response.
323
+
324
+ Parameters:
325
+ -----------
326
+ t : array-like
327
+ Time values
328
+ a0 : float
329
+ Offset (steady-state) value
330
+ a : float
331
+ Amplitude of the exponential component
332
+ tau : float
333
+ Time constant of the exponential decay
334
+
335
+ Returns:
336
+ --------
337
+ array-like
338
+ Function values at the given time points
339
+ """
174
340
  return a0 + a * np.exp(-t / tau)
175
341
 
176
342
  def tau_single_exponential(self):
343
+ """
344
+ Calculate membrane time constant by fitting a single exponential curve.
345
+
346
+ This method:
347
+ 1. Identifies the peak response (for sag characterization)
348
+ 2. Falls back to simple method for initial estimate
349
+ 3. Fits a single exponential function to the membrane potential response
350
+ 4. Sets tau to the exponential time constant
351
+
352
+ Returns:
353
+ --------
354
+ callable
355
+ A function that prints the calculation details when called.
356
+
357
+ Notes:
358
+ ------
359
+ Sets the following attributes:
360
+ - tau: The calculated membrane time constant in ms
361
+ - t_peak, v_peak: Time and voltage of peak response
362
+ - v_sag: Sag potential (difference between peak and steady-state)
363
+ - v_max_diff: Maximum potential difference from rest
364
+ - sag_norm: Normalized sag ratio
365
+ - popt: Optimized parameters from curve fitting
366
+ - pcov: Covariance matrix of the optimization
367
+ """
177
368
  index_v_peak = (np.sign(self.inj_amp) * self.v_vec_inj).argmax()
178
369
  self.t_peak = self.t_vec_inj[index_v_peak]
179
370
  self.v_peak = self.v_vec_inj[index_v_peak]
@@ -206,9 +397,57 @@ class Passive(CurrentClamp):
206
397
 
207
398
  @staticmethod
208
399
  def double_exponential(t, a0, a1, a2, tau1, tau2):
400
+ """
401
+ Double exponential function for fitting membrane potential response.
402
+
403
+ This function is particularly useful for modeling cells with sag responses,
404
+ where the membrane potential shows two distinct time constants.
405
+
406
+ Parameters:
407
+ -----------
408
+ t : array-like
409
+ Time values
410
+ a0 : float
411
+ Offset (steady-state) value
412
+ a1 : float
413
+ Amplitude of the first exponential component
414
+ a2 : float
415
+ Amplitude of the second exponential component
416
+ tau1 : float
417
+ Time constant of the first exponential component
418
+ tau2 : float
419
+ Time constant of the second exponential component
420
+
421
+ Returns:
422
+ --------
423
+ array-like
424
+ Function values at the given time points
425
+ """
209
426
  return a0 + a1 * np.exp(-t / tau1) + a2 * np.exp(-t / tau2)
210
427
 
211
428
  def tau_double_exponential(self):
429
+ """
430
+ Calculate membrane time constant by fitting a double exponential curve.
431
+
432
+ This method is useful for cells with sag responses that cannot be
433
+ fitted well with a single exponential.
434
+
435
+ Returns:
436
+ --------
437
+ callable
438
+ A function that prints the calculation details when called.
439
+
440
+ Notes:
441
+ ------
442
+ Sets the following attributes:
443
+ - tau: The calculated membrane time constant (the slower of the two time constants)
444
+ - t_peak, v_peak: Time and voltage of peak response
445
+ - v_sag: Sag potential (difference between peak and steady-state)
446
+ - v_max_diff: Maximum potential difference from rest
447
+ - sag_norm: Normalized sag ratio
448
+ - popt: Optimized parameters from curve fitting
449
+ - pcov: Covariance matrix of the optimization
450
+ """
212
451
  index_v_peak = (np.sign(self.inj_amp) * self.v_vec_inj).argmax()
213
452
  self.t_peak = self.t_vec_inj[index_v_peak]
214
453
  self.v_peak = self.v_vec_inj[index_v_peak]
@@ -240,16 +479,58 @@ class Passive(CurrentClamp):
240
479
  return print_calc
241
480
 
242
481
  def double_exponential_fit(self):
482
+ """
483
+ Get the double exponential fit values for plotting.
484
+
485
+ Returns:
486
+ --------
487
+ tuple
488
+ (time_vector, fitted_values) where:
489
+ - time_vector: Time points starting from rest time
490
+ - fitted_values: Membrane potential values predicted by the double exponential function
491
+ """
243
492
  t_vec = self.v_rest_time + self.t_vec_inj
244
493
  v_fit = self.double_exponential(self.t_vec_inj, *self.popt)
245
494
  return t_vec, v_fit
246
495
 
247
496
  def single_exponential_fit(self):
497
+ """
498
+ Get the single exponential fit values for plotting.
499
+
500
+ Returns:
501
+ --------
502
+ tuple
503
+ (time_vector, fitted_values) where:
504
+ - time_vector: Time points starting from rest time
505
+ - fitted_values: Membrane potential values predicted by the single exponential function
506
+ """
248
507
  t_vec = self.v_rest_time + self.t_vec_inj
249
508
  v_fit = self.single_exponential(self.t_vec_inj, *self.popt)
250
509
  return t_vec, v_fit
251
510
 
252
511
  def execute(self):
512
+ """
513
+ Run the simulation and calculate passive membrane properties.
514
+
515
+ This method:
516
+ 1. Runs the NEURON simulation
517
+ 2. Extracts membrane potential at rest and steady-state
518
+ 3. Calculates input resistance from the step response
519
+ 4. Calculates membrane time constant using the specified method
520
+ 5. Prints detailed calculations for educational purposes
521
+
522
+ Returns:
523
+ --------
524
+ tuple
525
+ (time_vector, voltage_vector) from the simulation
526
+
527
+ Notes:
528
+ ------
529
+ Sets several attributes including:
530
+ - v_rest: Resting membrane potential
531
+ - r_in: Input resistance in MOhms
532
+ - tau: Membrane time constant in ms
533
+ """
253
534
  print("Running simulation for passive properties...")
254
535
  h.tstop = self.tstop
255
536
  h.stdinit()
@@ -292,13 +573,41 @@ class FI(object):
292
573
  i_start=0., i_stop=1050., i_increment=100., tstart=50., tdur=1000., threshold=0.,
293
574
  record_sec='soma', record_loc=0.5, inj_sec='soma', inj_loc=0.5):
294
575
  """
295
- template_name: str, name of the cell template located in hoc
296
- or callable, a function that creates and returns a cell object
297
- i_start: initial current injection amplitude (pA)
298
- i_stop: maximum current injection amplitude (pA)
299
- i_increment: amplitude increment each trial (pA)
300
- tstart: current injection start time (ms)
301
- tdur: current injection duration (ms)
576
+ Initialize a frequency-current (F-I) curve simulation environment.
577
+
578
+ Parameters:
579
+ -----------
580
+ template_name : str or callable
581
+ Either the name of the cell template located in HOC or
582
+ a function that creates and returns a cell object.
583
+ post_init_function : str, optional
584
+ Function of the cell to be called after initialization.
585
+ i_start : float, optional
586
+ Initial current injection amplitude (pA). Default is 0.0.
587
+ i_stop : float, optional
588
+ Maximum current injection amplitude (pA). Default is 1050.0.
589
+ i_increment : float, optional
590
+ Amplitude increment between trials (pA). Default is 100.0.
591
+ tstart : float, optional
592
+ Current injection start time (ms). Default is 50.0.
593
+ tdur : float, optional
594
+ Current injection duration (ms). Default is 1000.0.
595
+ threshold : float, optional
596
+ Spike threshold (mV). Default is 0.0.
597
+ record_sec : str, int, or tuple, optional
598
+ Section to record from. Same format as in CurrentClamp. Default is 'soma'.
599
+ record_loc : float, optional
600
+ Location (0-1) within section to record from. Default is 0.5.
601
+ inj_sec : str, int, or tuple, optional
602
+ Section for current injection. Same format as record_sec. Default is 'soma'.
603
+ inj_loc : float, optional
604
+ Location (0-1) within section for current injection. Default is 0.5.
605
+
606
+ Notes:
607
+ ------
608
+ This class creates multiple instances of the cell model, one for each
609
+ current amplitude to be tested, allowing all simulations to be run
610
+ in a single call to NEURON's run() function.
302
611
  """
303
612
  self.create_cell = getattr(h, template_name) if isinstance(template_name, str) else template_name
304
613
  self.post_init_function = post_init_function
@@ -333,6 +642,19 @@ class FI(object):
333
642
  self.setup()
334
643
 
335
644
  def setup(self):
645
+ """
646
+ Set up the simulation environment for frequency-current (F-I) analysis.
647
+
648
+ For each current amplitude to be tested, this method:
649
+ 1. Creates a current source at the injection site
650
+ 2. Sets up spike detection at the recording site
651
+ 3. Creates vectors to record spike times
652
+
653
+ Notes:
654
+ ------
655
+ This preparation allows multiple simulations to be run with different
656
+ current amplitudes in a single call to h.run().
657
+ """
336
658
  for cell, amp in zip(self.cells, self.amps):
337
659
  inj_seg, _ = get_target_site(cell, self.inj_sec, self.inj_loc, 'injection')
338
660
  src = h.IClamp(inj_seg)
@@ -353,6 +675,21 @@ class FI(object):
353
675
  print(f'Recording: {rec_seg}._ref_v')
354
676
 
355
677
  def execute(self):
678
+ """
679
+ Run the simulation and count spikes for each current amplitude.
680
+
681
+ This method:
682
+ 1. Initializes and runs a single NEURON simulation that evaluates all current amplitudes
683
+ 2. Counts spikes for each current amplitude
684
+ 3. Prints a summary of results in tabular format
685
+
686
+ Returns:
687
+ --------
688
+ tuple
689
+ (current_amplitudes, spike_counts) where:
690
+ - current_amplitudes: List of current injection amplitudes (nA)
691
+ - spike_counts: List of spike counts corresponding to each amplitude
692
+ """
356
693
  print("Running simulations for FI curve...")
357
694
  h.tstop = self.tstop
358
695
  h.stdinit()
@@ -376,9 +713,42 @@ class ZAP(CurrentClamp):
376
713
  def __init__(self, template_name, inj_amp=100., inj_delay=200., inj_dur=15000.,
377
714
  tstop=15500., fstart=0., fend=15., chirp_type=None, **kwargs):
378
715
  """
379
- fstart, fend: float, frequency at the start and end of the chirp current
380
- chirp_type: {'linear', 'exponential'}, optional.
381
- Type of chirp current, i.e. how frequency increase over time.
716
+ Initialize a ZAP (impedance amplitude profile) simulation environment.
717
+
718
+ Parameters:
719
+ -----------
720
+ template_name : str or callable
721
+ Either the name of the cell template located in HOC or
722
+ a function that creates and returns a cell object.
723
+ inj_amp : float, optional
724
+ Current injection amplitude (pA). Default is 100.0.
725
+ inj_delay : float, optional
726
+ Start time for current injection (ms). Default is 200.0.
727
+ inj_dur : float, optional
728
+ Duration of current injection (ms). Default is 15000.0.
729
+ tstop : float, optional
730
+ Total simulation time (ms). Default is 15500.0.
731
+ fstart : float, optional
732
+ Starting frequency of the chirp current (Hz). Default is 0.0.
733
+ fend : float, optional
734
+ Ending frequency of the chirp current (Hz). Default is 15.0.
735
+ chirp_type : str, optional
736
+ Type of chirp current determining how frequency increases over time:
737
+ - 'linear': Linear increase in frequency (default if None)
738
+ - 'exponential': Exponential increase in frequency
739
+ **kwargs :
740
+ Additional keyword arguments to pass to the parent CurrentClamp constructor.
741
+
742
+ Notes:
743
+ ------
744
+ This class is designed for measuring the frequency-dependent impedance profile
745
+ of a neuron using a chirp current that sweeps through frequencies.
746
+
747
+ Raises:
748
+ -------
749
+ AssertionError
750
+ - If inj_amp is zero
751
+ - If chirp_type is 'exponential' and either fstart or fend is <= 0
382
752
  """
383
753
  assert(inj_amp != 0)
384
754
  super().__init__(template_name=template_name, tstop=tstop,
@@ -392,13 +762,67 @@ class ZAP(CurrentClamp):
392
762
  assert(fstart > 0 and fend > 0)
393
763
 
394
764
  def linear_chirp(self, t, f0, f1):
765
+ """
766
+ Generate a chirp current with linearly increasing frequency.
767
+
768
+ Parameters:
769
+ -----------
770
+ t : ndarray
771
+ Time vector (ms)
772
+ f0 : float
773
+ Start frequency (kHz)
774
+ f1 : float
775
+ End frequency (kHz)
776
+
777
+ Returns:
778
+ --------
779
+ ndarray
780
+ Current values with amplitude self.inj_amp and frequency
781
+ increasing linearly from f0 to f1 Hz over time t
782
+ """
395
783
  return self.inj_amp * np.sin(np.pi * (2 * f0 + (f1 - f0) / t[-1] * t) * t)
396
784
 
397
785
  def exponential_chirp(self, t, f0, f1):
786
+ """
787
+ Generate a chirp current with exponentially increasing frequency.
788
+
789
+ Parameters:
790
+ -----------
791
+ t : ndarray
792
+ Time vector (ms)
793
+ f0 : float
794
+ Start frequency (kHz), must be > 0
795
+ f1 : float
796
+ End frequency (kHz), must be > 0
797
+
798
+ Returns:
799
+ --------
800
+ ndarray
801
+ Current values with amplitude self.inj_amp and frequency
802
+ increasing exponentially from f0 to f1 Hz over time t
803
+
804
+ Notes:
805
+ ------
806
+ For exponential chirp, both f0 and f1 must be positive.
807
+ """
398
808
  L = np.log(f1 / f0) / t[-1]
399
809
  return self.inj_amp * np.sin(np.pi * 2 * f0 / L * (np.exp(L * t) - 1))
400
810
 
401
811
  def zap_current(self):
812
+ """
813
+ Create a frequency-modulated (chirp) current for probing impedance.
814
+
815
+ This method:
816
+ 1. Sets up time vectors for the simulation and current injection
817
+ 2. Creates a chirp current based on the specified parameters (linear or exponential)
818
+ 3. Prepares the current vector for NEURON playback
819
+
820
+ Notes:
821
+ ------
822
+ The chirp current increases in frequency from fstart to fend Hz over the duration
823
+ of the injection. This allows frequency-dependent impedance to be measured in
824
+ a single simulation.
825
+ """
402
826
  self.dt = dt = h.dt
403
827
  self.index_v_rest = int(self.inj_delay / dt)
404
828
  self.index_v_final = int(self.inj_stop / dt)
@@ -417,6 +841,28 @@ class ZAP(CurrentClamp):
417
841
  self.zap_vec.play(self.cell_src._ref_amp, dt)
418
842
 
419
843
  def get_impedance(self, smooth=1):
844
+ """
845
+ Calculate and extract the frequency-dependent impedance profile.
846
+
847
+ This method:
848
+ 1. Filters the impedance to the frequency range of interest
849
+ 2. Optionally applies smoothing to reduce noise
850
+ 3. Identifies the resonant frequency (peak impedance)
851
+
852
+ Parameters:
853
+ -----------
854
+ smooth : int, optional
855
+ Window size for smoothing the impedance. Default is 1 (no smoothing).
856
+
857
+ Returns:
858
+ --------
859
+ tuple
860
+ (frequencies, impedance_values) in the range of interest
861
+
862
+ Notes:
863
+ ------
864
+ Sets self.peak_freq to the resonant frequency (frequency of maximum impedance).
865
+ """
420
866
  f_idx = (self.freq > min(self.fstart, self.fend)) & (self.freq < max(self.fstart, self.fend))
421
867
  impedance = self.impedance
422
868
  if smooth > 1:
@@ -427,6 +873,27 @@ class ZAP(CurrentClamp):
427
873
  return freq, impedance
428
874
 
429
875
  def execute(self) -> Tuple[list, list]:
876
+ """
877
+ Run the ZAP simulation and calculate the impedance profile.
878
+
879
+ This method:
880
+ 1. Sets up the chirp current
881
+ 2. Runs the NEURON simulation
882
+ 3. Calculates the impedance using FFT
883
+ 4. Prints a summary of the frequency range and analysis method
884
+
885
+ Returns:
886
+ --------
887
+ tuple
888
+ (time_vector, voltage_vector) from the simulation
889
+
890
+ Notes:
891
+ ------
892
+ Sets several attributes including:
893
+ - Z: Complex impedance values (from FFT)
894
+ - freq: Frequency values for the impedance profile
895
+ - impedance: Absolute impedance values
896
+ """
430
897
  print("ZAP current simulation running...")
431
898
  self.zap_current()
432
899
  h.tstop = self.tstop