Repository: mne-tools/mne-bids

Issue:
write_raw_bids doesn't convert the .seq, .hsp, and .elp KIT related files
before bids conversion
![](https://files.gitter.im/mne-tools/mne-python/A33S/thumb/Screen-Shot-2019-11-03-at-12.56.11.png)

after bids conversion
![](https://files.gitter.im/mne-tools/mne-python/HxFs/thumb/Screen-Shot-2019-11-03-at-12.58.48.png)


Discussion:
@zuxfoucault I updated your description to include the screenshots
Also, raw read from `raw = read_raw_bids(bids_basename + '_meg.con', output_path)`, raw.info['dig'] information would loss after bids conversion.
`.seq`, `.hsp`, `.elp` files are not supported files in the BIDS spec so they just get bypassed. for `.hsp` and `.elp`, if you were to load them with the raw, the fiducials should be saved in the coordsystem.json file, which would be the critical information. just needed for computation the device-to-head transformation
I'm not sure if they are not supported @teonbrooks ? The BIDS specification does not forbid additional files that are not in the specification. And it seems we need these files to get the digitized head points in KIT system, no?
i see what's going on. so we handle this properly for the marker files by storing the input strings into the raw constructor. we would need to capture the `hsp` and `elp` args and do the same there ([ref](https://bids-specification.readthedocs.io/en/stable/04-modality-specific-files/02-magnetoencephalography.html#head-shape-and-electrode-description-_headshapeltextgt)). 

i think the coordsystem.json also need to be updated with these files' locations
Right, @teonbrooks or @zuxfoucault does any of you have time to make a PR?

Resolving patch:
diff --git a/mne_bids/__init__.py b/mne_bids/__init__.py
--- a/mne_bids/__init__.py
+++ b/mne_bids/__init__.py
@@ -5,6 +5,8 @@
 
 from mne_bids.write import (write_raw_bids, make_bids_folders, make_bids_basename,  # noqa: E501 F401
                             make_dataset_description, write_anat,  # noqa: F401
-                            get_anonymization_daysback)  # noqa: F401
+                            get_anonymization_daysback,  # noqa: F401
+                            _stamp_to_dt, _get_anonymization_daysback)
+
 from mne_bids.read import read_raw_bids, get_head_mri_trans  # noqa: F401
 from mne_bids import commands  # noqa: F401
diff --git a/mne_bids/copyfiles.py b/mne_bids/copyfiles.py
--- a/mne_bids/copyfiles.py
+++ b/mne_bids/copyfiles.py
@@ -22,6 +22,7 @@
 from scipy.io import loadmat, savemat
 
 from mne_bids.read import _parse_ext
+from mne_bids.utils import _get_mrk_meas_date
 
 
 def _copytree(src, dst, **kwargs):
@@ -153,6 +154,61 @@ def copyfile_ctf(src, dest):
                   op.join(dest, bids_folder_name + ext))
 
 
+def copyfile_kit(src, dest, subject_id, session_id,
+                 task, run, _init_kwargs):
+    """Copy and rename KIT files to a new location.
+
+    Parameters
+    ----------
+    src : str
+        Path to the source raw .con or .sqd folder.
+    dest : str
+        Path to the destination of the new bids folder.
+    subject_id : str | None
+        The subject ID. Corresponds to "sub".
+    session_id : str | None
+        The session identifier. Corresponds to "ses".
+    task : str | None
+        The task identifier. Corresponds to "task".
+    run : int | None
+        The run number. Corresponds to "run".
+    _init_kwargs : dict
+        Extract information of marker and headpoints
+
+    """
+    from mne_bids.write import make_bids_basename
+    # KIT data requires the marker file to be copied over too
+    sh.copyfile(src, dest)
+    data_path = op.split(dest)[0]
+    if 'mrk' in _init_kwargs:
+        hpi = _init_kwargs['mrk']
+        acq_map = dict()
+        if isinstance(hpi, list):
+            if _get_mrk_meas_date(hpi[0]) > _get_mrk_meas_date(hpi[1]):
+                raise ValueError('Markers provided in incorrect order.')
+            _, marker_ext = _parse_ext(hpi[0])
+            acq_map = dict(zip(['pre', 'post'], hpi))
+        else:
+            _, marker_ext = _parse_ext(hpi)
+            acq_map[None] = hpi
+        for key, value in acq_map.items():
+            marker_fname = make_bids_basename(
+                subject=subject_id, session=session_id, task=task, run=run,
+                acquisition=key, suffix='markers%s' % marker_ext,
+                prefix=data_path)
+            sh.copyfile(value, marker_fname)
+    for acq in ['elp', 'hsp']:
+        if acq in _init_kwargs:
+            position_file = _init_kwargs[acq]
+            task, run, acq = None, None, acq.upper()
+            position_ext = '.pos'
+            position_fname = make_bids_basename(
+                subject=subject_id, session=session_id, task=task, run=run,
+                acquisition=acq, suffix='headshape%s' % position_ext,
+                prefix=data_path)
+            sh.copyfile(position_file, position_fname)
+
+
 def copyfile_brainvision(vhdr_src, vhdr_dest, verbose=False):
     """Copy a BrainVision file triplet to a new location and repair links.
 
diff --git a/mne_bids/write.py b/mne_bids/write.py
--- a/mne_bids/write.py
+++ b/mne_bids/write.py
@@ -35,10 +35,10 @@
                             _age_on_date, _infer_eeg_placement_scheme,
                             _check_key_val,
                             _parse_bids_filename, _handle_kind, _check_types,
-                            _get_mrk_meas_date, _extract_landmarks, _parse_ext,
+                            _extract_landmarks, _parse_ext,
                             _get_ch_type_mapping)
 from mne_bids.copyfiles import (copyfile_brainvision, copyfile_eeglab,
-                                copyfile_ctf, copyfile_bti)
+                                copyfile_ctf, copyfile_bti, copyfile_kit)
 from mne_bids.read import reader
 from mne_bids.tsv_handler import _from_tsv, _combine, _drop, _contains_row
 
@@ -1261,26 +1261,11 @@ def write_raw_bids(raw, bids_basename, bids_root, events_data=None,
         copyfile_eeglab(raw_fname, bids_fname)
     elif ext == '.pdf':
         copyfile_bti(raw_orig, op.join(data_path, bids_raw_folder))
+    elif ext == '.con' or '.sqd':
+        copyfile_kit(raw_fname, bids_fname, subject_id, session_id,
+                     task, run, raw._init_kwargs)
     else:
         sh.copyfile(raw_fname, bids_fname)
-    # KIT data requires the marker file to be copied over too
-    if 'mrk' in raw._init_kwargs:
-        hpi = raw._init_kwargs['mrk']
-        acq_map = dict()
-        if isinstance(hpi, list):
-            if _get_mrk_meas_date(hpi[0]) > _get_mrk_meas_date(hpi[1]):
-                raise ValueError('Markers provided in incorrect order.')
-            _, marker_ext = _parse_ext(hpi[0])
-            acq_map = dict(zip(['pre', 'post'], hpi))
-        else:
-            _, marker_ext = _parse_ext(hpi)
-            acq_map[None] = hpi
-        for key, value in acq_map.items():
-            marker_fname = make_bids_basename(
-                subject=subject_id, session=session_id, task=task, run=run,
-                acquisition=key, suffix='markers%s' % marker_ext,
-                prefix=data_path)
-            sh.copyfile(value, marker_fname)
 
     return bids_root
 


Test patch:
diff --git a/mne_bids/tests/test_copyfiles.py b/mne_bids/tests/test_copyfiles.py
--- a/mne_bids/tests/test_copyfiles.py
+++ b/mne_bids/tests/test_copyfiles.py
@@ -11,10 +11,15 @@
 import mne
 from mne.datasets import testing
 from mne.utils import _TempDir
+from mne_bids.utils import _handle_kind, _parse_ext
 
 from mne_bids.copyfiles import (_get_brainvision_encoding,
                                 _get_brainvision_paths,
-                                copyfile_brainvision, copyfile_eeglab)
+                                copyfile_brainvision,
+                                copyfile_eeglab,
+                                copyfile_kit)
+
+from mne_bids.write import make_bids_basename
 
 base_path = op.join(op.dirname(mne.__file__), 'io')
 
@@ -110,3 +115,61 @@ def test_copyfile_eeglab():
     copyfile_eeglab(raw_fname, new_name)
     raw = mne.io.read_raw_eeglab(new_name)
     assert isinstance(raw, mne.io.BaseRaw)
+
+
+def test_copyfile_kit():
+    """Test copying and renaming KIT files to a new location."""
+    output_path = _TempDir()
+    data_path = op.join(base_path, 'kit', 'tests', 'data')
+    raw_fname = op.join(data_path, 'test.sqd')
+    hpi_fname = op.join(data_path, 'test_mrk.sqd')
+    electrode_fname = op.join(data_path, 'test.elp')
+    headshape_fname = op.join(data_path, 'test.hsp')
+    subject_id = '01'
+    session_id = '01'
+    run = '01'
+    acq = '01'
+    task = 'testing'
+
+    bids_basename = make_bids_basename(
+        subject=subject_id, session=session_id, run=run, acquisition=acq,
+        task=task)
+
+    kit_bids_basename = bids_basename.replace('_acq-01', '')
+
+    raw = mne.io.read_raw_kit(
+        raw_fname, mrk=hpi_fname, elp=electrode_fname,
+        hsp=headshape_fname)
+    _, ext = _parse_ext(raw_fname, verbose=True)
+    kind = _handle_kind(raw)
+    bids_fname = bids_basename + '_%s%s' % (kind, ext)
+    bids_fname = op.join(output_path, bids_fname)
+
+    copyfile_kit(raw_fname, bids_fname, subject_id, session_id,
+                 task, run, raw._init_kwargs)
+    assert op.exists(bids_fname)
+    _, ext = _parse_ext(hpi_fname, verbose=True)
+    if ext == '.sqd':
+        assert op.exists(op.join(
+            output_path, kit_bids_basename + '_markers.sqd'))
+    elif ext == '.mrk':
+        assert op.exists(op.join(
+            output_path, kit_bids_basename + '_markers.mrk'))
+
+    if op.exists(electrode_fname):
+        task, run, key = None, None, 'ELP'
+        elp_ext = '.pos'
+        elp_fname = make_bids_basename(
+            subject=subject_id, session=session_id, task=task, run=run,
+            acquisition=key, suffix='headshape%s' % elp_ext,
+            prefix=output_path)
+        assert op.exists(elp_fname)
+
+    if op.exists(headshape_fname):
+        task, run, key = None, None, 'HSP'
+        hsp_ext = '.pos'
+        hsp_fname = make_bids_basename(
+            subject=subject_id, session=session_id, task=task, run=run,
+            acquisition=key, suffix='headshape%s' % hsp_ext,
+            prefix=output_path)
+        assert op.exists(hsp_fname)
diff --git a/mne_bids/tests/test_write.py b/mne_bids/tests/test_write.py
--- a/mne_bids/tests/test_write.py
+++ b/mne_bids/tests/test_write.py
@@ -30,9 +30,9 @@
 from mne.io.kit.kit import get_kit_info
 
 from mne_bids import (write_raw_bids, read_raw_bids, make_bids_basename,
-                      make_bids_folders, write_anat,
-                      get_anonymization_daysback)
-from mne_bids.write import _stamp_to_dt, _get_anonymization_daysback
+                      make_bids_folders, write_anat)
+from mne_bids.write import (_stamp_to_dt, _get_anonymization_daysback,
+                            get_anonymization_daysback)
 from mne_bids.tsv_handler import _from_tsv, _to_tsv
 from mne_bids.utils import _find_matching_sidecar
 from mne_bids.pick import coil_type
@@ -368,8 +368,8 @@ def test_kit(_bids_validate):
     hpi_fname = op.join(data_path, 'test_mrk.sqd')
     hpi_pre_fname = op.join(data_path, 'test_mrk_pre.sqd')
     hpi_post_fname = op.join(data_path, 'test_mrk_post.sqd')
-    electrode_fname = op.join(data_path, 'test_elp.txt')
-    headshape_fname = op.join(data_path, 'test_hsp.txt')
+    electrode_fname = op.join(data_path, 'test.elp')
+    headshape_fname = op.join(data_path, 'test.hsp')
     event_id = dict(cond=1)
 
     kit_bids_basename = bids_basename.replace('_acq-01', '')
@@ -386,6 +386,13 @@ def test_kit(_bids_validate):
 
     read_raw_bids(kit_bids_basename + '_meg.sqd', bids_root)
 
+    # ensure the marker file is produced in the right place
+    marker_fname = make_bids_basename(
+        subject=subject_id, session=session_id, task=task, run=run,
+        suffix='markers.sqd',
+        prefix=op.join(bids_root, 'sub-01', 'ses-01', 'meg'))
+    assert op.exists(marker_fname)
+
     # test anonymize
     if check_version('mne', '0.20'):
         output_path = _test_anonymize(raw, kit_bids_basename,