Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversion test #102

Draft
wants to merge 60 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
9907435
changes for testing conversions locally
grg2rsr Oct 24, 2024
0c6b01b
some bugfixes to pass the processed-only checks
grg2rsr Oct 24, 2024
a161473
for local testing
grg2rsr Oct 25, 2024
caabeb6
read after write for raw ephys and video data added
grg2rsr Dec 10, 2024
3ab8de3
revision argument in all datainterfaces
grg2rsr Dec 11, 2024
58ccd21
cleanups
grg2rsr Dec 11, 2024
5e17eec
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 11, 2024
7999b4a
add signature to sorting interface
h-mayorquin Dec 13, 2024
dab27f0
Merge remote-tracking branch 'refs/remotes/origin/conversion_test' in…
h-mayorquin Dec 13, 2024
c58da11
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 13, 2024
6c80583
fix typing
h-mayorquin Dec 13, 2024
beae882
Merge remote-tracking branch 'refs/remotes/origin/conversion_test' in…
h-mayorquin Dec 13, 2024
9a1c01c
fix more typing errors
h-mayorquin Dec 13, 2024
2b9c4bf
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 13, 2024
5f9d77e
optional
h-mayorquin Dec 13, 2024
05d2958
integration of mine and hebertos changes
grg2rsr Dec 17, 2024
1ab3d11
Merge remote-tracking branch 'origin/conversion_test' into conversion…
grg2rsr Dec 17, 2024
e608b5d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 17, 2024
22feb6a
added automatic last revision to consistency checking
grg2rsr Dec 17, 2024
d4b80ef
Merge branch 'conversion_test' of github.com:catalystneuro/IBL-to-nwb…
grg2rsr Dec 17, 2024
76fc999
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 17, 2024
62d7a40
output path related fixes / cleanups
grg2rsr Dec 17, 2024
4202759
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 17, 2024
b640ee6
attempting to pass one to IblSortingInterface - fails currently by py…
grg2rsr Dec 18, 2024
6487907
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 18, 2024
45cbaca
one instantiation removed in IblSortingInterface, but requires hack i…
grg2rsr Dec 18, 2024
a522cb5
git mess fix
grg2rsr Dec 18, 2024
cff20a5
for heberto
grg2rsr Dec 18, 2024
86144df
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 18, 2024
72a7117
for sdsc
grg2rsr Dec 19, 2024
73899e5
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 19, 2024
0c792fb
fix for one local on sdsc
grg2rsr Dec 19, 2024
d6984ce
Merge branch 'conversion_test' of github.com:catalystneuro/IBL-to-nwb…
grg2rsr Dec 19, 2024
cafbbd5
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 19, 2024
9fad4ec
sdsc fix
grg2rsr Dec 19, 2024
86868dc
revisions bugfix
grg2rsr Dec 23, 2024
fcab8a9
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 23, 2024
0b930d7
updates with revision hack: session_id = eid:revision
grg2rsr Jan 8, 2025
d7a5ec0
Merge branch 'conversion_test' of github.com:catalystneuro/IBL-to-nwb…
grg2rsr Jan 8, 2025
631dec9
ruff happiness
grg2rsr Jan 8, 2025
225a0f8
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 8, 2025
497ba31
one scripts to convert both raw and processed, and also to to run on …
grg2rsr Jan 8, 2025
2da2f93
Merge branch 'conversion_test' of github.com:catalystneuro/IBL-to-nwb…
grg2rsr Jan 8, 2025
b72fd85
rest caching disabled
grg2rsr Jan 8, 2025
a8811a6
decompression and cleaup added
grg2rsr Jan 9, 2025
fed2679
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 9, 2025
b894d6a
decompression to scratch added
grg2rsr Jan 9, 2025
32aef9f
Merge branch 'conversion_test' of github.com:catalystneuro/IBL-to-nwb…
grg2rsr Jan 9, 2025
cf853a2
ruff
grg2rsr Jan 9, 2025
221f6b7
removing uuids from filenames of symbolic links
grg2rsr Jan 9, 2025
ca472a1
cleanup updated
grg2rsr Jan 9, 2025
b74359d
bugfix in symlink creater (uuid removal)
grg2rsr Jan 9, 2025
3a3d323
post conversion check update and bugfix
grg2rsr Jan 13, 2025
1f3cf25
checking all bands all probes
grg2rsr Jan 13, 2025
4a8c726
WIP commit / SDSC updates
Jan 14, 2025
53eb6c2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 14, 2025
cc2a508
wip
Jan 14, 2025
cc144fc
Merge branch 'conversion_test' of https://github.com/catalystneuro/IB…
Jan 14, 2025
77be87c
made a mess ... cleanup
grg2rsr Jan 14, 2025
315fa05
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
)
from ibl_to_nwb.testing import check_written_nwbfile_for_consistency

session_id = "d32876dd-8303-4720-8e7e-20678dc2fd71"
# session_id = "d32876dd-8303-4720-8e7e-20678dc2fd71"
session_id = "caa5dddc-9290-4e27-9f5e-575ba3598614" # a BWM session with dual probe

# Specify the revision of the pose estimation data
# Setting to 'None' will use whatever the latest released revision is
revision = None

base_path = Path("E:/IBL")
# base_path = Path("E:/IBL")
base_path = Path.home() / "ibl_scratch" # local directory
base_path.mkdir(exist_ok=True)
nwbfiles_folder_path = base_path / "nwbfiles"
nwbfiles_folder_path.mkdir(exist_ok=True)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,33 @@
os.environ["JUPYTER_PLATFORM_DIRS"] = "1" # Annoying

import os

# import traceback
# from concurrent.futures import ProcessPoolExecutor, as_completed
from pathlib import Path
from shutil import rmtree

# from tempfile import mkdtemp
# from dandi.download import download as dandi_download
# from dandi.organize import organize as dandi_organize
# from dandi.upload import upload as dandi_upload
# from neuroconv.tools.data_transfers import automatic_dandi_upload
# from nwbinspector.tools import get_s3_urls_and_dandi_paths
from one.api import ONE

# from pynwb import NWBHDF5IO
# from pynwb.image import ImageSeries
# from tqdm import tqdm
from ibl_to_nwb.brainwide_map import BrainwideMapConverter
from ibl_to_nwb.brainwide_map.datainterfaces import (
BrainwideMapTrialsInterface,
)
from ibl_to_nwb.converters import BrainwideMapConverter
from ibl_to_nwb.datainterfaces import (
BrainwideMapTrialsInterface,
IblPoseEstimationInterface,
IblSortingInterface,
LickInterface,
PupilTrackingInterface,
RoiMotionEnergyInterface,
WheelInterface,
)
from ibl_to_nwb.testing._consistency_checks import check_written_nwbfile_for_consistency

base_path = Path.home() / "ibl_scratch" # local directory
# session = "d32876dd-8303-4720-8e7e-20678dc2fd71"
session = "caa5dddc-9290-4e27-9f5e-575ba3598614" # a BWM session with dual probe

nwbfile_path = base_path / "nwbfiles" / session / f"{session}.nwb"
nwbfile_path.parent.mkdir(exist_ok=True)
nwbfile_path.parent.mkdir(exist_ok=True, parents=True)

stub_test: bool = False
cleanup: bool = False

# assert len(os.environ.get("DANDI_API_KEY", "")) > 0, "Run `export DANDI_API_KEY=...`!"
revision = None

nwbfile_path.parent.mkdir(exist_ok=True)

Expand All @@ -62,39 +48,41 @@

# These interfaces should always be present in source data
data_interfaces.append(IblSortingInterface(session=session, cache_folder=cache_folder / "sorting"))
data_interfaces.append(BrainwideMapTrialsInterface(one=session_one, session=session))
data_interfaces.append(WheelInterface(one=session_one, session=session))
data_interfaces.append(BrainwideMapTrialsInterface(one=session_one, session=session, revision=revision))
data_interfaces.append(WheelInterface(one=session_one, session=session, revision=revision))

# These interfaces may not be present; check if they are before adding to list
pose_estimation_files = session_one.list_datasets(eid=session, filename="*.dlc*")
for pose_estimation_file in pose_estimation_files:
camera_name = pose_estimation_file.replace("alf/_ibl_", "").replace(".dlc.pqt", "")
data_interfaces.append(
IblPoseEstimationInterface(
one=session_one, session=session, camera_name=camera_name, include_pose=True, include_video=False
)
IblPoseEstimationInterface(one=session_one, session=session, camera_name=camera_name, revision=revision)
)

pupil_tracking_files = session_one.list_datasets(eid=session, filename="*features*")
for pupil_tracking_file in pupil_tracking_files:
camera_name = pupil_tracking_file.replace("alf/_ibl_", "").replace(".features.pqt", "")
data_interfaces.append(PupilTrackingInterface(one=session_one, session=session, camera_name=camera_name))
data_interfaces.append(
PupilTrackingInterface(one=session_one, session=session, camera_name=camera_name, revision=revision)
)

roi_motion_energy_files = session_one.list_datasets(eid=session, filename="*ROIMotionEnergy.npy*")
for roi_motion_energy_file in roi_motion_energy_files:
camera_name = roi_motion_energy_file.replace("alf/", "").replace(".ROIMotionEnergy.npy", "")
data_interfaces.append(RoiMotionEnergyInterface(one=session_one, session=session, camera_name=camera_name))
data_interfaces.append(
RoiMotionEnergyInterface(one=session_one, session=session, camera_name=camera_name, revision=revision)
)

if session_one.list_datasets(eid=session, collection="alf", filename="licks*"):
data_interfaces.append(LickInterface(one=session_one, session=session))
data_interfaces.append(LickInterface(one=session_one, session=session, revision=revision))

# Run conversion
session_converter = BrainwideMapConverter(
one=session_one, session=session, data_interfaces=data_interfaces, verbose=True
)

metadata = session_converter.get_metadata()
metadata["NWBFile"]["session_id"] = metadata["NWBFile"]["session_id"] + "-processed-only"
metadata["NWBFile"]["session_id"] = metadata["NWBFile"]["session_id"] # + "-processed-only"

session_converter.run_conversion(
nwbfile_path=nwbfile_path,
Expand All @@ -109,3 +97,5 @@
if cleanup:
rmtree(cache_folder)
rmtree(nwbfile_path.parent)

check_written_nwbfile_for_consistency(one=session_one, nwbfile_path=nwbfile_path)
9 changes: 6 additions & 3 deletions src/ibl_to_nwb/_scripts/convert_brainwide_map_raw_only.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
from ibl_to_nwb.converters import BrainwideMapConverter, IblSpikeGlxConverter
from ibl_to_nwb.datainterfaces import RawVideoInterface

session_id = "d32876dd-8303-4720-8e7e-20678dc2fd71"
# session_id = "d32876dd-8303-4720-8e7e-20678dc2fd71"
session_id = "caa5dddc-9290-4e27-9f5e-575ba3598614" # a BWM session with dual probe


# Specify the revision of the pose estimation data
# Setting to 'None' will use whatever the latest released revision is
revision = None

base_path = Path("E:/IBL")
# base_path = Path("E:/IBL")
base_path = Path.home() / "ibl_scratch" # local directory
base_path.mkdir(exist_ok=True)
nwbfiles_folder_path = base_path / "nwbfiles"
nwbfiles_folder_path.mkdir(exist_ok=True)
Expand All @@ -28,7 +31,7 @@
# Specify the path to the SpikeGLX files on the server but use ONE API for timestamps
data_interfaces = []

spikeglx_source_folder_path = Path("D:/example_data/ephy_testing_data/spikeglx/Noise4Sam_g0")
# spikeglx_source_folder_path = Path("D:/example_data/ephy_testing_data/spikeglx/Noise4Sam_g0")
spikeglx_subconverter = IblSpikeGlxConverter(folder_path=spikeglx_source_folder_path, one=ibl_client)
data_interfaces.append(spikeglx_subconverter)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# %%
from pathlib import Path

from one.api import ONE

from ibl_to_nwb.converters import BrainwideMapConverter, IblSpikeGlxConverter
from ibl_to_nwb.datainterfaces import RawVideoInterface

# select eid
# -> run download_data_local first with this eid to set up the local folder structure and one cache
eid = "caa5dddc-9290-4e27-9f5e-575ba3598614"

# folders
base_path = Path.home() / "ibl_scratch"
base_path.mkdir(exist_ok=True)
nwbfiles_folder_path = base_path / "nwbfiles"
nwbfiles_folder_path.mkdir(exist_ok=True)

# Initialize IBL (ONE) client to download processed data for this session
one_cache_folder_path = base_path / "ibl_conversion" / eid / "cache"
one = ONE(
base_url="https://openalyx.internationalbrainlab.org",
password="international",
silent=True,
cache_dir=one_cache_folder_path,
)

data_interfaces = []

# %% ephys
session_folder = one.eid2path(eid)
spikeglx_source_folder_path = session_folder / "raw_ephys_data"

# Specify the path to the SpikeGLX files on the server but use ONE API for timestamps
spikeglx_subconverter = IblSpikeGlxConverter(folder_path=spikeglx_source_folder_path, one=one, eid=eid)
data_interfaces.append(spikeglx_subconverter)

# %% video
# Raw video takes some special handling
metadata_retrieval = BrainwideMapConverter(one=one, session=eid, data_interfaces=[], verbose=False)
subject_id = metadata_retrieval.get_metadata()["Subject"]["subject_id"]

pose_estimation_files = one.list_datasets(eid=eid, filename="*.dlc*")
for pose_estimation_file in pose_estimation_files:
camera_name = pose_estimation_file.replace("alf/_ibl_", "").replace(".dlc.pqt", "")

video_interface = RawVideoInterface(
nwbfiles_folder_path=nwbfiles_folder_path,
subject_id=subject_id,
one=one,
session=eid,
camera_name=camera_name,
)
data_interfaces.append(video_interface)

# Run conversion
session_converter = BrainwideMapConverter(one=one, session=eid, data_interfaces=data_interfaces, verbose=False)

metadata = session_converter.get_metadata()
metadata["NWBFile"]["eid"] = metadata["NWBFile"]["eid"]
subject_id = metadata["Subject"]["subject_id"]

subject_folder_path = nwbfiles_folder_path / f"sub-{subject_id}"
subject_folder_path.mkdir(exist_ok=True)
nwbfile_path = subject_folder_path / f"sub-{subject_id}_ses-{eid}_desc-video.nwb"

session_converter.run_conversion(
nwbfile_path=nwbfile_path,
metadata=metadata,
overwrite=True,
)

# TODO: add some kind of raw-specific check
# check_written_nwbfile_for_consistency(one=one, nwbfile_path=nwbfile_path)
45 changes: 45 additions & 0 deletions src/ibl_to_nwb/_scripts/download_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# %%
from pathlib import Path

from one.api import ONE

# %%
eid = "caa5dddc-9290-4e27-9f5e-575ba3598614" # a BWM eid with dual probe

base_path = Path.home() / "ibl_scratch" # local directory

# Download behavior and spike sorted data for this eid
session_path = base_path / "ibl_conversion" / eid
cache_folder = base_path / "ibl_conversion" / eid / "cache"
session_one = ONE(
base_url="https://openalyx.internationalbrainlab.org",
password="international",
silent=False,
cache_dir=cache_folder,
)

# %% latest revision
revisions = session_one.list_revisions(eid)
revision = revisions[-1]

# %% list all datasets
datasets = session_one.list_datasets(eid)

# %% list all collections
collections = session_one.list_collections(eid)

# %%
for dataset in datasets:
session_one.load_dataset(eid, dataset, download_only=True)

# %% downloads all raw ephys data!
collections = session_one.list_collections(eid, collection="raw_ephys_data/*")
for collection in collections:
datasets = session_one.list_datasets(eid, collection=collection)
for dataset in datasets:
session_one.load_dataset(eid, dataset, download_only=True)

# %% just the video data
datasets = session_one.list_datasets(eid, collection="raw_video_data")
for dataset in datasets:
session_one.load_dataset(eid, dataset, download_only=True)
2 changes: 1 addition & 1 deletion src/ibl_to_nwb/converters/_brainwide_map_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from neuroconv.utils import dict_deep_update, load_dict_from_file

from src.ibl_to_nwb.converters._iblconverter import IblConverter
from ibl_to_nwb.converters._iblconverter import IblConverter


class BrainwideMapConverter(IblConverter):
Expand Down
49 changes: 26 additions & 23 deletions src/ibl_to_nwb/converters/_ibl_spikeglx_converter.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,43 @@
import numpy as np
from brainbox.io.one import EphysSessionLoader, SpikeSortingLoader
from neuroconv.converters import SpikeGLXConverterPipe
from one.api import ONE
from pydantic import DirectoryPath
from pynwb import NWBFile


class IblSpikeGlxConverter(SpikeGLXConverterPipe):

def __init__(self, folder_path: DirectoryPath, one: ONE) -> None:
def __init__(self, folder_path: DirectoryPath, one: ONE, eid: str) -> None:
super().__init__(folder_path=folder_path)
self.one = one
self.eid = eid # probably should better name this session_id ?

def temporally_align_data_interfaces(self) -> None:
"""Align the raw data timestamps to the other data streams using the ONE API."""
# This is the syntax for aligning the raw timestamps; I cannot test this without the actual data as stored
# on your end, so please work with Heberto if there are any problems after uncommenting
# probe_to_imec_map = {
# "probe00": 0,
# "probe01": 1,
# }
#
# ephys_session_loader = EphysSessionLoader(one=self.one, eid=session_id)
# probes = ephys_session_loader.probes
# for probe_name, pid in ephys_session_loader.probes.items():
# spike_sorting_loader = SpikeSortingLoader(pid=pid, one=ibl_client)
#
# probe_index = probe_to_imec_map[probe_name]
# for band in ["ap", "lf"]:
# recording_interface = next(
# interface
# for interface in self.data_interface_objects
# if f"imec{probe_index}.{band}" in interface.source_data["file_path"]
# )
#
# band_info = spike_sorting_loader.raw_electrophysiology(band=band, stream=True)
# aligned_timestamps = spike_sorting_loader.samples2times(numpy.arange(0, band_info.ns), direction='forward')
# recording_interface.set_aligned_timestamps(aligned_timestamps=aligned_timestamps)
probe_to_imec_map = {
"probe00": 0,
"probe01": 1,
}

ephys_session_loader = EphysSessionLoader(one=self.one, eid=self.eid)
probes = ephys_session_loader.probes
for probe_name, pid in ephys_session_loader.probes.items():
spike_sorting_loader = SpikeSortingLoader(pid=pid, one=self.one)

probe_index = probe_to_imec_map[probe_name]
for band in ["ap", "lf"]:
recording_interface = self.data_interface_objects[f"imec{probe_index}.{band}"]
# recording_interface = next(
# interface
# for interface in self.data_interface_objects
# if f"imec{probe_index}.{band}" in interface.source_data["file_path"]
# )

band_info = spike_sorting_loader.raw_electrophysiology(band=band, stream=True)
aligned_timestamps = spike_sorting_loader.samples2times(np.arange(0, band_info.ns), direction="forward")
recording_interface.set_aligned_timestamps(aligned_timestamps=aligned_timestamps)
pass

def add_to_nwbfile(self, nwbfile: NWBFile, metadata) -> None:
Expand Down
5 changes: 3 additions & 2 deletions src/ibl_to_nwb/datainterfaces/_brainwide_map_trials.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@


class BrainwideMapTrialsInterface(BaseDataInterface):
def __init__(self, one: ONE, session: str):
def __init__(self, one: ONE, session: str, revision: str | None = None):
self.one = one
self.session = session
self.revision = one.list_revisions(session)[-1] if revision is None else revision

def get_metadata(self) -> dict:
metadata = super().get_metadata()
Expand All @@ -20,7 +21,7 @@ def get_metadata(self) -> dict:
return metadata

def add_to_nwbfile(self, nwbfile: NWBFile, metadata: dict):
trials = self.one.load_object(id=self.session, obj="trials", collection="alf")
trials = self.one.load_object(id=self.session, obj="trials", collection="alf", revision=self.revision)

column_ordering = [
"choice",
Expand Down
Loading
Loading