Skip to content

Commit

Permalink
Merge pull request #9 from catalystneuro/opto
Browse files Browse the repository at this point in the history
Opto
  • Loading branch information
pauladkisson authored Oct 22, 2024
2 parents 1ee065e + cb0b044 commit fd10baa
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/schneider_lab_to_nwb/schneider_2024/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .schneider_2024_behaviorinterface import Schneider2024BehaviorInterface
from .schneider_2024_optogeneticinterface import Schneider2024OptogeneticInterface
from .schneider_2024_intrinsic_signal_imaging_interface import Schneider2024IntrinsicSignalOpticalImagingInterface
from .schneider_2024_nwbconverter import Schneider2024NWBConverter
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ def session_to_nwb(
source_data.update({metadata_key_name: dict(file_paths=[video_file_path], metadata_key_name=metadata_key_name)})
conversion_options.update({metadata_key_name: dict()})

# Add Optogenetic
source_data.update(dict(Optogenetic=dict(file_path=behavior_file_path)))
conversion_options.update(dict(Optogenetic=dict()))

# Add Intrinsic Signal Optical Imaging
source_data.update(dict(ISOI=dict(folder_path=intrinsic_signal_optical_imaging_folder_path)))
conversion_options.update(dict(ISOI=dict()))
Expand Down Expand Up @@ -118,7 +122,7 @@ def main():
sorting_folder_path = (
data_dir_path / "Schneider sample Data" / "Processed Ephys" / "m69_2023-10-31_17-24-15_Day1_A1"
)
behavior_file_path = data_dir_path / "NWB_Share" / "Sample behavior data" / "m74_ephysSample.mat"
behavior_file_path = data_dir_path / "NWB_Share" / "Sample behavior data" / "m74_optoSample.mat"
video_folder_path = data_dir_path / "Schneider sample Data" / "Video" / "m69_231031"
intrinsic_signal_optical_imaging_folder_path = data_dir_path / "NWB_Share" / "Sample Intrinsic imaging data"
session_to_nwb(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,22 @@ Behavior:
Sorting:
units_description: Neural spikes will be sorted offline using Kilosort 2.5 and Phy2 software and manually curated to ensure precise spike time acquisition.

Optogenetics:
Device:
name: optogenetic_stimulation_laser
description: Real time optogenetic stimulation of brain regions of interest will be accomplished via TTL control of an all solidstate 473nm blue laser (MBL-III-473/1~100mW, Opto Engine LLC). Bifurcated fiber cables (ThorLabs, Ø200 µm Core Multimode Fiber) will be used for light delivery.
manufacturer: Opto Engine LLC
OptogeneticStimulusSite:
name: optogenetic_stimulus_site
description: To identify cortical neurons that project from the auditory cortex to motor regions (Aim 2), stereotaxic injections of AAV-ChR2 will be made into the primary auditory cortex (-2.8 AP, 4.2 ML relative to bregma; guided by intrinsic optical imaging) during head-fixation and animals will be trained while expression occurs (~2 weeks). In addition, fiber optics will be implanted to target cell bodies in the secondary motor cortex (1.0-1.5 AP, 0.5-0.7 ML).
excitation_lambda: 473.0 # nm
injection_location: Primary Auditory Cortex (-2.8 AP, 4.2 ML relative to bregma; guided by intrinsic optical imaging)
stimulation_location: Secondary Motor Cortex (1.0-1.5 AP, 0.5-0.7 ML)
OptogeneticSeries:
name: optogenetic_series
description: In optogenetic perturbation trials (~33% of trials), during each lever press, continuous wave stimulation of 473nm light (15-20mW) will be delivered bilaterally over primary auditory cortex A1 (or secondary motor cortex, M2, as necessary using similar protocol - see Aim 2) to activate the terminals of ChR2 expressing neurons.
power: 0.020 # 15-20 mW

IntrinsicSignalOpticalImaging:
Module:
name: intrinsic_signal_optical_imaging
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@

## Video

## Optogenetics
- is_opto_trial in the trials table is `np.logical_not(np.isnan(onset_times))` rather than reading from the .mat file
to ensure consistency with the onset/offset times.

## Intrinsic Signal Optical Imaging
- Just including raw blood vessel image and processed overlay + pixel locations bc including the isoi roi response series would really require an extension for context, but seems like it has limited reuse potential.
- Used the Audette paper for description of overlay image.
- Need pixel locs for ephys
- Need device info for 2p microscope and red light laser
- Why is the overlaid image flipped left/right compared to the original?


## Data Requests
- Mice sexes
- Remaining data for Grant's project
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from schneider_lab_to_nwb.schneider_2024 import (
Schneider2024BehaviorInterface,
Schneider2024OptogeneticInterface,
Schneider2024IntrinsicSignalOpticalImagingInterface,
)

Expand All @@ -22,5 +23,6 @@ class Schneider2024NWBConverter(NWBConverter):
Behavior=Schneider2024BehaviorInterface,
VideoCamera1=VideoInterface,
VideoCamera2=VideoInterface,
Optogenetic=Schneider2024OptogeneticInterface,
ISOI=Schneider2024IntrinsicSignalOpticalImagingInterface,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
"""Primary class for converting optogenetic stimulation."""
from pynwb.file import NWBFile
from pydantic import FilePath
import numpy as np
from pymatreader import read_mat
from pynwb.device import Device
from pynwb.ogen import OptogeneticSeries, OptogeneticStimulusSite

from neuroconv.basedatainterface import BaseDataInterface
from neuroconv.utils import DeepDict


class Schneider2024OptogeneticInterface(BaseDataInterface):
"""Optogenetic interface for schneider_2024 conversion"""

keywords = ["optogenetics"]

def __init__(self, file_path: FilePath):
super().__init__(file_path=file_path)

def get_metadata(self) -> DeepDict:
metadata = super().get_metadata()

return metadata

def get_metadata_schema(self) -> dict:
metadata_schema = super().get_metadata_schema()
return metadata_schema

def add_to_nwbfile(self, nwbfile: NWBFile, metadata: dict):
# Read Data
file_path = self.source_data["file_path"]
file = read_mat(file_path)
onset_times = file["events"]["push"]["opto_time"]
is_opto_trial = np.logical_not(np.isnan(onset_times))
onset_times = onset_times[is_opto_trial]
offset_times = file["events"]["push"]["opto_time_end"]
offset_times = offset_times[is_opto_trial]
assert np.all(
np.logical_not(np.isnan(offset_times))
), "Some of the offset times are nan when onset times are not nan."
power = metadata["Optogenetics"]["OptogeneticSeries"]["power"]

timestamps, data = [], []
for onset_time, offset_time in zip(onset_times, offset_times):
timestamps.append(onset_time)
data.append(power)
timestamps.append(offset_time)
data.append(0)
timestamps, data = np.array(timestamps, dtype=np.float64), np.array(data, dtype=np.float64)

# Add Data to NWBFile
# Add Device
device = Device(**metadata["Optogenetics"]["Device"])
nwbfile.add_device(device)

# Add OptogeneticStimulusSite
site_metadata = metadata["Optogenetics"]["OptogeneticStimulusSite"]
location = f"Injection location: {site_metadata['injection_location']} \n Stimulation location: {site_metadata['stimulation_location']}"
ogen_site = OptogeneticStimulusSite(
name=site_metadata["name"],
device=device,
description=site_metadata["description"],
excitation_lambda=site_metadata["excitation_lambda"],
location=location,
)
nwbfile.add_ogen_site(ogen_site)

# Add OptogeneticSeries
series_metadata = metadata["Optogenetics"]["OptogeneticSeries"]
optogenetic_series = OptogeneticSeries(
name=series_metadata["name"],
site=ogen_site,
description=series_metadata["description"],
data=data,
timestamps=timestamps,
)
nwbfile.add_stimulus(optogenetic_series)

0 comments on commit fd10baa

Please sign in to comment.