bmtool 0.6.8.1__py3-none-any.whl → 0.6.8.3__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/SLURM.py CHANGED
@@ -305,6 +305,45 @@ export OUTPUT_DIR={case_output_dir}
305
305
  return True
306
306
 
307
307
 
308
+ def get_relative_path(endpoint, absolute_path):
309
+ """Convert absolute path to relative path for Globus transfer."""
310
+ try:
311
+ # Get the directories at the mount point
312
+ result = subprocess.run(["globus", "ls", f"{endpoint}:/"], capture_output=True, text=True, check=True)
313
+ dirs = set(result.stdout.splitlines()) # Convert to a set for quicker lookup
314
+
315
+ # Split the absolute path into parts
316
+ path_parts = absolute_path.strip("/").split("/")
317
+
318
+ # Find the first matching directory in the list
319
+ for i, part in enumerate(path_parts):
320
+ if part+"/" in dirs:
321
+ # The mount point is everything up to and including this directory
322
+ mount_point = "/" + "/".join(path_parts[:i])
323
+ relative_path = absolute_path.replace(mount_point, "", 1).lstrip("/")
324
+ return relative_path
325
+
326
+ print("Error: Could not determine relative path.")
327
+ return None
328
+ except subprocess.CalledProcessError as e:
329
+ print(f"Error retrieving directories from Globus: {e}")
330
+ return None
331
+
332
+ def globus_transfer(source_endpoint, dest_endpoint, source_path, dest_path):
333
+ """
334
+ Transfers file using custom globus transfer function.
335
+ For more info see https://github.com/GregGlickert/transfer-files/blob/main/globus_transfer.sh
336
+ """
337
+ relative_source_path = get_relative_path(source_endpoint, source_path)
338
+ if relative_source_path is None:
339
+ print("Transfer aborted: Could not determine relative source path.")
340
+ return
341
+
342
+ command = f"globus transfer {source_endpoint}:{relative_source_path} {dest_endpoint}:{dest_path} --label 'bmtool slurm transfer'"
343
+ os.system(command)
344
+
345
+
346
+
308
347
  class BlockRunner:
309
348
  """
310
349
  Class to handle submitting multiple blocks sequentially.
@@ -334,6 +373,7 @@ class BlockRunner:
334
373
  Updates the JSON file with new parameters before each block run.
335
374
  """
336
375
  for i, block in enumerate(self.blocks):
376
+ print(block.output_base_dir)
337
377
  # Update JSON file with new parameter value
338
378
  if self.json_file_path == None and self.param_values == None:
339
379
  source_dir = block.component_path
bmtool/analysis/lfp.py CHANGED
@@ -406,3 +406,78 @@ def calculate_plv_over_time(x1: np.ndarray, x2: np.ndarray, fs: float,
406
406
  return np.array(plv_over_time), np.array(times)
407
407
 
408
408
 
409
+ def calculate_ppc1(spike_times: np.ndarray = None, lfp_signal: np.ndarray = None, spike_fs : float = None,
410
+ lfp_fs: float = None, method: str = 'hilbert', freq_of_interest: float = None,
411
+ lowcut: float = None, highcut: float = None,
412
+ bandwidth: float = 2.0) -> tuple:
413
+ """
414
+ Calculate Phase-Phase Coupling (PPC1) between spike times and LFP signal. Based on https://www.sciencedirect.com/science/article/pii/S1053811910000959
415
+
416
+ Parameters:
417
+ - spike_times: Array of spike times
418
+ - lfp_signal: Local field potential time series
419
+ - spike_fs: Sampling frequency in Hz of the spike times only needed if spikes times and lfp has different fs
420
+ - lfp_fs : Sampling frequency in Hz of the LFP
421
+ - method: 'wavelet' or 'hilbert' to choose the phase extraction method
422
+ - freq_of_interest: Desired frequency for wavelet phase extraction
423
+ - lowcut, highcut: Cutoff frequencies for bandpass filtering (Hilbert method)
424
+ - bandwidth: Bandwidth parameter for the wavelet
425
+
426
+ Returns:
427
+ - ppc1: Phase-Phase Coupling value
428
+ - spike_phases: Phases at spike times
429
+ """
430
+
431
+ if spike_fs == None:
432
+ spike_fs = lfp_fs
433
+ # Convert spike times to sample indices
434
+ spike_times_seconds = spike_times / spike_fs
435
+
436
+ # Then convert from seconds to samples at the new sampling rate
437
+ spike_indices = np.round(spike_times_seconds * lfp_fs).astype(int)
438
+
439
+ # Filter indices to ensure they're within bounds of the LFP signal
440
+ valid_indices = [idx for idx in spike_indices if 0 <= idx < len(lfp_signal)]
441
+ if len(valid_indices) <= 1:
442
+ return 0, np.array([])
443
+
444
+ # Extract phase using the specified method
445
+ if method == 'wavelet':
446
+ if freq_of_interest is None:
447
+ raise ValueError("freq_of_interest must be provided for the wavelet method.")
448
+
449
+ # Apply CWT to extract phase at the frequency of interest
450
+ lfp_complex = wavelet_filter(x=lfp_signal, freq=freq_of_interest, fs=lfp_fs, bandwidth=bandwidth)
451
+ instantaneous_phase = np.angle(lfp_complex)
452
+
453
+ elif method == 'hilbert':
454
+ if lowcut is None or highcut is None:
455
+ print("Lowcut and/or highcut were not defined, signal will not be filtered and will just take Hilbert transform for PPC1 calculation")
456
+ filtered_lfp = lfp_signal
457
+ else:
458
+ # Bandpass filter the signal
459
+ filtered_lfp = butter_bandpass_filter(lfp_signal, lowcut, highcut, lfp_fs)
460
+
461
+ # Get phase using the Hilbert transform
462
+ analytic_signal = signal.hilbert(filtered_lfp)
463
+ instantaneous_phase = np.angle(analytic_signal)
464
+
465
+ else:
466
+ raise ValueError("Invalid method. Choose 'wavelet' or 'hilbert'.")
467
+
468
+ # Get phases at spike times
469
+ spike_phases = instantaneous_phase[valid_indices]
470
+
471
+ # Calculate PPC1
472
+ n = len(spike_phases)
473
+
474
+ # Convert phases to unit vectors in the complex plane
475
+ unit_vectors = np.exp(1j * spike_phases)
476
+
477
+ # Calculate the resultant vector
478
+ resultant_vector = np.sum(unit_vectors)
479
+
480
+ # PPC1 is the squared length of the resultant vector divided by n²
481
+ ppc1 = (np.abs(resultant_vector) ** 2) / (n ** 2)
482
+
483
+ return ppc1, spike_phases
bmtool/bmplot.py CHANGED
@@ -1012,6 +1012,8 @@ def plot_firing_rate_distribution(individual_stats: pd.DataFrame, groupby: Union
1012
1012
 
1013
1013
  return ax
1014
1014
 
1015
+ def plot_entrainment():
1016
+ pass
1015
1017
 
1016
1018
  def plot_3d_positions(config=None, populations_list=None, group_by=None, title=None, save_file=None, subset=None):
1017
1019
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bmtool
3
- Version: 0.6.8.1
3
+ Version: 0.6.8.3
4
4
  Summary: BMTool
5
5
  Home-page: https://github.com/cyneuro/bmtool
6
6
  Download-URL:
@@ -1,7 +1,7 @@
1
- bmtool/SLURM.py,sha256=AKxu_Ln9wuCBVLdOJP4yAN59jYt222DM-iUlsQojNvY,18145
1
+ bmtool/SLURM.py,sha256=umHYGUX2HDlZr6Zo89wQekGrK9mZdAi0rBdCA7a--hE,19904
2
2
  bmtool/__init__.py,sha256=ZStTNkAJHJxG7Pwiy5UgCzC4KlhMS5pUNPtUJZVwL_Y,136
3
3
  bmtool/__main__.py,sha256=TmFkmDxjZ6250nYD4cgGhn-tbJeEm0u-EMz2ajAN9vE,650
4
- bmtool/bmplot.py,sha256=YoI7StM9qeZqyRfFX4M7oUGFz50tXTDOMIUqjYozj9s,54066
4
+ bmtool/bmplot.py,sha256=ymyrNBctZoglsNA28733mXzM_l4b_3JIchXkQa2V2XE,54099
5
5
  bmtool/connectors.py,sha256=hWkUUcJ4tmas8NDOFPPjQT-TgTlPcpjuZsYyAW2WkPA,72242
6
6
  bmtool/graphs.py,sha256=K8BiughRUeXFVvAgo8UzrwpSClIVg7UfmIcvtEsEsk0,6020
7
7
  bmtool/manage.py,sha256=_lCU0qBQZ4jSxjzAJUd09JEetb--cud7KZgxQFbLGSY,657
@@ -9,7 +9,7 @@ bmtool/plot_commands.py,sha256=Tqujyf0c0u8olhiHOMwgUSJXIIE1hgjv6otb25G9cA0,12298
9
9
  bmtool/singlecell.py,sha256=XZAT_2n44EhwqVLnk3qur9aO7oJ-10axJZfwPBslM88,27219
10
10
  bmtool/synapses.py,sha256=gIkfLhKDG2dHHCVJJoKuQrFn_Qut843bfk_-s97wu6c,54553
11
11
  bmtool/analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- bmtool/analysis/lfp.py,sha256=Zp-aJ8x2KmsI3h_mqvq4u9ixFYu4n0CxQpgdbYnrtYE,14909
12
+ bmtool/analysis/lfp.py,sha256=bCpxqhdH6r71yXyqAv_M7BMq4x75lO7bctyyQi6pqdU,18186
13
13
  bmtool/analysis/spikes.py,sha256=qqJ4zD8xfvSwltlWm_Bhicdngzl6uBqH6Kn5wOMKRc8,11507
14
14
  bmtool/debug/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  bmtool/debug/commands.py,sha256=AwtcR7BUUheM0NxvU1Nu234zCdpobhJv5noX8x5K2vY,583
@@ -19,9 +19,9 @@ bmtool/util/commands.py,sha256=zJF-fiLk0b8LyzHDfvewUyS7iumOxVnj33IkJDzux4M,64396
19
19
  bmtool/util/util.py,sha256=00vOAwTVIifCqouBoFoT0lBashl4fCalrk8fhg_Uq4c,56654
20
20
  bmtool/util/neuron/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  bmtool/util/neuron/celltuner.py,sha256=xSRpRN6DhPFz4q5buq_W8UmsD7BbUrkzYBEbKVloYss,87194
22
- bmtool-0.6.8.1.dist-info/licenses/LICENSE,sha256=qrXg2jj6kz5d0EnN11hllcQt2fcWVNumx0xNbV05nyM,1068
23
- bmtool-0.6.8.1.dist-info/METADATA,sha256=YVdlvlptmCrgkau7KEk_HkbEi__QcX0bAxDwe4eExJM,20431
24
- bmtool-0.6.8.1.dist-info/WHEEL,sha256=tTnHoFhvKQHCh4jz3yCn0WPTYIy7wXx3CJtJ7SJGV7c,91
25
- bmtool-0.6.8.1.dist-info/entry_points.txt,sha256=0-BHZ6nUnh0twWw9SXNTiRmKjDnb1VO2DfG_-oprhAc,45
26
- bmtool-0.6.8.1.dist-info/top_level.txt,sha256=gpd2Sj-L9tWbuJEd5E8C8S8XkNm5yUE76klUYcM-eWM,7
27
- bmtool-0.6.8.1.dist-info/RECORD,,
22
+ bmtool-0.6.8.3.dist-info/licenses/LICENSE,sha256=qrXg2jj6kz5d0EnN11hllcQt2fcWVNumx0xNbV05nyM,1068
23
+ bmtool-0.6.8.3.dist-info/METADATA,sha256=jT598Nn_w-_OrCzo7L0cW1wtrv-OKW2aIDhxAqXA2-Q,20431
24
+ bmtool-0.6.8.3.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
25
+ bmtool-0.6.8.3.dist-info/entry_points.txt,sha256=0-BHZ6nUnh0twWw9SXNTiRmKjDnb1VO2DfG_-oprhAc,45
26
+ bmtool-0.6.8.3.dist-info/top_level.txt,sha256=gpd2Sj-L9tWbuJEd5E8C8S8XkNm5yUE76klUYcM-eWM,7
27
+ bmtool-0.6.8.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (77.0.1)
2
+ Generator: setuptools (77.0.3)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5