Example #1
0
def test_make_folders():
    """Test that folders are created and named properly."""
    # Make sure folders are created properly
    output_path = _TempDir()
    make_bids_folders(subject='hi', session='foo', kind='ba', root=output_path)
    assert os.path.isdir(os.path.join(output_path, 'sub-hi', 'ses-foo', 'ba'))
    # If we remove a kwarg the folder shouldn't be created
    output_path = _TempDir()
    make_bids_folders(subject='hi', kind='ba', root=output_path)
    assert os.path.isdir(os.path.join(output_path, 'sub-hi', 'ba'))
Example #2
0
def get_matched_empty_room(bids_fname, bids_root):
    """Get matching empty room file.

    Parameters
    ----------
    bids_fname : str
        The filename for which to find the matching empty room file.
    bids_root : str
        Path to the BIDS root folder.

    Returns
    -------
    er_fname : str | None.
        The filename corresponding to the empty room.
        Returns None if no file found.
    """
    bids_fname = op.basename(bids_fname)
    _, ext = _parse_ext(bids_fname)

    raw = read_raw_bids(bids_fname, bids_root)
    if raw.info['meas_date'] is None:
        raise ValueError('Measurement date not available. Cannot get matching'
                         ' empty room file')

    ref_date = raw.info['meas_date']
    if not isinstance(ref_date, datetime):
        # for MNE < v0.20
        ref_date = datetime.fromtimestamp(raw.info['meas_date'][0])
    search_path = make_bids_folders(bids_root=bids_root, subject='emptyroom',
                                    session='**', make_dir=False)
    search_path = op.join(search_path, '**', '**%s' % ext)
    er_fnames = glob.glob(search_path)

    best_er_fname = None
    min_seconds = np.inf
    for er_fname in er_fnames:
        params = _parse_bids_filename(er_fname, verbose=False)
        dt = datetime.strptime(params['ses'], '%Y%m%d')
        dt = dt.replace(tzinfo=ref_date.tzinfo)
        delta_t = dt - ref_date
        if abs(delta_t.total_seconds()) < min_seconds:
            min_seconds = abs(delta_t.total_seconds())
            best_er_fname = er_fname

    return best_er_fname
Example #3
0
def test_make_folders():
    """Test that folders are created and named properly."""
    # Make sure folders are created properly
    output_path = _TempDir()
    make_bids_folders(subject='hi', session='foo', kind='ba',
                      output_path=output_path)
    assert op.isdir(op.join(output_path, 'sub-hi', 'ses-foo', 'ba'))
    # If we remove a kwarg the folder shouldn't be created
    output_path = _TempDir()
    make_bids_folders(subject='hi', kind='ba', output_path=output_path)
    assert op.isdir(op.join(output_path, 'sub-hi', 'ba'))
    # check overwriting of folders
    make_bids_folders(subject='hi', kind='ba', output_path=output_path,
                      overwrite=True, verbose=True)
Example #4
0
def get_matched_empty_room(bids_basename, bids_root):
    """Get matching empty-room file for an MEG recording.

    Parameters
    ----------
    bids_basename : str | BIDSPath
        The base filename of the BIDS-compatible file. Typically, this can be
        generated using :func:`mne_bids.make_bids_basename`.
    bids_root : str | pathlib.Path
        Path to the BIDS root folder.

    Returns
    -------
    er_basename : str | None.
        The basename corresponding to the best-matching empty-room measurement.
        Returns None if none was found.
    """
    # convert to BIDS Path
    if isinstance(bids_basename, str):
        params = _parse_bids_filename(bids_basename, False)
        bids_basename = BIDSPath(subject=params.get('sub'),
                                 session=params.get('ses'),
                                 recording=params.get('rec'),
                                 acquisition=params.get('acq'),
                                 processing=params.get('proc'),
                                 space=params.get('space'),
                                 run=params.get('run'),
                                 task=params.get('task'))

    kind = 'meg'  # We're only concerned about MEG data here
    bids_fname = bids_basename.get_bids_fname(kind=kind, bids_root=bids_root)
    _, ext = _parse_ext(bids_fname)
    if ext == '.fif':
        extra_params = dict(allow_maxshield=True)
    else:
        extra_params = None

    raw = read_raw_bids(bids_basename=bids_basename,
                        bids_root=bids_root,
                        kind=kind,
                        extra_params=extra_params)
    if raw.info['meas_date'] is None:
        raise ValueError('The provided recording does not have a measurement '
                         'date set. Cannot get matching empty-room file.')

    ref_date = raw.info['meas_date']
    if not isinstance(ref_date, datetime):
        # for MNE < v0.20
        ref_date = datetime.fromtimestamp(raw.info['meas_date'][0])

    emptyroom_dir = pathlib.Path(
        make_bids_folders(bids_root=bids_root,
                          subject='emptyroom',
                          make_dir=False))

    if not emptyroom_dir.exists():
        return None

    # Find the empty-room recording sessions.
    emptyroom_session_dirs = [
        x for x in emptyroom_dir.iterdir()
        if x.is_dir() and str(x.name).startswith('ses-')
    ]
    if not emptyroom_session_dirs:  # No session sub-directories found
        emptyroom_session_dirs = [emptyroom_dir]

    # Now try to discover all recordings inside the session directories.

    allowed_extensions = list(reader.keys())
    # `.pdf` is just a "virtual" extension for BTi data (which is stored inside
    # a dedicated directory that doesn't have an extension)
    del allowed_extensions[allowed_extensions.index('.pdf')]

    candidate_er_fnames = []
    for session_dir in emptyroom_session_dirs:
        dir_contents = glob.glob(
            op.join(session_dir, kind, f'sub-emptyroom_*_{kind}*'))
        for item in dir_contents:
            item = pathlib.Path(item)
            if ((item.suffix in allowed_extensions)
                    or (not item.suffix and item.is_dir())):  # Hopefully BTi?
                candidate_er_fnames.append(item.name)

    # Walk through recordings, trying to extract the recording date:
    # First, from the filename; and if that fails, from `info['meas_date']`.
    best_er_basename = None
    min_delta_t = np.inf
    date_tie = False

    failed_to_get_er_date_count = 0
    for er_fname in candidate_er_fnames:
        params = _parse_bids_filename(er_fname, verbose=False)
        er_meas_date = None

        er_bids_path = BIDSPath(subject='emptyroom',
                                session=params.get('ses', None),
                                task=params.get('task', None),
                                acquisition=params.get('acq', None),
                                run=params.get('run', None),
                                processing=params.get('proc', None),
                                recording=params.get('rec', None),
                                space=params.get('space', None))
        er_basename = str(er_bids_path)

        # Try to extract date from filename.
        if params['ses'] is not None:
            try:
                er_meas_date = datetime.strptime(params['ses'], '%Y%m%d')
            except (ValueError, TypeError):
                # There is a session in the filename, but it doesn't encode a
                # valid date.
                pass

        if er_meas_date is None:  # No luck so far! Check info['meas_date']
            _, ext = _parse_ext(er_fname)
            if ext == '.fif':
                extra_params = dict(allow_maxshield=True)
            else:
                extra_params = None

            er_raw = read_raw_bids(bids_basename=er_basename,
                                   bids_root=bids_root,
                                   kind=kind,
                                   extra_params=extra_params)

            er_meas_date = er_raw.info['meas_date']
            if er_meas_date is None:  # There's nothing we can do.
                failed_to_get_er_date_count += 1
                continue

        er_meas_date = er_meas_date.replace(tzinfo=ref_date.tzinfo)
        delta_t = er_meas_date - ref_date

        if abs(delta_t.total_seconds()) == min_delta_t:
            date_tie = True
        elif abs(delta_t.total_seconds()) < min_delta_t:
            min_delta_t = abs(delta_t.total_seconds())
            best_er_basename = er_basename
            date_tie = False

    if failed_to_get_er_date_count > 0:
        msg = (f'Could not retrieve the empty-room measurement date from '
               f'a total of {failed_to_get_er_date_count} recording(s).')
        warn(msg)

    if date_tie:
        msg = ('Found more than one matching empty-room measurement with the '
               'same recording date. Selecting the first match.')
        warn(msg)

    return best_er_basename
Example #5
0
def read_raw_bids(bids_basename,
                  bids_root,
                  kind=None,
                  extra_params=None,
                  verbose=True):
    """Read BIDS compatible data.

    Will attempt to read associated events.tsv and channels.tsv files to
    populate the returned raw object with raw.annotations and raw.info['bads'].

    Parameters
    ----------
    bids_basename : str | BIDSPath
        The base filename of the BIDS compatible files. Typically, this can be
        generated using :func:`mne_bids.make_bids_basename`.
    bids_root : str | pathlib.Path
        Path to root of the BIDS folder
    kind : str | None
        The kind of recording to read. If ``None`` and only one kind (e.g.,
        only EEG or only MEG data) is present in the dataset, it will be
        selected automatically.
    extra_params : None | dict
        Extra parameters to be passed to MNE read_raw_* functions.
        If a dict, for example: ``extra_params=dict(allow_maxshield=True)``.
    verbose : bool
        The verbosity level.

    Returns
    -------
    raw : instance of Raw
        The data as MNE-Python Raw object.

    Raises
    ------
    RuntimeError
        If multiple recording kinds are present in the dataset, but
        ``kind=None``.

    RuntimeError
        If more than one data files exist for the specified recording.

    RuntimeError
        If no data file in a supported format can be located.

    ValueError
        If the specified ``kind`` cannot be found in the dataset.

    """
    # convert to BIDS Path
    if isinstance(bids_basename, str):
        params = _parse_bids_filename(bids_basename, verbose)
        bids_basename = BIDSPath(subject=params.get('sub'),
                                 session=params.get('ses'),
                                 recording=params.get('rec'),
                                 acquisition=params.get('acq'),
                                 processing=params.get('proc'),
                                 space=params.get('space'),
                                 run=params.get('run'),
                                 task=params.get('task'))
    sub = bids_basename.subject
    ses = bids_basename.session
    acq = bids_basename.acquisition

    if kind is None:
        kind = _infer_kind(bids_basename=bids_basename,
                           bids_root=bids_root,
                           sub=sub,
                           ses=ses)

    data_dir = make_bids_folders(subject=sub,
                                 session=ses,
                                 kind=kind,
                                 make_dir=False)
    bids_fname = bids_basename.get_bids_fname(kind=kind, bids_root=bids_root)

    if op.splitext(bids_fname)[1] == '.pdf':
        bids_raw_folder = op.join(bids_root, data_dir,
                                  f'{bids_basename}_{kind}')
        bids_fpath = glob.glob(op.join(bids_raw_folder, 'c,rf*'))[0]
        config = op.join(bids_raw_folder, 'config')
    else:
        bids_fpath = op.join(bids_root, data_dir, bids_fname)
        config = None

    if extra_params is None:
        extra_params = dict()
    raw = _read_raw(bids_fpath,
                    electrode=None,
                    hsp=None,
                    hpi=None,
                    config=config,
                    verbose=None,
                    **extra_params)

    # Try to find an associated events.tsv to get information about the
    # events in the recorded data
    events_fname = _find_matching_sidecar(bids_fname,
                                          bids_root,
                                          'events.tsv',
                                          allow_fail=True)
    if events_fname is not None:
        raw = _handle_events_reading(events_fname, raw)

    # Try to find an associated channels.tsv to get information about the
    # status and type of present channels
    channels_fname = _find_matching_sidecar(bids_fname,
                                            bids_root,
                                            'channels.tsv',
                                            allow_fail=True)
    if channels_fname is not None:
        raw = _handle_channels_reading(channels_fname, bids_fname, raw)

    # Try to find an associated electrodes.tsv and coordsystem.json
    # to get information about the status and type of present channels
    search_modifier = f'acq-{acq}' if acq else ''
    elec_suffix = f'{search_modifier}*_electrodes.tsv'
    coord_suffix = f'{search_modifier}*_coordsystem.json'
    electrodes_fname = _find_matching_sidecar(bids_fname,
                                              bids_root,
                                              suffix=elec_suffix,
                                              allow_fail=True)
    coordsystem_fname = _find_matching_sidecar(bids_fname,
                                               bids_root,
                                               suffix=coord_suffix,
                                               allow_fail=True)
    if electrodes_fname is not None:
        if coordsystem_fname is None:
            raise RuntimeError("BIDS mandates that the coordsystem.json "
                               "should exist if electrodes.tsv does. "
                               "Please create coordsystem.json for"
                               "{}".format(bids_basename))
        if kind in ['meg', 'eeg', 'ieeg']:
            raw = _read_dig_bids(electrodes_fname, coordsystem_fname, raw,
                                 kind, verbose)

    # Try to find an associated sidecar.json to get information about the
    # recording snapshot
    sidecar_fname = _find_matching_sidecar(bids_fname,
                                           bids_root,
                                           '{}.json'.format(kind),
                                           allow_fail=True)
    if sidecar_fname is not None:
        raw = _handle_info_reading(sidecar_fname, raw, verbose=verbose)

    # read in associated subject info from participants.tsv
    participants_tsv_fpath = op.join(bids_root, 'participants.tsv')
    subject = f"sub-{bids_basename.subject}"
    if op.exists(participants_tsv_fpath):
        raw = _handle_participants_reading(participants_tsv_fpath,
                                           raw,
                                           subject,
                                           verbose=verbose)
    else:
        warn("Participants file not found for {}... Not reading "
             "in any particpants.tsv data.".format(bids_fname))

    return raw