Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
22 changes: 22 additions & 0 deletions mne_bids_pipeline/_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,28 @@
Currently not implemented
"""

et_has_run: bool = False
"""
Specify whether `run` is included in the eye-tracking data file name.

???+ example "Example"
``` python
et_has_run = False # Case with only one run and run is omitted in the file name.
et_has_run = True # Case with multiple runs. Run specification from EEG data is used.
```
"""

et_has_task: bool = False
"""
Specify whether `task` is included in the eye-tracking data file name.

???+ example "Example"
``` python
et_has_task = False # Case with only one task and task is omitted in the file name.
et_has_task = True # Case with multiple tasks. Task specification from EEG data is used.
```
"""

sync_eventtype_regex: str = ""
"""
Regular expression which will be used to select events in the EEG file for synchronisation
Expand Down
70 changes: 47 additions & 23 deletions mne_bids_pipeline/steps/preprocessing/_05b_sync_eyelink.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ def get_input_fnames_sync_eyelink(
subject: str,
session: str | None,
) -> dict:

# Get from config file whether `task` is specified in the et file name
if cfg.et_has_task == True:
et_task = cfg.task
else:
et_task = None

bids_basename = BIDSPath(
subject=subject,
session=session,
Expand All @@ -80,10 +87,10 @@ def get_input_fnames_sync_eyelink(
extension=".fif",
)

et_bids_basename = BIDSPath(
et_asc_bids_basename = BIDSPath(
subject=subject,
session=session,
task=cfg.task,
task=et_task,
acquisition=cfg.acq,
recording=cfg.rec,
datatype="beh",
Expand All @@ -93,11 +100,10 @@ def get_input_fnames_sync_eyelink(
extension=".asc",
)


et_edf_bids_basename = BIDSPath(
subject=subject,
session=session,
task=cfg.task,
task=et_task,
acquisition=cfg.acq,
recording=cfg.rec,
datatype="beh",
Expand All @@ -115,19 +121,30 @@ def get_input_fnames_sync_eyelink(
)
_update_for_splits(in_files, key, single=True)

et_bids_basename_temp = et_asc_bids_basename.copy()

if cfg.et_has_run:
et_bids_basename_temp.update(run=run)

# _update_for_splits(in_files, key, single=True) # TODO: Find out if we need to add this or not

if not os.path.isfile(et_bids_basename_temp):
logger.info(**gen_log_kwargs(message=f"Couldn't find {et_bids_basename_temp} file. If edf file exists, edf2asc will be called."))

et_bids_basename_temp = et_edf_bids_basename.copy()

if cfg.et_has_run:
et_bids_basename_temp.update(run=run)

# _update_for_splits(in_files, key, single=True) # TODO: Find out if we need to add this or not

if not os.path.isfile(et_bids_basename_temp):
logger.error(**gen_log_kwargs(message=f"Also didn't find {et_bids_basename_temp} file, one of both needs to exist for ET sync."))
raise FileNotFoundError(f"For run {run}, could neither find .asc or .edf eye-tracking file. Please double-check the file names.")

key = f"et_run-{run}"
in_files[key] = et_bids_basename.copy().update(
run=run
)
_update_for_splits(in_files, key, single=True) # TODO: Find out if we need to add this or not
in_files[key] = et_bids_basename_temp

key = f"et_edf_run-{run}"
in_files[key] = et_edf_bids_basename.copy().update(
run=run
)
_update_for_splits(in_files, key, single=True) # TODO: Find out if we need to add this or not

return in_files


Expand All @@ -143,30 +160,35 @@ def sync_eyelink(
session: str | None,
in_files: dict,
) -> dict:

"""Run Sync for Eyelink."""
import matplotlib.pyplot as plt
from scipy.signal import correlate

raw_fnames = [in_files.pop(f"raw_run-{run}") for run in cfg.runs]
et_fnames = [in_files.pop(f"et_run-{run}") for run in cfg.runs]
et_edf_fnames = [in_files.pop(f"et_edf_run-{run}") for run in cfg.runs]

logger.info(**gen_log_kwargs(message=f"et_fnames {et_fnames}"))
logger.info(**gen_log_kwargs(message=f"Found the following eye-tracking files: {et_fnames}"))
out_files = dict()
bids_basename = raw_fnames[0].copy().update(processing=None, split=None, run=None)
out_files["eyelink"] = bids_basename.copy().update(processing="eyelink", suffix="raw")
del bids_basename

for idx, (run, raw_fname,et_fname,et_edf_fname) in enumerate(zip(cfg.runs, raw_fnames,et_fnames,et_edf_fnames)):
msg = f"Syncing eyelink data (fake for now) {raw_fname.basename}"
for idx, (run, raw_fname,et_fname) in enumerate(zip(cfg.runs, raw_fnames,et_fnames)):
msg = f"Syncing Eyelink ({et_fname.basename}) and EEG data ({raw_fname.basename})."
logger.info(**gen_log_kwargs(message=msg))
raw = mne.io.read_raw_fif(raw_fname, preload=True)
if not os.path.isfile(et_fname):
logger.info(**gen_log_kwargs(message=f"Couldn't find {et_fname} file, trying to call edf2asc."))
if not os.path.isfile(et_edf_fname):
logger.error(**gen_log_kwargs(message=f"Also didn't find {et_edf_fname} file, one of both need to exist for ET sync."))

et_format = et_fname.extension

if not et_format == '.asc':
assert et_format == '.edf', "ET file is neither an `.asc` nor an `.edf`. This should not have happened."
logger.info(**gen_log_kwargs(message=f"Converting {et_fname} file to `.asc` using edf2asc."))
import subprocess
subprocess.run(["edf2asc", et_edf_fname]) # TODO: Still needs to be tested
subprocess.run(["edf2asc", et_fname]) # TODO: Still needs to be tested
print(et_fname.fpath)
et_fname.update(extension='.asc')
print(et_fname.fpath)

raw_et = mne.io.read_raw_eyelink(et_fname, find_overlaps=True)

Expand Down Expand Up @@ -341,6 +363,8 @@ def get_config(
cfg = SimpleNamespace(
runs=get_runs(config=config, subject=subject),
remove_blink_saccades = config.remove_blink_saccades,
et_has_run = config.et_has_run,
et_has_task = config.et_has_task,
sync_eventtype_regex = config.sync_eventtype_regex,
sync_eventtype_regex_et = config.sync_eventtype_regex_et,
sync_heog_ch = config.sync_heog_ch,
Expand Down